Use old discovery card for the realm explore

This commit is contained in:
2025-12-24 00:48:12 +08:00
parent 689965c582
commit 0948810993
4 changed files with 152 additions and 12 deletions

View File

@@ -628,15 +628,15 @@ class _DiscoveryActivityItem extends StatelessWidget {
children: [
for (final item in items)
switch (type) {
'realm' => RealmCard(
'realm' => RealmDiscoveryCard(
realm: SnRealm.fromJson(item['data']),
maxWidth: 280,
),
'publisher' => PublisherCard(
'publisher' => PublisherDiscoveryCard(
publisher: SnPublisher.fromJson(item['data']),
maxWidth: 280,
),
'article' => WebArticleCard(
'article' => WebArticleDiscoveryCard(
article: SnWebArticle.fromJson(item['data']),
maxWidth: 280,
),

View File

@@ -5,11 +5,15 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/publisher.dart';
import 'package:island/widgets/content/cloud_files.dart';
class PublisherCard extends ConsumerWidget {
class PublisherDiscoveryCard extends ConsumerWidget {
final SnPublisher publisher;
final double? maxWidth;
const PublisherCard({super.key, required this.publisher, this.maxWidth});
const PublisherDiscoveryCard({
super.key,
required this.publisher,
this.maxWidth,
});
@override
Widget build(BuildContext context, WidgetRef ref) {

View File

@@ -6,21 +6,20 @@ import 'package:island/models/realm.dart';
import 'package:island/widgets/content/cloud_files.dart';
import 'package:material_symbols_icons/symbols.dart';
class RealmCard extends ConsumerWidget {
class RealmDiscoveryCard extends ConsumerWidget {
final SnRealm realm;
final double? maxWidth;
const RealmCard({super.key, required this.realm, this.maxWidth});
const RealmDiscoveryCard({super.key, required this.realm, this.maxWidth});
@override
Widget build(BuildContext context, WidgetRef ref) {
Widget imageWidget;
if (realm.picture != null) {
imageWidget =
imageWidget = CloudImageWidget(
file: realm.background,
fit: BoxFit.cover,
);
imageWidget = imageWidget = CloudImageWidget(
file: realm.background,
fit: BoxFit.cover,
);
} else {
imageWidget = ColoredBox(
color: Theme.of(context).colorScheme.secondaryContainer,

View File

@@ -71,3 +71,140 @@ class WebArticleCard extends StatelessWidget {
);
}
}
class WebArticleDiscoveryCard extends StatelessWidget {
final SnWebArticle article;
final double? maxWidth;
final bool showDetails;
const WebArticleDiscoveryCard({
super.key,
required this.article,
this.maxWidth,
this.showDetails = false,
});
void _onTap(BuildContext context) {
context.pushNamed('articleDetail', pathParameters: {'id': article.id});
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
return ConstrainedBox(
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
child: Card(
margin: EdgeInsets.zero,
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () => _onTap(context),
child: AspectRatio(
aspectRatio: 16 / 9,
child: Stack(
fit: StackFit.expand,
children: [
// Image or fallback
article.preview?.imageUrl != null
? CachedNetworkImage(
imageUrl: article.preview!.imageUrl!,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
)
: ColoredBox(
color: colorScheme.secondaryContainer,
child: const Center(
child: Icon(
Icons.article_outlined,
size: 48,
color: Colors.white,
),
),
),
// Gradient overlay
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.transparent,
Colors.black.withOpacity(0.7),
],
),
),
),
// Title
Align(
alignment: Alignment.bottomLeft,
child: Container(
padding: const EdgeInsets.only(
left: 12,
right: 12,
bottom: 8,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
if (showDetails)
const SizedBox(height: 8)
else
Spacer(),
Text(
article.title,
style: theme.textTheme.titleSmall?.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
height: 1.3,
),
maxLines: showDetails ? 3 : 1,
overflow: TextOverflow.ellipsis,
),
if (showDetails &&
article.author?.isNotEmpty == true) ...[
const SizedBox(height: 4),
Text(
article.author!,
style: TextStyle(
fontSize: 10,
color: Colors.white.withOpacity(0.9),
fontWeight: FontWeight.w500,
),
),
],
if (showDetails) const Spacer(),
if (showDetails && article.publishedAt != null) ...[
Text(
'${article.publishedAt!.formatSystem()} · ${article.publishedAt!.formatRelative(context)}',
style: const TextStyle(
fontSize: 9,
color: Colors.white70,
),
),
const SizedBox(height: 2),
],
Text(
article.feed?.title ?? 'Unknown Source',
style: const TextStyle(
fontSize: 9,
color: Colors.white70,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
),
],
),
),
),
),
);
}
}