feat: add RssItemMeta.fromNewsItem adapter factory

This commit is contained in:
2026-04-06 08:18:34 -04:00
parent b56f3d3a0f
commit 01ea6b48db
+46 -2
View File
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../data/models/news_item.dart';
class RssItemMeta { class RssItemMeta {
final int id; final int id;
final String title; final String title;
@@ -29,6 +31,15 @@ class RssItemMeta {
: null, : null,
); );
factory RssItemMeta.fromNewsItem(NewsItem item) => RssItemMeta(
id: item.id,
title: item.title,
url: item.url,
source: item.source,
snippet: item.snippet,
publishedAt: item.publishedAt,
);
String get relativeDate { String get relativeDate {
if (publishedAt == null) return ''; if (publishedAt == null) return '';
final diff = DateTime.now().difference(publishedAt!); final diff = DateTime.now().difference(publishedAt!);
@@ -42,12 +53,14 @@ class NewsCard extends StatelessWidget {
final RssItemMeta item; final RssItemMeta item;
final String? reaction; // 'up' | 'down' | null final String? reaction; // 'up' | 'down' | null
final void Function(int itemId, String reaction) onReaction; final void Function(int itemId, String reaction) onReaction;
final VoidCallback? onDiscuss;
const NewsCard({ const NewsCard({
super.key, super.key,
required this.item, required this.item,
required this.reaction, required this.reaction,
required this.onReaction, required this.onReaction,
this.onDiscuss,
}); });
Future<void> _openUrl() async { Future<void> _openUrl() async {
@@ -127,9 +140,8 @@ class NewsCard extends StatelessWidget {
), ),
], ],
const SizedBox(height: 8), const SizedBox(height: 8),
// Reaction buttons // Actions row: reactions + discuss
Row( Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
_ReactionButton( _ReactionButton(
emoji: '👍', emoji: '👍',
@@ -142,6 +154,10 @@ class NewsCard extends StatelessWidget {
active: reaction == 'down', active: reaction == 'down',
onTap: () => onReaction(item.id, 'down'), onTap: () => onReaction(item.id, 'down'),
), ),
if (onDiscuss != null) ...[
const Spacer(),
_DiscussButton(onTap: onDiscuss!),
],
], ],
), ),
], ],
@@ -151,6 +167,34 @@ class NewsCard extends StatelessWidget {
} }
} }
class _DiscussButton extends StatelessWidget {
final VoidCallback onTap;
const _DiscussButton({required this.onTap});
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 3),
decoration: BoxDecoration(
border: Border.all(color: scheme.primary.withValues(alpha: 0.5)),
borderRadius: BorderRadius.circular(6),
),
child: Text(
'Discuss',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: scheme.primary,
),
),
),
);
}
}
class _ReactionButton extends StatelessWidget { class _ReactionButton extends StatelessWidget {
final String emoji; final String emoji;
final bool active; final bool active;