diff --git a/README.md b/README.md index 4f99d78..283a638 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ MioFeed - Modern RSS reader - [x] 更新订阅 - [x] 删除订阅 - [x] 获取订阅 + - [x] 时间排序 - [ ] 主题功能 - [ ] 订阅分组 diff --git a/lib/models/universal_feed.dart b/lib/models/universal_feed.dart index 5aad009..2752db1 100644 --- a/lib/models/universal_feed.dart +++ b/lib/models/universal_feed.dart @@ -31,7 +31,7 @@ class UniversalFeed { : title = atom.title ?? '无标题', author = _atomToUniversalPersonList(atom.authors), description = '没有介绍', - icon = atom.logo ?? '', + icon = atom.icon ?? '', link = atom.links.first.href ?? '',//atom.links, copyright = atom.rights ?? '', categories = _atomToStringCategories(atom.categories), @@ -51,7 +51,7 @@ class UniversalFeed { : title = rss.title ?? '无标题', author = [UniversalPerson(name: rss.author)], description = rss.description ?? '没有介绍', - icon = rss.image?.link ?? '', + icon = rss.image?.url ?? '', link = rss.link ?? '', copyright = rss.copyright ?? '没有版权信息', categories = _rssToStringCategories(rss.categories), @@ -186,6 +186,12 @@ class UniversalFeed { } catch (ignored) { // ignored } + } else { + try { + return DateTime.parse(dateString); + } catch (ignored) { + // ignored + } } return null; } diff --git a/lib/models/universal_item.dart b/lib/models/universal_item.dart index 07c4d91..2327632 100644 --- a/lib/models/universal_item.dart +++ b/lib/models/universal_item.dart @@ -1,3 +1,5 @@ +import 'package:miofeed/models/universal_feed.dart'; + import 'generator.dart'; class UniversalItem { @@ -22,4 +24,9 @@ class UniversalItem { final DateTime? publishTime; final DateTime? updateTime; final String content; + + @override + String toString() { + return title; + } } diff --git a/lib/ui/home.dart b/lib/ui/home.dart index 1a05584..9e0b8f3 100644 --- a/lib/ui/home.dart +++ b/lib/ui/home.dart @@ -1,9 +1,11 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:miofeed/controllers/navigator_controller.dart'; +import 'package:miofeed/models/universal_feed.dart'; import 'package:miofeed/models/universal_item.dart'; import 'package:miofeed/ui/paragraph.dart'; import 'package:miofeed/utils/after_layout.dart'; +import 'package:miofeed/utils/paragraph_utils.dart'; import '../controllers/progressbar_controller.dart'; import '../utils/rss/rss_utils.dart'; @@ -47,16 +49,23 @@ class HomeUI extends StatelessWidget { itemBuilder: (context, index) { final para = hctr.allParagraph[index]; final UniversalItem paraData = para['item']; + final UniversalFeed paraFeed = para['feed_data']; + + // print(paraIconUrl); final paraDesc = paraData.content .replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' ') .replaceAll(RegExp(r'\n{2,}'), ' ') + .replaceAll(RegExp(r'\r{2,}'), ' ') .replaceAll(RegExp(r' {2,}'), ' ') .trim(); return InkWell( onTap: () async { - Get.to(() => ParagraphUI(data: paraData)); + Get.to(() => ParagraphUI( + data: paraData, + parent: paraFeed, + )); }, child: Card( child: Container( @@ -77,7 +86,43 @@ class HomeUI extends StatelessWidget { ? paraDesc : '${paraDesc.substring(0, 320)}......'), ), - _buildLabels(paraData.categories ?? []), + Row( + children: [ + // 图标 + Tooltip( + message: paraFeed.title, + child: Container( + margin: const EdgeInsets.only(right: 5), + child: ClipRRect( + borderRadius: + BorderRadius.circular(5), + child: SizedBox( + width: 20, + height: 20, + child: paraFeed.icon.isNotEmpty + ? Image.network( + paraFeed.icon, + errorBuilder: ( + context, + error, + stackTrace, + ) { + return ParagraphUtils + .buildColorIcon( + paraFeed.title, + ); + }, + ) + : ParagraphUtils.buildColorIcon( + paraFeed.title, + ), + ), + ), + ), + ), + _buildLabels(paraData.categories ?? []), + ], + ) ], ), ), @@ -101,6 +146,7 @@ class HomeUI extends StatelessWidget { labels += ' | $label'; } labels = labels.length > 3 ? labels.substring(3, labels.length) : labels; + if (labels.isEmpty) labels = '没有分类信息'; return Row( children: [ Container( @@ -126,6 +172,15 @@ class _HomeController extends GetxController { var allParagraph = [].obs; load() { - allParagraph.value = RssUtils.allRssParagraph; + final dataParagraph = RssUtils.allRssParagraph; + dataParagraph.sort((a, b) { + // TODO: 正序还是倒序显示文章 + final aTime = a['item'].publishTime ?? DateTime(0); + final bTime = b['item'].publishTime ?? DateTime(0); + final result = bTime.compareTo(aTime); + // print('${b['item'].title} $bTime, ${a['item'].title} $aTime, RES: $result'); + return result; + }); + allParagraph.value = dataParagraph; } } diff --git a/lib/ui/paragraph.dart b/lib/ui/paragraph.dart index cf3cfb7..fbf16ca 100644 --- a/lib/ui/paragraph.dart +++ b/lib/ui/paragraph.dart @@ -3,21 +3,26 @@ import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:miofeed/controllers/progressbar_controller.dart'; import 'package:miofeed/main.dart'; +import 'package:miofeed/models/universal_feed.dart'; import 'package:miofeed/models/universal_item.dart'; import 'package:miofeed/ui/models/navigation_bar.dart'; import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; +import '../utils/paragraph_utils.dart'; + class ParagraphUI extends StatelessWidget { ParagraphUI({ super.key, // this.title, required this.data, + required this.parent, }); // final title; final UniversalItem data; + final UniversalFeed parent; final ProgressbarController progressbar = Get.find(); @@ -48,6 +53,37 @@ class ParagraphUI extends StatelessWidget { data.title, style: const TextStyle(fontSize: 30), ), + Row( + children: [ + Container( + margin: const EdgeInsets.only(right: 5), + child: ClipRRect( + borderRadius: BorderRadius.circular(5), + child: SizedBox( + width: 20, + height: 20, + child: parent.icon.isNotEmpty + ? Image.network( + parent.icon, + errorBuilder: ( + context, + error, + stackTrace, + ) { + return ParagraphUtils.buildColorIcon( + parent.title); + }, + ) + : ParagraphUtils.buildColorIcon(parent.title)), + ), + ), + Text( + '${parent.title} | ${data.publishTime != null ? dateFormatter.format(data.publishTime!) : '未知'}'), + ], + ), + Container( + margin: const EdgeInsets.only(bottom: 5), + ), Row( children: [ const Icon( diff --git a/lib/ui/settings/rss_sub.dart b/lib/ui/settings/rss_sub.dart index dc7ab8d..e84d06c 100644 --- a/lib/ui/settings/rss_sub.dart +++ b/lib/ui/settings/rss_sub.dart @@ -247,6 +247,7 @@ class _RssSubController extends GetxController { RSS data = await RssStorage().getRss(key); var uuid = const Uuid(); subListWidgets.add( + // 手势 Dismissible( key: Key('${uuid.v8()}@${data.name}'), onDismissed: (direction) { @@ -265,6 +266,7 @@ class _RssSubController extends GetxController { color: Colors.white, ), ), + // 点击 child: InkWell( child: ListTile( title: Text('${data.showName} (${data.name})'), diff --git a/lib/utils/color.dart b/lib/utils/color.dart new file mode 100644 index 0000000..1e70772 --- /dev/null +++ b/lib/utils/color.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart' as md; + +class Color { + /// 根据字符串生成一个颜色 + /// [string] 字符串 + static md.Color stringToColor(String string) { + string = string.length > 20 ? string.substring(0, 20) : string; + + int hash = 0; + for (int i = 0; i < string.length; i++) { + hash = string.codeUnitAt(i) + ((hash << 5) - hash); + } + + String colorString = '#'; + for (int i = 0; i < 3; i++) { + int value = (hash >> (i * 8)) & 0xFF; + colorString += value.toRadixString(16).padLeft(2, '0'); + } + + return md.Color( + int.parse(colorString.substring(1), radix: 16) + 0xFF000000, + ); + } +} diff --git a/lib/utils/paragraph_utils.dart b/lib/utils/paragraph_utils.dart new file mode 100644 index 0000000..51276ea --- /dev/null +++ b/lib/utils/paragraph_utils.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; +import 'package:miofeed/utils/color.dart' as color_utils; + +class ParagraphUtils { + static Widget buildColorIcon(String subName) { + return Container( + color: color_utils.Color.stringToColor(subName), + child: Center(child: Text(subName.substring(0, 1))), + ); + } +} \ No newline at end of file