feat: add RssItemMeta.fromNewsItem adapter factory
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user