You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
5.6 KiB
184 lines
5.6 KiB
2 years ago
|
part of '../neon_news.dart';
|
||
2 years ago
|
|
||
|
class NewsArticlePage extends StatefulWidget {
|
||
|
const NewsArticlePage({
|
||
|
required this.bloc,
|
||
2 years ago
|
required this.articlesBloc,
|
||
2 years ago
|
required this.useWebView,
|
||
|
this.bodyData,
|
||
2 years ago
|
this.url,
|
||
2 years ago
|
super.key,
|
||
2 years ago
|
}) : assert(useWebView || bodyData != null, 'bodyData has to be set when not using a WebView'),
|
||
|
assert(!useWebView || url != null, 'url has to be set when using a WebView');
|
||
2 years ago
|
|
||
2 years ago
|
final NewsArticleBloc bloc;
|
||
|
final NewsArticlesBloc articlesBloc;
|
||
2 years ago
|
final bool useWebView;
|
||
|
final String? bodyData;
|
||
2 years ago
|
final String? url;
|
||
2 years ago
|
|
||
|
@override
|
||
|
State<NewsArticlePage> createState() => _NewsArticlePageState();
|
||
|
}
|
||
|
|
||
|
class _NewsArticlePageState extends State<NewsArticlePage> {
|
||
|
WebViewController? _webviewController;
|
||
|
Timer? _markAsReadTimer;
|
||
|
|
||
|
@override
|
||
|
void initState() {
|
||
|
super.initState();
|
||
|
|
||
2 years ago
|
widget.bloc.errors.listen((final error) {
|
||
|
ExceptionWidget.showSnackbar(context, error);
|
||
2 years ago
|
});
|
||
|
|
||
2 years ago
|
WidgetsBinding.instance.addPostFrameCallback((final _) async {
|
||
2 years ago
|
if (Provider.of<NeonPlatform>(context, listen: false).canUseWakelock) {
|
||
2 years ago
|
await Wakelock.enable();
|
||
2 years ago
|
}
|
||
|
});
|
||
|
|
||
|
if (!widget.useWebView) {
|
||
2 years ago
|
unawaited(_startMarkAsReadTimer());
|
||
2 years ago
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void dispose() {
|
||
|
_cancelMarkAsReadTimer();
|
||
|
|
||
|
super.dispose();
|
||
|
}
|
||
|
|
||
2 years ago
|
Future _startMarkAsReadTimer() async {
|
||
|
if (await widget.bloc.unread.first) {
|
||
2 years ago
|
if (widget.articlesBloc.options.articleDisableMarkAsReadTimeoutOption.value) {
|
||
2 years ago
|
widget.bloc.markArticleAsRead();
|
||
2 years ago
|
} else {
|
||
2 years ago
|
_markAsReadTimer = Timer(const Duration(seconds: 3), () async {
|
||
|
if (await widget.bloc.unread.first) {
|
||
|
widget.bloc.markArticleAsRead();
|
||
2 years ago
|
}
|
||
|
});
|
||
|
}
|
||
2 years ago
|
}
|
||
|
}
|
||
|
|
||
|
void _cancelMarkAsReadTimer() {
|
||
|
if (_markAsReadTimer != null) {
|
||
|
_markAsReadTimer!.cancel();
|
||
|
_markAsReadTimer = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Future<String> _getURL() async {
|
||
|
if (_webviewController != null) {
|
||
|
return (await _webviewController!.currentUrl())!;
|
||
|
}
|
||
|
|
||
2 years ago
|
return widget.url!;
|
||
2 years ago
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(final BuildContext context) => WillPopScope(
|
||
|
onWillPop: () async {
|
||
|
if (_webviewController != null && await _webviewController!.canGoBack()) {
|
||
|
await _webviewController!.goBack();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
2 years ago
|
if (mounted && Provider.of<NeonPlatform>(context, listen: false).canUseWakelock) {
|
||
2 years ago
|
await Wakelock.disable();
|
||
|
}
|
||
|
return true;
|
||
|
},
|
||
|
child: Scaffold(
|
||
|
resizeToAvoidBottomInset: false,
|
||
|
appBar: AppBar(
|
||
|
actions: [
|
||
2 years ago
|
StreamBuilder<bool>(
|
||
|
stream: widget.bloc.starred,
|
||
|
builder: (final context, final starredSnapshot) {
|
||
2 years ago
|
final starred = starredSnapshot.data ?? false;
|
||
|
return IconButton(
|
||
|
onPressed: () async {
|
||
|
if (starred) {
|
||
|
widget.bloc.unstarArticle();
|
||
|
} else {
|
||
|
widget.bloc.starArticle();
|
||
|
}
|
||
|
},
|
||
|
icon: Icon(starred ? Icons.star : Icons.star_outline),
|
||
|
);
|
||
2 years ago
|
},
|
||
|
),
|
||
2 years ago
|
StreamBuilder<bool>(
|
||
|
stream: widget.bloc.unread,
|
||
|
builder: (final context, final unreadSnapshot) {
|
||
2 years ago
|
final unread = unreadSnapshot.data ?? false;
|
||
|
return IconButton(
|
||
|
onPressed: () async {
|
||
|
if (unread) {
|
||
|
widget.bloc.markArticleAsRead();
|
||
|
} else {
|
||
|
widget.bloc.markArticleAsUnread();
|
||
|
}
|
||
|
},
|
||
|
icon: Icon(unread ? MdiIcons.email : MdiIcons.emailMarkAsUnread),
|
||
|
);
|
||
2 years ago
|
},
|
||
|
),
|
||
2 years ago
|
if (widget.url != null) ...[
|
||
|
IconButton(
|
||
|
onPressed: () async {
|
||
|
await launchUrlString(
|
||
|
await _getURL(),
|
||
|
mode: LaunchMode.externalApplication,
|
||
|
);
|
||
|
},
|
||
|
icon: const Icon(Icons.open_in_new),
|
||
|
),
|
||
|
IconButton(
|
||
|
onPressed: () async {
|
||
|
await Share.share(await _getURL());
|
||
|
},
|
||
|
icon: const Icon(Icons.share),
|
||
|
),
|
||
|
],
|
||
2 years ago
|
],
|
||
|
),
|
||
|
body: widget.useWebView
|
||
2 years ago
|
? WebView(
|
||
|
javascriptMode: JavascriptMode.unrestricted,
|
||
|
onWebViewCreated: (final controller) async {
|
||
|
_webviewController = controller;
|
||
|
await controller.loadUrl(widget.url!);
|
||
|
},
|
||
|
onPageFinished: (final _) async {
|
||
|
await _startMarkAsReadTimer();
|
||
|
},
|
||
2 years ago
|
)
|
||
|
: SingleChildScrollView(
|
||
|
padding: const EdgeInsets.all(10),
|
||
|
child: Html(
|
||
|
data: widget.bodyData,
|
||
|
onLinkTap: (
|
||
|
final url,
|
||
|
final renderContext,
|
||
|
final attributes,
|
||
|
final element,
|
||
|
) async {
|
||
|
if (url != null) {
|
||
|
await launchUrlString(
|
||
|
url,
|
||
|
mode: LaunchMode.externalApplication,
|
||
|
);
|
||
|
}
|
||
|
},
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|