mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-09-01 09:14:06 +00:00
show news icon
This commit is contained in:
parent
9f8cb6f735
commit
7e3caec42e
11 changed files with 152 additions and 111 deletions
|
|
@ -806,11 +806,11 @@ abstract class AppLocalizations {
|
||||||
/// **'Feedback submitted successfully!'**
|
/// **'Feedback submitted successfully!'**
|
||||||
String get contactUsSuccess;
|
String get contactUsSuccess;
|
||||||
|
|
||||||
/// No description provided for @contactUsShortcut.
|
/// No description provided for @hideNewsIcon.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Hide Feedback Icon'**
|
/// **'Hide News Icon'**
|
||||||
String get contactUsShortcut;
|
String get hideNewsIcon;
|
||||||
|
|
||||||
/// No description provided for @settingsHelpTerms.
|
/// No description provided for @settingsHelpTerms.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -386,7 +386,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get contactUsSuccess => 'Feedback erfolgreich übermittelt!';
|
String get contactUsSuccess => 'Feedback erfolgreich übermittelt!';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get contactUsShortcut => 'Feedback-Symbol ausblenden';
|
String get hideNewsIcon => 'Neuigkeiten-Symbol ausblenden';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsHelpTerms => 'Nutzungsbedingungen';
|
String get settingsHelpTerms => 'Nutzungsbedingungen';
|
||||||
|
|
|
||||||
|
|
@ -382,7 +382,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get contactUsSuccess => 'Feedback submitted successfully!';
|
String get contactUsSuccess => 'Feedback submitted successfully!';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get contactUsShortcut => 'Hide Feedback Icon';
|
String get hideNewsIcon => 'Hide News Icon';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsHelpTerms => 'Terms of Service';
|
String get settingsHelpTerms => 'Terms of Service';
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit bb353aa572623d20578f470d2c683ead79669ed8
|
Subproject commit 1727cd6d4f2c56f976883497c182b1456033b614
|
||||||
|
|
@ -72,7 +72,7 @@ class UserData {
|
||||||
bool videoStabilizationEnabled = true;
|
bool videoStabilizationEnabled = true;
|
||||||
|
|
||||||
@JsonKey(defaultValue: true)
|
@JsonKey(defaultValue: true)
|
||||||
bool showFeedbackShortcut = true;
|
bool showNewsShortcut = true;
|
||||||
|
|
||||||
@JsonKey(defaultValue: false)
|
@JsonKey(defaultValue: false)
|
||||||
bool showShowImagePreviewWhenSending = false;
|
bool showShowImagePreviewWhenSending = false;
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) =>
|
||||||
json['automaticallyMarkEqualMediaFilesAsOpened'] as bool? ?? false
|
json['automaticallyMarkEqualMediaFilesAsOpened'] as bool? ?? false
|
||||||
..videoStabilizationEnabled =
|
..videoStabilizationEnabled =
|
||||||
json['videoStabilizationEnabled'] as bool? ?? true
|
json['videoStabilizationEnabled'] as bool? ?? true
|
||||||
..showFeedbackShortcut = json['showFeedbackShortcut'] as bool? ?? true
|
..showNewsShortcut = json['showNewsShortcut'] as bool? ?? true
|
||||||
..showShowImagePreviewWhenSending =
|
..showShowImagePreviewWhenSending =
|
||||||
json['showShowImagePreviewWhenSending'] as bool? ?? false
|
json['showShowImagePreviewWhenSending'] as bool? ?? false
|
||||||
..startWithCameraOpen = json['startWithCameraOpen'] as bool? ?? true
|
..startWithCameraOpen = json['startWithCameraOpen'] as bool? ?? true
|
||||||
|
|
@ -142,7 +142,7 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
|
||||||
'automaticallyMarkEqualMediaFilesAsOpened':
|
'automaticallyMarkEqualMediaFilesAsOpened':
|
||||||
instance.automaticallyMarkEqualMediaFilesAsOpened,
|
instance.automaticallyMarkEqualMediaFilesAsOpened,
|
||||||
'videoStabilizationEnabled': instance.videoStabilizationEnabled,
|
'videoStabilizationEnabled': instance.videoStabilizationEnabled,
|
||||||
'showFeedbackShortcut': instance.showFeedbackShortcut,
|
'showNewsShortcut': instance.showNewsShortcut,
|
||||||
'showShowImagePreviewWhenSending': instance.showShowImagePreviewWhenSending,
|
'showShowImagePreviewWhenSending': instance.showShowImagePreviewWhenSending,
|
||||||
'startWithCameraOpen': instance.startWithCameraOpen,
|
'startWithCameraOpen': instance.startWithCameraOpen,
|
||||||
'preSelectedEmojies': instance.preSelectedEmojies,
|
'preSelectedEmojies': instance.preSelectedEmojies,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@ class BlogEntry {
|
||||||
guid: (json['guid'] as String?) ?? '',
|
guid: (json['guid'] as String?) ?? '',
|
||||||
description: (json['description'] as String?) ?? '',
|
description: (json['description'] as String?) ?? '',
|
||||||
imageUrl: (json['imageUrl'] as String?) ?? '',
|
imageUrl: (json['imageUrl'] as String?) ?? '',
|
||||||
pubDate: json['pubDate'] != null ? DateTime.tryParse(json['pubDate'] as String) : null,
|
pubDate: json['pubDate'] != null
|
||||||
|
? DateTime.tryParse(json['pubDate'] as String)
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|
@ -56,7 +58,8 @@ class NewsService {
|
||||||
|
|
||||||
final ValueNotifier<int> unreadCountNotifier = ValueNotifier<int>(0);
|
final ValueNotifier<int> unreadCountNotifier = ValueNotifier<int>(0);
|
||||||
|
|
||||||
File get _cacheFile => File(join(AppEnvironment.supportDir, 'news_feed.json'));
|
File get _cacheFile =>
|
||||||
|
File(join(AppEnvironment.supportDir, 'news_feed.json'));
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
try {
|
try {
|
||||||
|
|
@ -152,7 +155,9 @@ class NewsService {
|
||||||
|
|
||||||
_updateUnreadCount();
|
_updateUnreadCount();
|
||||||
await saveCache();
|
await saveCache();
|
||||||
Log.info('Successfully fetched ${entries.length} news entries. Unread count: ${unreadCountNotifier.value}');
|
Log.info(
|
||||||
|
'Successfully fetched ${entries.length} news entries. Unread count: ${unreadCountNotifier.value}',
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error('Failed to fetch news feed: $e');
|
Log.error('Failed to fetch news feed: $e');
|
||||||
}
|
}
|
||||||
|
|
@ -166,32 +171,54 @@ class NewsService {
|
||||||
for (final match in matches) {
|
for (final match in matches) {
|
||||||
final itemContent = match.group(1) ?? '';
|
final itemContent = match.group(1) ?? '';
|
||||||
|
|
||||||
final titleMatch = RegExp(r'<title>([\s\S]*?)<\/title>').firstMatch(itemContent);
|
final titleMatch = RegExp(
|
||||||
|
r'<title>([\s\S]*?)<\/title>',
|
||||||
|
).firstMatch(itemContent);
|
||||||
final title = _stripCdata(titleMatch?.group(1) ?? '');
|
final title = _stripCdata(titleMatch?.group(1) ?? '');
|
||||||
|
|
||||||
final linkMatch = RegExp(r'<link>([\s\S]*?)<\/link>').firstMatch(itemContent);
|
final linkMatch = RegExp(
|
||||||
|
r'<link>([\s\S]*?)<\/link>',
|
||||||
|
).firstMatch(itemContent);
|
||||||
final link = _stripCdata(linkMatch?.group(1) ?? '');
|
final link = _stripCdata(linkMatch?.group(1) ?? '');
|
||||||
|
|
||||||
final guidMatch = RegExp(r'<guid[^>]*?>([\s\S]*?)<\/guid>').firstMatch(itemContent);
|
final guidMatch = RegExp(
|
||||||
|
r'<guid[^>]*?>([\s\S]*?)<\/guid>',
|
||||||
|
).firstMatch(itemContent);
|
||||||
final guid = _stripCdata(guidMatch?.group(1) ?? link);
|
final guid = _stripCdata(guidMatch?.group(1) ?? link);
|
||||||
|
|
||||||
final descMatch = RegExp(r'<description>([\s\S]*?)<\/description>').firstMatch(itemContent);
|
final descMatch = RegExp(
|
||||||
|
r'<description>([\s\S]*?)<\/description>',
|
||||||
|
).firstMatch(itemContent);
|
||||||
final descriptionRaw = _stripCdata(descMatch?.group(1) ?? '');
|
final descriptionRaw = _stripCdata(descMatch?.group(1) ?? '');
|
||||||
final description = descriptionRaw.replaceAll(RegExp('<[^>]*>'), '');
|
final description = descriptionRaw
|
||||||
|
.replaceAll('<', '<')
|
||||||
|
.replaceAll('>', '>')
|
||||||
|
.replaceAll('&', '&')
|
||||||
|
.replaceAll('"', '"')
|
||||||
|
.replaceAll(''', "'")
|
||||||
|
.replaceAll(''', "'")
|
||||||
|
.replaceAll(RegExp('<[^>]*>'), '')
|
||||||
|
.trim();
|
||||||
|
|
||||||
var imageUrl = '';
|
var imageUrl = '';
|
||||||
final enclosureMatch = RegExp(r'<enclosure\s+[^>]*?url="([^"]+)"').firstMatch(itemContent);
|
final enclosureMatch = RegExp(
|
||||||
|
r'<enclosure\s+[^>]*?url="([^"]+)"',
|
||||||
|
).firstMatch(itemContent);
|
||||||
if (enclosureMatch != null) {
|
if (enclosureMatch != null) {
|
||||||
imageUrl = enclosureMatch.group(1) ?? '';
|
imageUrl = enclosureMatch.group(1) ?? '';
|
||||||
}
|
}
|
||||||
if (imageUrl.isEmpty) {
|
if (imageUrl.isEmpty) {
|
||||||
final mediaMatch = RegExp(r'<media:content\s+[^>]*?url="([^"]+)"').firstMatch(itemContent);
|
final mediaMatch = RegExp(
|
||||||
|
r'<media:content\s+[^>]*?url="([^"]+)"',
|
||||||
|
).firstMatch(itemContent);
|
||||||
if (mediaMatch != null) {
|
if (mediaMatch != null) {
|
||||||
imageUrl = mediaMatch.group(1) ?? '';
|
imageUrl = mediaMatch.group(1) ?? '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final pubDateMatch = RegExp(r'<pubDate>([\s\S]*?)<\/pubDate>').firstMatch(itemContent);
|
final pubDateMatch = RegExp(
|
||||||
|
r'<pubDate>([\s\S]*?)<\/pubDate>',
|
||||||
|
).firstMatch(itemContent);
|
||||||
DateTime? pubDate;
|
DateTime? pubDate;
|
||||||
if (pubDateMatch != null) {
|
if (pubDateMatch != null) {
|
||||||
final pubDateStr = pubDateMatch.group(1) ?? '';
|
final pubDateStr = pubDateMatch.group(1) ?? '';
|
||||||
|
|
@ -199,14 +226,16 @@ class NewsService {
|
||||||
pubDate ??= _parseRfc2822(pubDateStr);
|
pubDate ??= _parseRfc2822(pubDateStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.add(BlogEntry(
|
entries.add(
|
||||||
|
BlogEntry(
|
||||||
title: title,
|
title: title,
|
||||||
link: link,
|
link: link,
|
||||||
guid: guid,
|
guid: guid,
|
||||||
description: description,
|
description: description,
|
||||||
imageUrl: imageUrl,
|
imageUrl: imageUrl,
|
||||||
pubDate: pubDate,
|
pubDate: pubDate,
|
||||||
));
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
|
|
@ -238,14 +267,30 @@ class NewsService {
|
||||||
|
|
||||||
final timeParts = parts[3].split(':');
|
final timeParts = parts[3].split(':');
|
||||||
final hour = timeParts.isNotEmpty ? (int.tryParse(timeParts[0]) ?? 0) : 0;
|
final hour = timeParts.isNotEmpty ? (int.tryParse(timeParts[0]) ?? 0) : 0;
|
||||||
final minute = timeParts.length > 1 ? (int.tryParse(timeParts[1]) ?? 0) : 0;
|
final minute = timeParts.length > 1
|
||||||
final second = timeParts.length > 2 ? (int.tryParse(timeParts[2]) ?? 0) : 0;
|
? (int.tryParse(timeParts[1]) ?? 0)
|
||||||
|
: 0;
|
||||||
|
final second = timeParts.length > 2
|
||||||
|
? (int.tryParse(timeParts[2]) ?? 0)
|
||||||
|
: 0;
|
||||||
|
|
||||||
const months = {
|
const months = {
|
||||||
'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4, 'may': 5, 'jun': 6,
|
'jan': 1,
|
||||||
'jul': 7, 'aug': 8, 'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12
|
'feb': 2,
|
||||||
|
'mar': 3,
|
||||||
|
'apr': 4,
|
||||||
|
'may': 5,
|
||||||
|
'jun': 6,
|
||||||
|
'jul': 7,
|
||||||
|
'aug': 8,
|
||||||
|
'sep': 9,
|
||||||
|
'oct': 10,
|
||||||
|
'nov': 11,
|
||||||
|
'dec': 12,
|
||||||
};
|
};
|
||||||
final monthStringPart = monthStr.length > 3 ? monthStr.substring(0, 3) : monthStr;
|
final monthStringPart = monthStr.length > 3
|
||||||
|
? monthStr.substring(0, 3)
|
||||||
|
: monthStr;
|
||||||
final month = months[monthStringPart] ?? 1;
|
final month = months[monthStringPart] ?? 1;
|
||||||
|
|
||||||
return DateTime.utc(year, month, day, hour, minute, second);
|
return DateTime.utc(year, month, day, hour, minute, second);
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
||||||
import 'package:go_router/go_router.dart';
|
|
||||||
import 'package:twonly/locator.dart';
|
|
||||||
import 'package:twonly/src/constants/routes.keys.dart';
|
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
|
||||||
|
|
||||||
class FeedbackIconButtonComp extends StatelessWidget {
|
|
||||||
const FeedbackIconButtonComp({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return StreamBuilder(
|
|
||||||
stream: userService.onUserUpdated,
|
|
||||||
builder: (context, asyncSnapshot) {
|
|
||||||
if (!userService.currentUser.showFeedbackShortcut) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
return IconButton(
|
|
||||||
onPressed: () => context.push(Routes.settingsHelpContactUs),
|
|
||||||
color: Colors.grey,
|
|
||||||
tooltip: context.lang.feedbackTooltip,
|
|
||||||
icon: const FaIcon(FontAwesomeIcons.commentDots, size: 19),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,25 +5,36 @@ import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/constants/routes.keys.dart';
|
import 'package:twonly/src/constants/routes.keys.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/components/notification_badge.comp.dart';
|
import 'package:twonly/src/visual/components/notification_badge.comp.dart';
|
||||||
|
import 'package:twonly/src/visual/themes/light.dart';
|
||||||
|
|
||||||
class NewsIconButtonComp extends StatelessWidget {
|
class NewsIconButtonComp extends StatelessWidget {
|
||||||
const NewsIconButtonComp({super.key});
|
const NewsIconButtonComp({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
return StreamBuilder(
|
||||||
|
stream: userService.onUserUpdated,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!userService.currentUser.showNewsShortcut) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
return ValueListenableBuilder<int>(
|
return ValueListenableBuilder<int>(
|
||||||
valueListenable: newsService.unreadCountNotifier,
|
valueListenable: newsService.unreadCountNotifier,
|
||||||
builder: (context, count, child) {
|
builder: (context, count, child) {
|
||||||
return NotificationBadgeComp(
|
return NotificationBadgeComp(
|
||||||
count: count.toString(),
|
count: count.toString(),
|
||||||
|
backgroundColor: primaryColor,
|
||||||
|
textColor: Colors.black87,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () => context.push(Routes.settingsHelpNews),
|
onPressed: () => context.push(Routes.settingsHelpNews),
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
tooltip: context.lang.settingsHelpNews,
|
tooltip: context.lang.settingsHelpNews,
|
||||||
icon: const FaIcon(FontAwesomeIcons.newspaper, size: 19),
|
icon: const FaIcon(FontAwesomeIcons.bullhorn, size: 19),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,9 @@ class _AppearanceViewState extends State<AppearanceView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleShowFeedbackIcon() async {
|
Future<void> toggleShowNewsIcon() async {
|
||||||
await UserService.update((u) {
|
await UserService.update((u) {
|
||||||
u.showFeedbackShortcut = !u.showFeedbackShortcut;
|
u.showNewsShortcut = !u.showNewsShortcut;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,11 +113,11 @@ class _AppearanceViewState extends State<AppearanceView> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(context.lang.contactUsShortcut),
|
title: Text(context.lang.hideNewsIcon),
|
||||||
onTap: toggleShowFeedbackIcon,
|
onTap: toggleShowNewsIcon,
|
||||||
trailing: Switch.adaptive(
|
trailing: Switch.adaptive(
|
||||||
value: !userService.currentUser.showFeedbackShortcut,
|
value: !userService.currentUser.showNewsShortcut,
|
||||||
onChanged: (a) => toggleShowFeedbackIcon(),
|
onChanged: (a) => toggleShowNewsIcon(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
import 'package:twonly/src/visual/elements/reactive_tap_feedback.element.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class NewsView extends StatefulWidget {
|
class NewsView extends StatefulWidget {
|
||||||
|
|
@ -42,18 +43,24 @@ class _NewsViewState extends State<NewsView> {
|
||||||
itemCount: entries.length,
|
itemCount: entries.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final entry = entries[index];
|
final entry = entries[index];
|
||||||
return Card(
|
final isDark = isDarkMode(context);
|
||||||
clipBehavior: Clip.antiAlias,
|
|
||||||
shape: RoundedRectangleBorder(
|
return ReactiveTapFeedback(
|
||||||
borderRadius: BorderRadius.circular(16),
|
|
||||||
),
|
|
||||||
elevation: 2,
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () => launchUrl(
|
onTap: () => launchUrl(
|
||||||
Uri.parse(entry.link),
|
Uri.parse(entry.link),
|
||||||
mode: LaunchMode.externalApplication,
|
mode: LaunchMode.externalApplication,
|
||||||
),
|
),
|
||||||
|
child: Card(
|
||||||
|
color: isDark ? Colors.grey[800] : Colors.grey[200],
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
elevation: 0,
|
||||||
|
margin: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -65,14 +72,15 @@ class _NewsViewState extends State<NewsView> {
|
||||||
placeholder: (context, url) => Container(
|
placeholder: (context, url) => Container(
|
||||||
height: 180,
|
height: 180,
|
||||||
color: Colors.grey.withValues(alpha: 0.1),
|
color: Colors.grey.withValues(alpha: 0.1),
|
||||||
child: const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
errorWidget: (context, url, error) => Container(
|
errorWidget: (context, url, error) => Container(
|
||||||
height: 180,
|
height: 180,
|
||||||
color: Colors.grey.withValues(alpha: 0.1),
|
color: Colors.grey.withValues(alpha: 0.1),
|
||||||
child: const Icon(Icons.broken_image, size: 50, color: Colors.grey),
|
child: const Icon(
|
||||||
|
Icons.broken_image,
|
||||||
|
size: 50,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
|
@ -85,7 +93,8 @@ class _NewsViewState extends State<NewsView> {
|
||||||
DateFormat.yMMMMd(
|
DateFormat.yMMMMd(
|
||||||
Localizations.localeOf(context).toString(),
|
Localizations.localeOf(context).toString(),
|
||||||
).format(entry.pubDate!),
|
).format(entry.pubDate!),
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall
|
||||||
|
?.copyWith(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -93,7 +102,8 @@ class _NewsViewState extends State<NewsView> {
|
||||||
],
|
],
|
||||||
Text(
|
Text(
|
||||||
entry.title,
|
entry.title,
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
style: Theme.of(context).textTheme.titleLarge
|
||||||
|
?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -102,8 +112,11 @@ class _NewsViewState extends State<NewsView> {
|
||||||
entry.description,
|
entry.description,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: Theme.of(context).textTheme.bodyMedium
|
||||||
color: context.color.onSurface.withValues(alpha: 0.8),
|
?.copyWith(
|
||||||
|
color: context.color.onSurface.withValues(
|
||||||
|
alpha: 0.8,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue