From eaae622f95b582bfd1f511e0ce1f70ecd08514ba Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 29 Jun 2024 17:12:06 +0800 Subject: [PATCH 1/5] =?UTF-8?q?opt:=20=E5=AD=97=E5=B9=95=E6=B8=B2=E6=9F=93?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/common/subtitle_type.dart | 95 ------------------- lib/models/video/subTitile/result.dart | 8 -- lib/pages/video/detail/controller.dart | 9 -- .../video/detail/introduction/controller.dart | 3 +- .../video/detail/widgets/header_control.dart | 9 +- lib/plugin/pl_player/controller.dart | 27 +----- 6 files changed, 11 insertions(+), 140 deletions(-) delete mode 100644 lib/models/common/subtitle_type.dart diff --git a/lib/models/common/subtitle_type.dart b/lib/models/common/subtitle_type.dart deleted file mode 100644 index ac3ee3e0..00000000 --- a/lib/models/common/subtitle_type.dart +++ /dev/null @@ -1,95 +0,0 @@ -enum SubtitleType { - // 中文(中国) - zhCN, - // 中文(自动翻译) - aizh, - // 英语(自动生成) - aien, - // 中文(简体) - zhHans, - // 英文(美国) - enUS, - // 中文繁体 - zhTW, - // - en, - // - pt, - // - es, -} - -extension SubtitleTypeExtension on SubtitleType { - String get description { - switch (this) { - case SubtitleType.zhCN: - return '中文(中国)'; - case SubtitleType.aizh: - return '中文(自动翻译)'; - case SubtitleType.aien: - return '英语(自动生成)'; - case SubtitleType.zhHans: - return '中文(简体)'; - case SubtitleType.enUS: - return '英文(美国)'; - case SubtitleType.zhTW: - return '中文(繁体)'; - case SubtitleType.en: - return '英文'; - case SubtitleType.pt: - return '葡萄牙语'; - case SubtitleType.es: - return '西班牙语'; - } - } -} - -extension SubtitleIdExtension on SubtitleType { - String get id { - switch (this) { - case SubtitleType.zhCN: - return 'zh-CN'; - case SubtitleType.aizh: - return 'ai-zh'; - case SubtitleType.aien: - return 'ai-en'; - case SubtitleType.zhHans: - return 'zh-Hans'; - case SubtitleType.enUS: - return 'en-US'; - case SubtitleType.zhTW: - return 'zh-TW'; - case SubtitleType.en: - return 'en'; - case SubtitleType.pt: - return 'pt'; - case SubtitleType.es: - return 'es'; - } - } -} - -extension SubtitleCodeExtension on SubtitleType { - int get code { - switch (this) { - case SubtitleType.zhCN: - return 1; - case SubtitleType.aizh: - return 2; - case SubtitleType.aien: - return 3; - case SubtitleType.zhHans: - return 4; - case SubtitleType.enUS: - return 5; - case SubtitleType.zhTW: - return 6; - case SubtitleType.en: - return 7; - case SubtitleType.pt: - return 8; - case SubtitleType.es: - return 9; - } - } -} diff --git a/lib/models/video/subTitile/result.dart b/lib/models/video/subTitile/result.dart index d3e32e55..e137439f 100644 --- a/lib/models/video/subTitile/result.dart +++ b/lib/models/video/subTitile/result.dart @@ -1,6 +1,3 @@ -import 'package:get/get.dart'; -import '../../common/subtitle_type.dart'; - class SubTitlteModel { SubTitlteModel({ this.aid, @@ -78,11 +75,6 @@ class SubTitlteItemModel { aiType: json["ai_type"], aiStatus: json["ai_status"], title: json["lan_doc"], - code: SubtitleType.values - .firstWhereOrNull( - (element) => element.id.toString() == json["lan"]) - ?.index ?? - -1, content: '', body: [], ); diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index ea85a5b9..901c4014 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -446,15 +446,6 @@ class VideoDetailController extends GetxController } } - // 获取字幕内容 - // Future getSubtitleContent(String url) async { - // var res = await Request().get('https:$url'); - // subtitleContents.value = res.data['body'].map((e) { - // return SubTitileContentModel.fromJson(e); - // }).toList(); - // setSubtitleContent(); - // } - setSubtitleContent() { plPlayerController.subtitleContent.value = ''; plPlayerController.subtitles.value = subtitles; diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 1a1b1b74..50aac4cd 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -435,7 +435,8 @@ class VideoIntroController extends GetxController { videoDetailCtr.danmakuCid.value = cid; videoDetailCtr.cover.value = cover; videoDetailCtr.queryVideoUrl(); - videoDetailCtr.getSubtitle(); + videoDetailCtr.clearSubtitleContent(); + await videoDetailCtr.getSubtitle(); videoDetailCtr.setSubtitleContent(); // 重新请求评论 try { diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 5072377a..45a9684a 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -426,7 +426,12 @@ class _HeaderControlState extends State { /// 选择字幕 void showSubtitleDialog() async { int tempThemeValue = widget.controller!.subTitleCode.value; - int len = widget.videoDetailCtr!.subtitles.length; + final List subtitles = widget.videoDetailCtr!.subtitles; + int len = subtitles.length; + if (subtitles.firstWhereOrNull((element) => element.id == tempThemeValue) == + null) { + tempThemeValue = -1; + } showDialog( context: context, builder: (BuildContext context) { @@ -458,7 +463,7 @@ class _HeaderControlState extends State { ), ...widget.videoDetailCtr!.subtitles .map((e) => RadioListTile( - value: e.code, + value: e.id, title: Text(e.title), groupValue: tempThemeValue, onChanged: (value) { diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index a614d75d..a5de33fd 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -123,7 +123,7 @@ class PlPlayerController { PreferredSizeWidget? headerControl; PreferredSizeWidget? bottomControl; Widget? danmuWidget; - late RxList subtitles; + RxList subtitles = [].obs; String videoType = 'archive'; /// 数据加载监听 @@ -642,10 +642,6 @@ class PlPlayerController { const Duration(seconds: 1), () => videoPlayerServiceHandler.onPositionChange(event)); }), - - // onSubTitleOpenChanged.listen((bool event) { - // toggleSubtitle(event ? subTitleCode.value : -1); - // }) ], ); } @@ -1049,25 +1045,6 @@ class PlPlayerController { void toggleSubtitle(int code) { _subTitleOpen.value = code != -1; _subTitleCode.value = code; - // if (code == -1) { - // // 关闭字幕 - // _subTitleOpen.value = false; - // _subTitleCode.value = code; - // _videoPlayerController?.setSubtitleTrack(SubtitleTrack.no()); - // return; - // } - // final SubTitlteItemModel? subtitle = subtitles?.firstWhereOrNull( - // (element) => element.code == code, - // ); - // _subTitleOpen.value = true; - // _subTitleCode.value = code; - // _videoPlayerController?.setSubtitleTrack( - // SubtitleTrack.data( - // subtitle!.content!, - // title: subtitle.title, - // language: subtitle.lan, - // ), - // ); } void querySubtitleContent(double progress) { @@ -1079,7 +1056,7 @@ class PlPlayerController { return; } final SubTitlteItemModel? subtitle = subtitles.firstWhereOrNull( - (element) => element.code == subTitleCode.value, + (element) => element.id == subTitleCode.value, ); if (subtitle != null && subtitle.body!.isNotEmpty) { for (var content in subtitle.body!) { From de86dba39dee578a77c54c938397552cc962f56d Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 29 Jun 2024 18:47:04 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E6=B8=AF=E6=BE=B3=E5=8F=B0?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/constants.dart | 1 + lib/http/init.dart | 40 ++++++++++++++++++++--------- lib/pages/setting/play_setting.dart | 9 +++++++ lib/utils/storage.dart | 2 ++ 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/lib/http/constants.dart b/lib/http/constants.dart index 3d749ee8..cf6e00f2 100644 --- a/lib/http/constants.dart +++ b/lib/http/constants.dart @@ -5,6 +5,7 @@ class HttpString { static const String appBaseUrl = 'https://app.bilibili.com'; static const String liveBaseUrl = 'https://api.live.bilibili.com'; static const String passBaseUrl = 'https://passport.bilibili.com'; + static const String bangumiBaseUrl = 'https://bili.meark.me'; static const List validateStatusCodes = [ 302, 304, diff --git a/lib/http/init.dart b/lib/http/init.dart index a0b36369..cb9d6f39 100644 --- a/lib/http/init.dart +++ b/lib/http/init.dart @@ -27,11 +27,13 @@ class Request { late bool enableSystemProxy; late String systemProxyHost; late String systemProxyPort; - static final RegExp spmPrefixExp = RegExp(r''); + static final RegExp spmPrefixExp = + RegExp(r''); /// 设置cookie static setCookie() async { Box userInfoCache = GStrorage.userInfo; + Box setting = GStrorage.setting; final String cookiePath = await Utils.getCookiePath(); final PersistCookieJar cookieJar = PersistCookieJar( ignoreExpires: true, @@ -54,7 +56,11 @@ class Request { } } setOptionsHeaders(userInfo, userInfo != null && userInfo.mid != null); - + String baseUrlType = 'default'; + if (setting.get(SettingBoxKey.enableGATMode, defaultValue: false)) { + baseUrlType = 'bangumi'; + } + setBaseUrl(type: baseUrlType); try { await buvidActivate(); } catch (e) { @@ -95,11 +101,10 @@ class Request { String spmPrefix = spmPrefixExp.firstMatch(html.data)!.group(1)!; Random rand = Random(); String rand_png_end = base64.encode( - List.generate(32, (_) => rand.nextInt(256)) + - List.filled(4, 0) + - [73, 69, 78, 68] + - List.generate(4, (_) => rand.nextInt(256)) - ); + List.generate(32, (_) => rand.nextInt(256)) + + List.filled(4, 0) + + [73, 69, 78, 68] + + List.generate(4, (_) => rand.nextInt(256))); String jsonData = json.encode({ '3064': 1, @@ -110,11 +115,9 @@ class Request { }, }); - await Request().post( - Api.activateBuvidApi, - data: {'payload': jsonData}, - options: Options(contentType: 'application/json') - ); + await Request().post(Api.activateBuvidApi, + data: {'payload': jsonData}, + options: Options(contentType: 'application/json')); } /* @@ -294,4 +297,17 @@ class Request { } return headerUa; } + + static setBaseUrl({String type = 'default'}) { + switch (type) { + case 'default': + dio.options.baseUrl = HttpString.apiBaseUrl; + break; + case 'bangumi': + dio.options.baseUrl = HttpString.bangumiBaseUrl; + break; + default: + dio.options.baseUrl = HttpString.apiBaseUrl; + } + } } diff --git a/lib/pages/setting/play_setting.dart b/lib/pages/setting/play_setting.dart index 0f7dcdc3..cb8a3996 100644 --- a/lib/pages/setting/play_setting.dart +++ b/lib/pages/setting/play_setting.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; +import 'package:pilipala/http/init.dart'; import 'package:pilipala/models/video/play/ao_output.dart'; import 'package:pilipala/models/video/play/quality.dart'; import 'package:pilipala/pages/setting/widgets/select_dialog.dart'; @@ -163,6 +164,14 @@ class _PlaySettingState extends State { callFn: (bool val) { GlobalData().enablePlayerControlAnimation = val; }), + SetSwitchItem( + title: '港澳台模式', + setKey: SettingBoxKey.enableGATMode, + defaultVal: false, + callFn: (bool val) { + Request.setBaseUrl(type: val ? 'bangumi' : 'default'); + }, + ), ListTile( dense: false, title: Text('默认视频画质', style: titleStyle), diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index bf9074e3..dca5a158 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -104,6 +104,8 @@ class SettingBoxKey { enablePlayerControlAnimation = 'enablePlayerControlAnimation', // 默认音频输出方式 defaultAoOutput = 'defaultAoOutput', + // 港澳台模式 + enableGATMode = 'enableGATMode', // youtube 双击快进快退 enableQuickDouble = 'enableQuickDouble', From 9f1b74b7e23f2b09c0c506dfbb5dd26a8217b506 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 30 Jun 2024 00:28:26 +0800 Subject: [PATCH 3/5] mod --- lib/pages/video/detail/reply/view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index be1bd331..4fe69481 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -188,7 +188,7 @@ class _VideoReplyPanelState extends State if (snapshot.connectionState == ConnectionState.done) { var data = snapshot.data; if (_videoReplyController.replyList.isNotEmpty || - (data && data['status'])) { + (data != null && data['status'])) { // 请求成功 return Obx( () => _videoReplyController.isLoadingMore && From a19129c59615c5eda9750ffd0d881528d1054d66 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 30 Jun 2024 13:02:50 +0800 Subject: [PATCH 4/5] =?UTF-8?q?opt:=20=E5=AD=97=E5=B9=95=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E6=98=BE=E9=9A=90=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/controller.dart | 46 +++++++++++-------- .../video/detail/widgets/header_control.dart | 17 ++++--- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 901c4014..c5e37be1 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -141,13 +141,7 @@ class VideoDetailController extends GetxController if (Platform.isAndroid) { floating = Floating(); } - headerControl = HeaderControl( - controller: plPlayerController, - videoDetailCtr: this, - floating: floating, - bvid: bvid, - videoType: videoType, - ); + // CDN优化 enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true); // 预设的画质 @@ -158,7 +152,18 @@ class VideoDetailController extends GetxController defaultAudioQa = setting.get(SettingBoxKey.defaultAudioQa, defaultValue: AudioQuality.hiRes.code); oid.value = IdUtils.bv2av(Get.parameters['bvid']!); - getSubtitle(); + getSubtitle().then( + (subtitles) { + headerControl = HeaderControl( + controller: plPlayerController, + videoDetailCtr: this, + floating: floating, + bvid: bvid, + videoType: videoType, + showSubtitleBtn: subtitles.isNotEmpty, + ); + }, + ); } showReplyReplyPanel(oid, fRpid, firstFloor) { @@ -432,17 +437,22 @@ class VideoDetailController extends GetxController if (result['status']) { if (result['data'].subtitles.isNotEmpty) { subtitles = result['data'].subtitles; - if (subtitles.isNotEmpty) { - for (var i in subtitles) { - final Map res = await VideoHttp.getSubtitleContent( - i.subtitleUrl, - ); - i.content = res['content']; - i.body = res['body']; - } - } + getDanmaku(subtitles); + } + return subtitles; + } + } + + // 获取弹幕 + Future getDanmaku(List subtitles) async { + if (subtitles.isNotEmpty) { + for (var i in subtitles) { + final Map res = await VideoHttp.getSubtitleContent( + i.subtitleUrl, + ); + i.content = res['content']; + i.body = res['body']; } - return result['data']; } } diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 45a9684a..f3b9549a 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -30,6 +30,7 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget { this.floating, this.bvid, this.videoType, + this.showSubtitleBtn, super.key, }); final PlPlayerController? controller; @@ -37,6 +38,7 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget { final Floating? floating; final String? bvid; final SearchType? videoType; + final bool? showSubtitleBtn; @override State createState() => _HeaderControlState(); @@ -1327,14 +1329,15 @@ class _HeaderControlState extends State { ], /// 字幕 - ComBtn( - icon: const Icon( - Icons.closed_caption_off, - size: 22, - color: Colors.white, + if (widget.showSubtitleBtn!) + ComBtn( + icon: const Icon( + Icons.closed_caption_off, + size: 22, + color: Colors.white, + ), + fuc: () => showSubtitleDialog(), ), - fuc: () => showSubtitleDialog(), - ), SizedBox(width: buttonSpace), Obx( () => SizedBox( From c7ba9dc97bd9adb0042ded14858638ede7050ae9 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 30 Jun 2024 22:01:12 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=E7=B3=BB=E7=BB=9F=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 4 + lib/http/constants.dart | 1 + lib/http/msg.dart | 27 +++++- lib/models/msg/system.dart | 77 +++++++++++++++++ lib/pages/message/system/controller.dart | 14 ++- lib/pages/message/system/view.dart | 104 +++++++++++++++++++++++ lib/pages/whisper/view.dart | 2 +- 7 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 lib/models/msg/system.dart diff --git a/lib/http/api.dart b/lib/http/api.dart index f20b8bcf..46bbb6ac 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -548,4 +548,8 @@ class Api { /// 收到的赞 static const String messageLikeAPi = '/x/msgfeed/like'; + + /// 系统通知 + static const String messageSystemAPi = + '${HttpString.messageBaseUrl}/x/sys-msg/query_unified_notify'; } diff --git a/lib/http/constants.dart b/lib/http/constants.dart index 3d749ee8..cad413ef 100644 --- a/lib/http/constants.dart +++ b/lib/http/constants.dart @@ -5,6 +5,7 @@ class HttpString { static const String appBaseUrl = 'https://app.bilibili.com'; static const String liveBaseUrl = 'https://api.live.bilibili.com'; static const String passBaseUrl = 'https://passport.bilibili.com'; + static const String messageBaseUrl = 'https://message.bilibili.com'; static const List validateStatusCodes = [ 302, 304, diff --git a/lib/http/msg.dart b/lib/http/msg.dart index 7c168230..86789fd1 100644 --- a/lib/http/msg.dart +++ b/lib/http/msg.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:dio/dio.dart'; import 'package:pilipala/models/msg/like.dart'; import 'package:pilipala/models/msg/reply.dart'; +import 'package:pilipala/models/msg/system.dart'; import '../models/msg/account.dart'; import '../models/msg/session.dart'; import '../utils/wbi_sign.dart'; @@ -149,7 +150,7 @@ class MsgHttp { 'msg[msg_status]': 0, 'msg[content]': jsonEncode(content), 'msg[timestamp]': DateTime.now().millisecondsSinceEpoch ~/ 1000, - 'msg[new_face_version]': 0, + 'msg[new_face_version]': 1, 'msg[dev_id]': getDevId(), 'from_firework': 0, 'build': 0, @@ -287,4 +288,28 @@ class MsgHttp { return {'status': false, 'date': [], 'msg': res.data['message']}; } } + + static Future messageSystem() async { + var res = await Request().get(Api.messageSystemAPi, data: { + 'csrf': await Request.getCsrf(), + 'page_size': 20, + 'build': 0, + 'mobi_app': 'web', + }); + if (res.data['code'] == 0) { + try { + print(res.data['data']['system_notify_list']); + return { + 'status': true, + 'data': res.data['data']['system_notify_list'] + .map((e) => MessageSystemModel.fromJson(e)) + .toList(), + }; + } catch (err) { + return {'status': false, 'date': [], 'msg': err.toString()}; + } + } else { + return {'status': false, 'date': [], 'msg': res.data['message']}; + } + } } diff --git a/lib/models/msg/system.dart b/lib/models/msg/system.dart new file mode 100644 index 00000000..20427707 --- /dev/null +++ b/lib/models/msg/system.dart @@ -0,0 +1,77 @@ +import 'dart:convert'; + +class MessageSystemModel { + int? id; + int? cursor; + int? type; + String? title; + Map? content; + Source? source; + String? timeAt; + int? cardType; + String? cardBrief; + String? cardMsgBrief; + String? cardCover; + String? cardStoryTitle; + String? cardLink; + String? mc; + int? isStation; + int? isSend; + int? notifyCursor; + + MessageSystemModel({ + this.id, + this.cursor, + this.type, + this.title, + this.content, + this.source, + this.timeAt, + this.cardType, + this.cardBrief, + this.cardMsgBrief, + this.cardCover, + this.cardStoryTitle, + this.cardLink, + this.mc, + this.isStation, + this.isSend, + this.notifyCursor, + }); + + factory MessageSystemModel.fromJson(Map jsons) => + MessageSystemModel( + id: jsons["id"], + cursor: jsons["cursor"], + type: jsons["type"], + title: jsons["title"], + content: json.decode(jsons["content"]), + source: Source.fromJson(jsons["source"]), + timeAt: jsons["time_at"], + cardType: jsons["card_type"], + cardBrief: jsons["card_brief"], + cardMsgBrief: jsons["card_msg_brief"], + cardCover: jsons["card_cover"], + cardStoryTitle: jsons["card_story_title"], + cardLink: jsons["card_link"], + mc: jsons["mc"], + isStation: jsons["is_station"], + isSend: jsons["is_send"], + notifyCursor: jsons["notify_cursor"], + ); +} + +class Source { + String? name; + String? logo; + + Source({ + this.name, + this.logo, + }); + + factory Source.fromJson(Map json) => Source( + name: json["name"], + logo: json["logo"], + ); +} diff --git a/lib/pages/message/system/controller.dart b/lib/pages/message/system/controller.dart index ad28af56..bf31f6bc 100644 --- a/lib/pages/message/system/controller.dart +++ b/lib/pages/message/system/controller.dart @@ -1,3 +1,15 @@ import 'package:get/get.dart'; +import 'package:pilipala/http/msg.dart'; +import 'package:pilipala/models/msg/system.dart'; -class MessageSystemController extends GetxController {} +class MessageSystemController extends GetxController { + RxList systemItems = [].obs; + + Future queryMessageSystem({String type = 'init'}) async { + var res = await MsgHttp.messageSystem(); + if (res['status']) { + systemItems.addAll(res['data']); + } + return res; + } +} diff --git a/lib/pages/message/system/view.dart b/lib/pages/message/system/view.dart index da0f1219..f7b94e5a 100644 --- a/lib/pages/message/system/view.dart +++ b/lib/pages/message/system/view.dart @@ -1,4 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/common/widgets/http_error.dart'; +import 'package:pilipala/models/msg/system.dart'; +import 'controller.dart'; class MessageSystemPage extends StatefulWidget { const MessageSystemPage({super.key}); @@ -8,12 +12,112 @@ class MessageSystemPage extends StatefulWidget { } class _MessageSystemPageState extends State { + final MessageSystemController _messageSystemCtr = + Get.put(MessageSystemController()); + late Future _futureBuilderFuture; + final ScrollController scrollController = ScrollController(); + + @override + void initState() { + super.initState(); + _futureBuilderFuture = _messageSystemCtr.queryMessageSystem(); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('系统通知'), ), + body: RefreshIndicator( + onRefresh: () async { + await _messageSystemCtr.queryMessageSystem(); + }, + child: FutureBuilder( + future: _futureBuilderFuture, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.data == null) { + return const SizedBox(); + } + if (snapshot.data['status']) { + final systemItems = _messageSystemCtr.systemItems; + print(systemItems.length); + return Obx( + () => ListView.separated( + controller: scrollController, + itemBuilder: (context, index) => SystemItem( + item: systemItems[index], + index: index, + messageSystemCtr: _messageSystemCtr, + ), + itemCount: systemItems.length, + separatorBuilder: (BuildContext context, int index) { + return Divider( + indent: 14, + endIndent: 14, + height: 1, + color: Colors.grey.withOpacity(0.1), + ); + }, + ), + ); + } else { + // 请求错误 + return CustomScrollView( + slivers: [ + HttpError( + errMsg: snapshot.data['msg'], + fn: () { + setState(() { + _futureBuilderFuture = + _messageSystemCtr.queryMessageSystem(); + }); + }, + ) + ], + ); + } + } else { + return const SizedBox(); + } + }, + ), + ), + ); + } +} + +class SystemItem extends StatelessWidget { + final MessageSystemModel item; + final int index; + final MessageSystemController messageSystemCtr; + + const SystemItem( + {super.key, + required this.item, + required this.index, + required this.messageSystemCtr}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.fromLTRB(14, 14, 14, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(item.title!, + style: + const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), + const SizedBox(height: 4), + Text( + item.timeAt!, + style: TextStyle(color: Theme.of(context).colorScheme.outline), + ), + const SizedBox(height: 6), + Text(item.content!['web']), + ], + ), ); } } diff --git a/lib/pages/whisper/view.dart b/lib/pages/whisper/view.dart index 9436e2be..1814c274 100644 --- a/lib/pages/whisper/view.dart +++ b/lib/pages/whisper/view.dart @@ -71,7 +71,7 @@ class _WhisperPageState extends State { ..._whisperController.noticesList.map((element) { return InkWell( onTap: () { - if (['/messageAt', '/messageSystem'] + if (['/messageAt'] .contains(element['path'])) { SmartDialog.showToast('功能开发中'); return;