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+ }
0 commit comments