👽 Support new mixed feed
This commit is contained in:
@ -17,10 +17,9 @@ import 'package:surface/types/realm.dart';
|
||||
import 'package:surface/widgets/account/account_image.dart';
|
||||
import 'package:surface/widgets/app_bar_leading.dart';
|
||||
import 'package:surface/widgets/dialog.dart';
|
||||
import 'package:surface/widgets/feed/feed_news.dart';
|
||||
import 'package:surface/widgets/feed/feed_reader.dart';
|
||||
import 'package:surface/widgets/feed/feed_unknown.dart';
|
||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||
import 'package:surface/widgets/post/fediverse_post_item.dart';
|
||||
import 'package:surface/widgets/post/post_item.dart';
|
||||
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
||||
|
||||
@ -549,12 +548,7 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
||||
refreshPosts();
|
||||
},
|
||||
);
|
||||
case 'fediverse.post':
|
||||
return FediversePostWidget(
|
||||
data: SnFediversePost.fromJson(ele.data),
|
||||
maxWidth: 640,
|
||||
);
|
||||
case 'reader.news':
|
||||
case 'reader.feed':
|
||||
return Center(
|
||||
child: Container(
|
||||
constraints: BoxConstraints(maxWidth: 640),
|
||||
|
@ -24,13 +24,13 @@ class NewsDetailScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _NewsDetailScreenState extends State<NewsDetailScreen> {
|
||||
SnNewsArticle? _article;
|
||||
SnSubscriptionItem? _article;
|
||||
|
||||
Future<void> _fetchArticle() async {
|
||||
try {
|
||||
final sn = context.read<SnNetworkProvider>();
|
||||
final resp = await sn.client.get('/cgi/re/news/${widget.hash}');
|
||||
_article = SnNewsArticle.fromJson(resp.data);
|
||||
_article = SnSubscriptionItem.fromJson(resp.data);
|
||||
} catch (err) {
|
||||
if (!mounted) return;
|
||||
context.showErrorDialog(err).then((_) {
|
||||
|
@ -66,7 +66,8 @@ class _NewsScreenState extends State<NewsScreen> {
|
||||
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||
return <Widget>[
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
handle:
|
||||
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
sliver: SliverAppBar(
|
||||
leading: AutoAppBarLeading(),
|
||||
title: Text('screenNews').tr(),
|
||||
@ -75,10 +76,13 @@ class _NewsScreenState extends State<NewsScreen> {
|
||||
bottom: TabBar(
|
||||
isScrollable: true,
|
||||
tabs: [
|
||||
Tab(child: Text('newsAllSources'.tr()).textColor(Theme.of(context).appBarTheme.foregroundColor)),
|
||||
Tab(
|
||||
child: Text('newsAllSources'.tr()).textColor(
|
||||
Theme.of(context).appBarTheme.foregroundColor)),
|
||||
for (final source in _sources!)
|
||||
Tab(
|
||||
child: Text(source.label).textColor(Theme.of(context).appBarTheme.foregroundColor),
|
||||
child: Text(source.label).textColor(
|
||||
Theme.of(context).appBarTheme.foregroundColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -116,7 +120,7 @@ class _NewsArticleListWidgetState extends State<_NewsArticleListWidget> {
|
||||
bool _isBusy = false;
|
||||
|
||||
int? _totalCount;
|
||||
final List<SnNewsArticle> _articles = List.empty(growable: true);
|
||||
final List<SnSubscriptionItem> _articles = List.empty(growable: true);
|
||||
|
||||
Future<void> _fetchArticles() async {
|
||||
setState(() => _isBusy = true);
|
||||
@ -129,8 +133,8 @@ class _NewsArticleListWidgetState extends State<_NewsArticleListWidget> {
|
||||
if (widget.source != null) 'source': widget.source,
|
||||
});
|
||||
_totalCount = resp.data['count'];
|
||||
_articles.addAll(List<SnNewsArticle>.from(
|
||||
resp.data['data']?.map((e) => SnNewsArticle.fromJson(e)) ?? [],
|
||||
_articles.addAll(List<SnSubscriptionItem>.from(
|
||||
resp.data['data']?.map((e) => SnSubscriptionItem.fromJson(e)) ?? [],
|
||||
));
|
||||
} catch (err) {
|
||||
if (!mounted) return;
|
||||
@ -159,7 +163,8 @@ class _NewsArticleListWidgetState extends State<_NewsArticleListWidget> {
|
||||
child: InfiniteList(
|
||||
isLoading: _isBusy,
|
||||
itemCount: _articles.length,
|
||||
hasReachedMax: _totalCount != null && _articles.length >= _totalCount!,
|
||||
hasReachedMax:
|
||||
_totalCount != null && _articles.length >= _totalCount!,
|
||||
onFetchData: () {
|
||||
_fetchArticles();
|
||||
},
|
||||
@ -184,7 +189,8 @@ class _NewsArticleListWidgetState extends State<_NewsArticleListWidget> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (article.thumbnail.isNotEmpty && !article.thumbnail.endsWith('.svg'))
|
||||
if (article.thumbnail.isNotEmpty &&
|
||||
!article.thumbnail.endsWith('.svg'))
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(8),
|
||||
@ -193,7 +199,9 @@ class _NewsArticleListWidgetState extends State<_NewsArticleListWidget> {
|
||||
child: AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainer,
|
||||
child: AutoResizeUniversalImage(
|
||||
article.thumbnail.startsWith('http')
|
||||
? article.thumbnail
|
||||
@ -203,25 +211,38 @@ class _NewsArticleListWidgetState extends State<_NewsArticleListWidget> {
|
||||
),
|
||||
),
|
||||
const Gap(16),
|
||||
Text(article.title).textStyle(Theme.of(context).textTheme.titleLarge!).padding(horizontal: 16),
|
||||
Text(article.title)
|
||||
.textStyle(Theme.of(context).textTheme.titleLarge!)
|
||||
.padding(horizontal: 16),
|
||||
const Gap(8),
|
||||
Text(htmlDescription.children.map((ele) => ele.text.trim()).join())
|
||||
Text(htmlDescription.children
|
||||
.map((ele) => ele.text.trim())
|
||||
.join())
|
||||
.textStyle(Theme.of(context).textTheme.bodyMedium!)
|
||||
.padding(horizontal: 16),
|
||||
const Gap(8),
|
||||
Row(
|
||||
spacing: 2,
|
||||
children: [
|
||||
Text(widget.allSources.where((x) => x.id == article.source).first.label)
|
||||
.textStyle(Theme.of(context).textTheme.bodySmall!),
|
||||
Text(widget.allSources
|
||||
.where((x) => x.id == article.feedId)
|
||||
.first
|
||||
.label)
|
||||
.textStyle(
|
||||
Theme.of(context).textTheme.bodySmall!),
|
||||
],
|
||||
).opacity(0.75).padding(horizontal: 16),
|
||||
Row(
|
||||
spacing: 2,
|
||||
children: [
|
||||
Text(DateFormat().format(date)).textStyle(Theme.of(context).textTheme.bodySmall!),
|
||||
Text(' · ').textStyle(Theme.of(context).textTheme.bodySmall!).bold(),
|
||||
Text(RelativeTime(context).format(date)).textStyle(Theme.of(context).textTheme.bodySmall!),
|
||||
Text(DateFormat().format(date)).textStyle(
|
||||
Theme.of(context).textTheme.bodySmall!),
|
||||
Text(' · ')
|
||||
.textStyle(
|
||||
Theme.of(context).textTheme.bodySmall!)
|
||||
.bold(),
|
||||
Text(RelativeTime(context).format(date)).textStyle(
|
||||
Theme.of(context).textTheme.bodySmall!),
|
||||
],
|
||||
).opacity(0.75).padding(horizontal: 16),
|
||||
const Gap(16),
|
||||
|
Reference in New Issue
Block a user