@@ -11,6 +11,7 @@ import 'package:fluent_reader_lite/utils/global.dart';
1111import 'package:fluent_reader_lite/utils/store.dart' ;
1212import 'package:flutter/cupertino.dart' ;
1313import 'package:flutter/material.dart' ;
14+ import 'package:flutter/services.dart' ;
1415import 'package:intl/intl.dart' ;
1516import 'package:http/http.dart' as http;
1617import 'package:provider/provider.dart' ;
@@ -29,10 +30,14 @@ class ArticlePage extends StatefulWidget {
2930 ArticlePageState createState () => ArticlePageState ();
3031}
3132
33+ enum _ArticleLoadState {
34+ Loading , Success , Failure
35+ }
36+
3237class ArticlePageState extends State <ArticlePage > {
3338 WebViewController _controller;
3439 int requestId = 0 ;
35- bool loaded = false ;
40+ _ArticleLoadState loaded = _ArticleLoadState . Loading ;
3641 bool navigated = false ;
3742 SourceOpenTarget _target;
3843 String iid;
@@ -44,7 +49,7 @@ class ArticlePageState extends State<ArticlePage> {
4449 }
4550 setState (() {
4651 iid = id;
47- loaded = false ;
52+ loaded = _ArticleLoadState . Loading ;
4853 navigated = false ;
4954 _target = null ;
5055 if (isSource != null ) isSourceFeed = isSource;
@@ -70,12 +75,15 @@ class ArticlePageState extends State<ArticlePage> {
7075 var html = (await http.get (item.link)).body;
7176 a = Uri .encodeComponent (html);
7277 } catch (exp) {
73- setState (() { loaded = true ; });
78+ if (mounted && currId == requestId) {
79+ setState (() { loaded = _ArticleLoadState .Failure ; });
80+ }
7481 return ;
7582 }
7683 } else {
7784 a = Uri .encodeComponent (item.content);
7885 }
86+ if (! mounted || currId != requestId) return ;
7987 var h = '<p id="source">${source .name }${(item .creator !=null &&item .creator .length >0 )?' / ' +item .creator :'' }</p>' ;
8088 h += '<p id="title">${item .title }</p>' ;
8189 h += '<p id="date">${DateFormat .yMd (Localizations .localeOf (context ).toString ()).add_Hm ().format (item .date )}</p>' ;
@@ -87,20 +95,20 @@ class ArticlePageState extends State<ArticlePage> {
8795 var brightness = Global .currentBrightness (context);
8896 localUrl += "&t=${brightness .index }" ;
8997 }
90- if (currId == requestId) _controller.loadUrl (localUrl);
98+ _controller.loadUrl (localUrl);
9199 }
92100
93101 void _onPageReady (_) async {
94102 if (Platform .isAndroid || Global .globalModel.getBrightness () != null ) {
95103 await Future .delayed (Duration (milliseconds: 300 ));
96104 }
97- setState (() { loaded = true ; });
105+ setState (() { loaded = _ArticleLoadState . Success ; });
98106 if (_target == SourceOpenTarget .Local || _target == SourceOpenTarget .FullContent ) {
99107 navigated = true ;
100108 }
101109 }
102110 void _onWebpageReady (_) {
103- if (loaded) navigated = true ;
111+ if (loaded == _ArticleLoadState . Success ) navigated = true ;
104112 }
105113
106114 void _setOpenTarget (RSSSource source, {SourceOpenTarget target}) {
@@ -112,7 +120,7 @@ class ArticlePageState extends State<ArticlePage> {
112120 void _loadOpenTarget (RSSItem item, RSSSource source) {
113121 setState (() {
114122 requestId += 1 ;
115- loaded = false ;
123+ loaded = _ArticleLoadState . Loading ;
116124 navigated = false ;
117125 });
118126 switch (_target) {
@@ -166,7 +174,7 @@ class ArticlePageState extends State<ArticlePage> {
166174 var source = tuple.item2;
167175 if (_target == null ) _target = source.openTarget;
168176 final body = SafeArea (child: IndexedStack (
169- index: ! loaded ? 0 : 1 ,
177+ index: loaded.index ,
170178 children: [
171179 Center (
172180 child: CupertinoActivityIndicator ()
@@ -182,6 +190,21 @@ class ArticlePageState extends State<ArticlePage> {
182190 onPageFinished: _onWebpageReady,
183191 navigationDelegate: _onNavigate,
184192 ),
193+ Center (
194+ child: Column (
195+ mainAxisAlignment: MainAxisAlignment .center,
196+ children: [
197+ Text (
198+ S .of (context).wentWrong,
199+ style: TextStyle (color: CupertinoColors .label.resolveFrom (context)),
200+ ),
201+ CupertinoButton (
202+ child: Text (S .of (context).retry),
203+ onPressed: () { _loadOpenTarget (item, source); },
204+ ),
205+ ],
206+ ),
207+ )
185208 ],
186209 ), bottom: false ,);
187210 return CupertinoPageScaffold (
@@ -208,6 +231,7 @@ class ArticlePageState extends State<ArticlePage> {
208231 ? S .of (context).markUnread
209232 : S .of (context).markRead,
210233 onPressed: () {
234+ HapticFeedback .mediumImpact ();
211235 Global .itemsModel.updateItem (item.id, read: ! item.hasRead);
212236 },
213237 ),
@@ -219,13 +243,25 @@ class ArticlePageState extends State<ArticlePage> {
219243 ? S .of (context).star
220244 : S .of (context).unstar,
221245 onPressed: () {
246+ HapticFeedback .mediumImpact ();
222247 Global .itemsModel.updateItem (item.id, starred: ! item.starred);
223248 },
224249 ),
225250 CupertinoToolbarItem (
226251 icon: CupertinoIcons .share,
227252 semanticLabel: S .of (context).share,
228- onPressed: () { Share .share (item.link); },
253+ onPressed: () {
254+ final media = MediaQuery .of (context);
255+ Share .share (
256+ item.link,
257+ sharePositionOrigin: Rect .fromLTWH (
258+ media.size.width - ArticlePage .state.currentContext.size.width / 2 ,
259+ media.size.height - media.padding.bottom - 54 ,
260+ 0 ,
261+ 0
262+ )
263+ );
264+ },
229265 ),
230266 CupertinoToolbarItem (
231267 icon: CupertinoIcons .chevron_up,
0 commit comments