新增信息流 (接入 Anicat G佬 新闻组+)

This commit is contained in:
xkeyC 2023-11-28 23:08:34 +08:00
parent 4f6623a4cd
commit 4d7f73ffc4
5 changed files with 214 additions and 105 deletions

31
lib/api/rss.dart Normal file
View File

@ -0,0 +1,31 @@
import 'dart:io';
import 'package:dart_rss/dart_rss.dart';
import 'package:dio/dio.dart';
import 'package:starcitizen_doctor/common/conf.dart';
class RSSApi {
static final _dio = Dio(BaseOptions(
connectTimeout: const Duration(seconds: 10),
responseType: ResponseType.plain));
static Future<List<RssItem>> getRssVideo() async {
final r = await _dio.get(AppConf.rssVideoUrl);
final f = RssFeed.parse(r.data);
return f.items.sublist(0, 8);
}
static Future<List<RssItem>> getRssText() async {
final r1 = await _dio.get(AppConf.rssTextUrl1);
final r1f = RssFeed.parse(r1.data);
final r2 = await _dio.get(AppConf.rssTextUrl2);
final r2f = RssFeed.parse(r2.data);
final items = r1f.items..addAll(r2f.items);
items.sort((a, b) {
final aDate = HttpDate.parse(a.pubDate ?? "").millisecondsSinceEpoch;
final bDate = HttpDate.parse(b.pubDate ?? "").millisecondsSinceEpoch;
return bDate - aDate;
});
return items;
}
}

View File

@ -34,6 +34,14 @@ class AppConf {
static const String xkeycApiUrl = "https://sctoolbox.xkeyc.com";
static const rssVideoUrl =
"https://rss.42kit.com/bilibili/user/channel/27976358/290653";
static const rssTextUrl1 =
"https://rss.42kit.com/bilibili/user/article/40102960";
static const rssTextUrl2 =
"https://rss.42kit.com/baidu/tieba/user/%E7%81%AC%E7%81%ACG%E7%81%AC%E7%81%AC&";
static late final String applicationSupportDir;
static AppVersionData? networkVersionData;
@ -90,8 +98,8 @@ class AppConf {
/// init windows
await windowManager.ensureInitialized();
windowManager.waitUntilReadyToShow().then((_) async {
await windowManager.setSize(const Size(1280, 820));
await windowManager.setMinimumSize(const Size(1280, 820));
await windowManager.setSize(const Size(1300, 830));
await windowManager.setMinimumSize(const Size(1300, 830));
await windowManager.center(animate: true);
await windowManager.setSkipTaskbar(false);
await windowManager.setTitleBarStyle(

View File

@ -1,11 +1,11 @@
import 'package:card_swiper/card_swiper.dart';
import 'package:extended_image/extended_image.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_tilt/flutter_tilt.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:starcitizen_doctor/api/analytics.dart';
import 'package:starcitizen_doctor/base/ui.dart';
import 'package:starcitizen_doctor/widgets/cache_image.dart';
import 'package:starcitizen_doctor/widgets/countdown_time_text.dart';
import 'package:url_launcher/url_launcher_string.dart';
@ -18,6 +18,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
children: [
Center(
child: SingleChildScrollView(
padding: EdgeInsets.zero,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -36,7 +37,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
? null
: () => model.closePlacard(),
),
const SizedBox(height: 12),
const SizedBox(height: 6),
],
if (!model.isChecking &&
model.checkResult != null &&
@ -71,7 +72,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
}
List<Widget> makeIndex(BuildContext context, HomeUIModel model) {
final width = MediaQuery.of(context).size.width * .21;
const double width = 280;
return [
Stack(
children: [
@ -80,10 +81,17 @@ class HomeUI extends BaseUI<HomeUIModel> {
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: Center(
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 30),
child: Image.asset(
"assets/sc_logo.png",
height: 256,
fit: BoxFit.fitHeight,
height: 260,
),
),
],
),
),
),
@ -224,25 +232,126 @@ class HomeUI extends BaseUI<HomeUIModel> {
Positioned(
left: 24,
bottom: 0,
child: SizedBox(
height: 420,
child: ScrollConfiguration(
behavior:
ScrollConfiguration.of(context).copyWith(scrollbars: false),
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 200,
width: 316,
child: Tilt(
shadowConfig: const ShadowConfig(maxIntensity: .3),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
child: model.rssVideoItems == null
? Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(.1)),
child: makeLoading(context),
)
: Swiper(
itemCount: model.rssVideoItems?.length ?? 0,
itemBuilder: (context, index) {
final item = model.rssVideoItems![index];
return GestureDetector(
onTap: () {
if (item.link != null) {
launchUrlString(item.link!);
}
},
child: CacheNetImage(
url: model.getRssImage(item),
fit: BoxFit.cover,
),
);
},
autoplay: true,
),
)),
SizedBox(
width: 316,
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(.1),
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12))),
child: model.rssTextItems == null
? Padding(
padding: const EdgeInsets.only(
top: 24, bottom: 24),
child: makeLoading(context),
)
: Column(
children: [
const SizedBox(height: 12),
makeADCard(context, model,
bgURl:
"https://i2.hdslb.com/bfs/face/7582c8d46fc03004f4f8032c667c0ea4dbbb1088.jpg",
title: "Anicat",
subtitle: "高质量星际公民资讯UP主",
jumpUrl: "https://space.bilibili.com/27976358/video"),
const SizedBox(height: 12),
makeADCard(context, model,
bgURl:
"https://citizenwiki.cn/images/f/f2/890Jump_beach.jpg.webp",
title: "星际公民中文百科",
subtitle: "探索宇宙的好伙伴",
jumpUrl: "https://citizenwiki.cn"),
const SizedBox(height: 12),
makeGameStatusCard(context, model, width),
ListView.builder(
physics:
const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder:
(BuildContext context, int index) {
final item = model.rssTextItems![index];
return Tilt(
shadowConfig: const ShadowConfig(
maxIntensity: .3),
borderRadius:
BorderRadius.circular(12),
child: GestureDetector(
onTap: () {
if (item.link != null) {
launchUrlString(item.link!);
}
},
child: Padding(
padding: const EdgeInsets.only(
left: 12,
right: 12,
top: 4,
bottom: 4),
child: Row(
children: [
const Text("· "),
Expanded(
child: Text(
"${item.title}",
textAlign:
TextAlign.start,
maxLines: 1,
overflow: TextOverflow
.ellipsis,
style: const TextStyle(
fontSize: 12.2),
),
)
],
),
),
));
},
itemCount: model.rssTextItems?.length,
),
const SizedBox(height: 12),
],
)),
),
],
)),
),
),
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Center(
child: makeGameStatusCard(context, model, 320),
))
],
),
@ -315,9 +424,7 @@ class HomeUI extends BaseUI<HomeUIModel> {
),
const SizedBox(height: 8),
Text(model.lastScreenInfo, maxLines: 1),
const SizedBox(height: 32),
makeIndexActionLists(context, model),
const SizedBox(height: 32),
];
}
@ -480,79 +587,6 @@ class HomeUI extends BaseUI<HomeUIModel> {
);
}
Widget makeADCard(
BuildContext context,
HomeUIModel model, {
required String bgURl,
required String title,
required String subtitle,
required String jumpUrl,
}) {
final width = MediaQuery.of(context).size.width * .21;
return Tilt(
shadowConfig: const ShadowConfig(maxIntensity: .3),
borderRadius: BorderRadius.circular(12),
child: GestureDetector(
onTap: () {
launchUrlString(jumpUrl);
},
child: ClipRRect(
child: Container(
width: width,
height: 128,
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor,
),
child: Stack(
children: [
Padding(
padding: const EdgeInsets.all(.3),
child: ExtendedImage.network(
bgURl,
fit: BoxFit.cover,
width: width,
),
),
Container(
width: width,
decoration: BoxDecoration(
color: Colors.black.withOpacity(.7),
),
),
Positioned(
top: 0,
bottom: 0,
left: 0,
right: 0,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
title,
style: const TextStyle(
fontSize: 24,
),
),
const SizedBox(height: 6),
Text(
subtitle,
style: TextStyle(
color: Colors.white.withOpacity(.8),
fontSize: 14),
),
],
),
),
)
],
),
),
),
),
);
}
Widget makeWebViewButton(HomeUIModel model,
{required Widget icon,
required String name,

View File

@ -2,11 +2,13 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:dart_rss/dart_rss.dart';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:dio/dio.dart';
import 'package:hive/hive.dart';
import 'package:starcitizen_doctor/api/analytics.dart';
import 'package:starcitizen_doctor/api/api.dart';
import 'package:starcitizen_doctor/api/rss.dart';
import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:starcitizen_doctor/common/conf.dart';
import 'package:starcitizen_doctor/common/helper/log_helper.dart';
@ -25,6 +27,9 @@ import 'package:starcitizen_doctor/ui/home/webview/webview.dart';
import 'package:starcitizen_doctor/ui/home/webview/webview_localization_capture_ui_model.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:html/parser.dart' as html;
import 'package:html/dom.dart' as htmlDom;
import 'countdown/countdown_dialog_ui.dart';
import 'localization/localization_ui.dart';
import 'performance/performance_ui.dart';
@ -48,6 +53,9 @@ class HomeUIModel extends BaseUIModel {
bool get isCurGameRunning => _isGameRunning[scInstalledPath] ?? false;
List<RssItem>? rssVideoItems;
List<RssItem>? rssTextItems;
set lastScreenInfo(String info) {
_lastScreenInfo = info;
notifyListeners();
@ -98,6 +106,7 @@ class HomeUIModel extends BaseUIModel {
.data));
countdownFestivalListData = await Api.getFestivalCountdownList();
notifyListeners();
handleError(() => _loadRRS());
} catch (e) {
dPrint(e);
}
@ -158,6 +167,15 @@ class HomeUIModel extends BaseUIModel {
}
}
Future _loadRRS() async {
final v = await RSSApi.getRssVideo();
rssVideoItems = v;
notifyListeners();
final t = await RSSApi.getRssText();
rssTextItems = t;
notifyListeners();
}
VoidCallback? doCheck() {
if (isChecking) return null;
return () async {
@ -573,4 +591,17 @@ class HomeUIModel extends BaseUIModel {
CountdownDialogUIModel(countdownFestivalListData!));
});
}
getRssImage(RssItem item) {
final h = html.parse(item.description ?? "");
if (h.body == null) return "";
for (var node in h.body!.nodes) {
if (node is htmlDom.Element) {
if (node.localName == "img") {
return node.attributes["src"]?.trim() ?? "";
}
}
}
return "";
}
}

View File

@ -42,7 +42,7 @@ dependencies:
path_provider: ^2.1.1
dio: ^5.3.3
markdown_widget: ^2.2.0
extended_image: ^8.1.1
extended_image: ^8.2.0
device_info_plus: ^9.0.3
file_picker: ^6.0.0
file_sizes: ^1.0.6
@ -62,6 +62,11 @@ dependencies:
cryptography: ^2.7.0
cryptography_flutter: ^2.3.2
hexcolor: ^3.0.1
dart_rss: ^3.0.1
html: ^0.15.4
dependency_overrides:
http: ^1.1.2
dev_dependencies:
flutter_test: