Skip to content

Commit 3d5a482

Browse files
committed
Splits main.dart into hn-webview & hn-state dart files
1 parent 0ae86aa commit 3d5a482

File tree

4 files changed

+251
-177
lines changed

4 files changed

+251
-177
lines changed

lib/hn-state.dart

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import 'package:flutter/material.dart';
2+
import 'dart:async';
3+
import 'package:http/http.dart' as http;
4+
import 'dart:convert';
5+
import 'package:shared_preferences/shared_preferences.dart';
6+
import 'package:advanced_share/advanced_share.dart';
7+
8+
import 'package:hackernews/hn-webview.dart';
9+
10+
class HackerNews extends StatefulWidget {
11+
final String url;
12+
final int currentPage;
13+
14+
HackerNews({Key key, @required this.url, @required this.currentPage}): super(key: key);
15+
16+
@override
17+
HackerNewsState createState() => new HackerNewsState(url: this.url, currentPage: this.currentPage);
18+
}
19+
20+
class Title extends StatelessWidget {
21+
final String text;
22+
final bool urlOpened;
23+
24+
Title({Key key, @required this.text, @required this.urlOpened}): super(key: key);
25+
26+
@override
27+
Widget build(BuildContext context) {
28+
return Text(
29+
text,
30+
style: TextStyle(
31+
fontSize: 16.0,
32+
fontWeight: FontWeight.w500,
33+
color: urlOpened ? Colors.grey : Colors.black,
34+
)
35+
);
36+
}
37+
}
38+
39+
class TimeAgo extends StatelessWidget {
40+
final String text;
41+
42+
TimeAgo({Key key, @required this.text}): super(key: key);
43+
44+
@override
45+
Widget build(BuildContext context) {
46+
return Text(
47+
text,
48+
style: TextStyle(
49+
color: Colors.grey,
50+
fontSize: 14.0,
51+
)
52+
);
53+
}
54+
}
55+
56+
class HackerNewsState extends State<HackerNews> {
57+
int currentPage;
58+
int lastItemIndex = -1;
59+
List data = [];
60+
List<int> loadedIndices = [];
61+
List<String> openedLinks = [];
62+
String url;
63+
64+
HackerNewsState({Key key, @required this.url, @required this.currentPage});
65+
66+
@override
67+
void initState() {
68+
super.initState();
69+
this._getJSONData();
70+
this._loadOpenedLinks();
71+
}
72+
73+
void _loadOpenedLinks() async {
74+
SharedPreferences prefs = await SharedPreferences.getInstance();
75+
List<String> _openedLinks = (prefs.getStringList("openedLinks") ?? []);
76+
setState(() {
77+
openedLinks = _openedLinks;
78+
});
79+
}
80+
81+
Future<String> _getJSONData() async {
82+
// String url = "https://api.hnpwa.com/v0/news/" + currentPage.toString() + ".json";
83+
String _url = this.url + currentPage.toString() + ".json";
84+
var response = await http.get(
85+
Uri.encodeFull(_url),
86+
headers: {"Accept": "application/json"},
87+
);
88+
setState(() {
89+
for (var value in jsonDecode(response.body)) {
90+
data.add(value);
91+
}
92+
lastItemIndex = data.length - 1;
93+
});
94+
return "Successful";
95+
}
96+
97+
void _incrementPageNum() {
98+
if (currentPage + 1 == 5) {
99+
return;
100+
}
101+
currentPage = currentPage + 1;
102+
}
103+
104+
void _updateOpenedLinks(String url, String source) async {
105+
// SharedPreferences.setMockInitialValues({});
106+
SharedPreferences prefs = await SharedPreferences.getInstance();
107+
var urlOpened = openedLinks.contains(url) == true;
108+
var allowedStateUpdates = (source == "onTap" && urlOpened == false) || (source == "onLongPress");
109+
if (allowedStateUpdates) {
110+
setState(() {
111+
urlOpened ? openedLinks.remove(url) : openedLinks.add(url);
112+
});
113+
await prefs.setStringList("openedLinks", openedLinks);
114+
}
115+
}
116+
117+
@override
118+
Widget build(BuildContext context) {
119+
return Scaffold(
120+
appBar: AppBar(
121+
title: Text("HackerNews top posts"),
122+
),
123+
body: ListView.builder(
124+
itemCount: data == null ? 0 : data.length,
125+
itemBuilder: (BuildContext context, int index) {
126+
var urlChecked = openedLinks.contains(data[index]["url"]);
127+
if (index > 0 && index % 29 == 0 && loadedIndices.contains(index) == false) {
128+
_incrementPageNum();
129+
_getJSONData();
130+
loadedIndices.add(index);
131+
}
132+
return GestureDetector(
133+
onTap: () {
134+
if (data[index]["url"].startsWith("item?")) {
135+
Navigator.push(
136+
context,
137+
MaterialPageRoute(
138+
builder: (context) => HNWebView(
139+
url: "https://news.ycombinator.com/" + data[index]["url"],
140+
title: data[index]["title"]
141+
)
142+
)
143+
);
144+
} else {
145+
Navigator.push(
146+
context,
147+
MaterialPageRoute(
148+
builder: (context) => HNWebView(
149+
url: data[index]["url"],
150+
title: data[index]["title"]
151+
)
152+
)
153+
);
154+
}
155+
_updateOpenedLinks(data[index]["url"], "onTap");
156+
},
157+
onLongPress: () {
158+
var flag = openedLinks.contains(data[index]["url"]) ? "not read" : "read";
159+
final snackBar = SnackBar(content: Text("Marking as " + flag.toString() + ": " + data[index]["title"]), duration: Duration(milliseconds: 500));
160+
Scaffold.of(context).showSnackBar(snackBar);
161+
Future.delayed(const Duration(milliseconds: 850), () {
162+
_updateOpenedLinks(data[index]["url"], "onLongPress");
163+
});
164+
},
165+
child: Container(
166+
child: Card(
167+
child: Container(
168+
child: Column(
169+
children: <Widget>[
170+
Title(
171+
text: data[index]["title"],
172+
urlOpened: urlChecked,
173+
),
174+
Container(
175+
margin: EdgeInsets.only(top: 10.0),
176+
child: Row(
177+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
178+
children: <Widget>[
179+
TimeAgo(text: data[index]["time_ago"]),
180+
GestureDetector(
181+
onTap: () {
182+
String __url = data[index]["url"].startsWith("item?") ? "https://news.ycombinator.com/" + data[index]["url"] : data[index]["url"];
183+
AdvancedShare.whatsapp(
184+
msg: data[index]["title"] + " - " + __url
185+
).then((_) => {
186+
187+
});
188+
},
189+
child: Container(
190+
child: Row(
191+
mainAxisAlignment: MainAxisAlignment.center,
192+
children: <Widget>[
193+
Text("Share", style: TextStyle(color: Colors.grey, fontSize: 16.0)),
194+
Container(
195+
child: Icon(Icons.share, color: Colors.grey, size: 22.0,),
196+
margin: EdgeInsets.only(left: 5.0),
197+
)
198+
]
199+
),
200+
),
201+
),
202+
],
203+
),
204+
)
205+
]
206+
),
207+
padding: EdgeInsets.all(16.0),
208+
),
209+
elevation: 2.0,
210+
margin: EdgeInsets.only(
211+
top: 16.0,
212+
bottom: index == data.length - 1 ? 16.0 : 0.0,
213+
left: 10.0,
214+
right: 10.0,
215+
),
216+
),
217+
)
218+
);
219+
}
220+
)
221+
);
222+
}
223+
}

lib/hn-webview.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
3+
4+
class HNWebView extends StatelessWidget {
5+
final String url;
6+
final String title;
7+
8+
HNWebView({Key key, @required this.url, @required this.title}): super(key: key);
9+
10+
@override
11+
Widget build(BuildContext context) {
12+
return WebviewScaffold(
13+
url: url,
14+
appBar: AppBar(
15+
title: Text(title),
16+
),
17+
withZoom: false,
18+
withLocalStorage: true,
19+
);
20+
}
21+
}

0 commit comments

Comments
 (0)