diff --git a/lib/common/widgets/html_render.dart b/lib/common/widgets/html_render.dart
index bf58d78c..b2aa75ff 100644
--- a/lib/common/widgets/html_render.dart
+++ b/lib/common/widgets/html_render.dart
@@ -1,7 +1,9 @@
+import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
-import 'package:get/get.dart';
-import 'network_img_layer.dart';
+import 'package:pilipala/plugin/pl_gallery/hero_dialog_route.dart';
+import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart';
+import 'package:pilipala/utils/highlight.dart';
// ignore: must_be_immutable
class HtmlRender extends StatelessWidget {
@@ -22,6 +24,20 @@ class HtmlRender extends StatelessWidget {
data: htmlContent,
onLinkTap: (String? url, Map buildContext, attributes) {},
extensions: [
+ TagExtension(
+ tagsToExtend: {'pre'},
+ builder: (ExtensionContext extensionContext) {
+ final Map attributes = extensionContext.attributes;
+ final String lang = attributes['data-lang'] as String;
+ final String code = attributes['codecontent'] as String;
+ List selectedLanguages = [lang.split('@').first];
+ TextSpan? result = highlightExistingText(code, selectedLanguages);
+ if (result == null) {
+ return const Center(child: Text('代码块渲染失败'));
+ }
+ return SelectableText.rich(result);
+ },
+ ),
TagExtension(
tagsToExtend: {'img'},
builder: (ExtensionContext extensionContext) {
@@ -44,20 +60,52 @@ class HtmlRender extends StatelessWidget {
if (isMall) {
return const SizedBox();
}
- // bool inTable =
- // extensionContext.element!.previousElementSibling == null ||
- // extensionContext.element!.nextElementSibling == null;
- // imgUrl = Utils().imageUrl(imgUrl!);
- // return Image.network(
- // imgUrl,
- // width: isEmote ? 22 : null,
- // height: isEmote ? 22 : null,
- // );
- return NetworkImgLayer(
- width: isEmote ? 22 : Get.size.width - 24,
- height: isEmote ? 22 : 200,
- src: imgUrl,
+ return InkWell(
+ onTap: () {
+ Navigator.of(context).push(
+ HeroDialogRoute(
+ builder: (BuildContext context) =>
+ InteractiveviewerGallery(
+ sources: imgList ?? [imgUrl],
+ initIndex: imgList?.indexOf(imgUrl) ?? 0,
+ itemBuilder: (
+ BuildContext context,
+ int index,
+ bool isFocus,
+ bool enablePageView,
+ ) {
+ return GestureDetector(
+ behavior: HitTestBehavior.opaque,
+ onTap: () {
+ if (enablePageView) {
+ Navigator.of(context).pop();
+ }
+ },
+ child: Center(
+ child: Hero(
+ tag: imgList?[index] ?? imgUrl,
+ child: CachedNetworkImage(
+ fadeInDuration:
+ const Duration(milliseconds: 0),
+ imageUrl: imgList?[index] ?? imgUrl,
+ fit: BoxFit.contain,
+ ),
+ ),
+ ),
+ );
+ },
+ onPageChanged: (int pageIndex) {},
+ ),
+ ),
+ );
+ },
+ child: CachedNetworkImage(imageUrl: imgUrl),
);
+ // return NetworkImgLayer(
+ // width: isEmote ? 22 : Get.size.width - 24,
+ // height: isEmote ? 22 : 200,
+ // src: imgUrl,
+ // );
} catch (err) {
return const SizedBox();
}
@@ -66,7 +114,7 @@ class HtmlRender extends StatelessWidget {
],
style: {
'html': Style(
- fontSize: FontSize.medium,
+ fontSize: FontSize.large,
lineHeight: LineHeight.percent(140),
),
'body': Style(margin: Margins.zero, padding: HtmlPaddings.zero),
@@ -78,7 +126,7 @@ class HtmlRender extends StatelessWidget {
margin: Margins.only(bottom: 10),
),
'span': Style(
- fontSize: FontSize.medium,
+ fontSize: FontSize.large,
height: Height(1.65),
),
'div': Style(height: Height.auto()),
diff --git a/lib/common/widgets/video_card_v.dart b/lib/common/widgets/video_card_v.dart
index 7a9ef39c..378c9f75 100644
--- a/lib/common/widgets/video_card_v.dart
+++ b/lib/common/widgets/video_card_v.dart
@@ -60,17 +60,13 @@ class VideoCardV extends StatelessWidget {
// 动态
case 'picture':
try {
- String dynamicType = 'picture';
String uri = videoItem.uri;
- String id = '';
if (videoItem.uri.startsWith('bilibili://article/')) {
// https://www.bilibili.com/read/cv27063554
- dynamicType = 'read';
RegExp regex = RegExp(r'\d+');
Match match = regex.firstMatch(videoItem.uri)!;
String matchedNumber = match.group(0)!;
videoItem.param = int.parse(matchedNumber);
- id = 'cv${videoItem.param}';
}
if (uri.startsWith('http')) {
String path = Uri.parse(uri).path;
@@ -88,11 +84,10 @@ class VideoCardV extends StatelessWidget {
return;
}
}
- Get.toNamed('/htmlRender', parameters: {
- 'url': uri,
+ Get.toNamed('/read', parameters: {
'title': videoItem.title,
- 'id': id,
- 'dynamicType': dynamicType
+ 'id': videoItem.param,
+ 'articleType': 'read'
});
} catch (err) {
SmartDialog.showToast(err.toString());
diff --git a/lib/http/api.dart b/lib/http/api.dart
index 70488fa3..df0b9c85 100644
--- a/lib/http/api.dart
+++ b/lib/http/api.dart
@@ -555,6 +555,10 @@ class Api {
static const String messageSystemAPi =
'${HttpString.messageBaseUrl}/x/sys-msg/query_unified_notify';
+ /// 系统通知 个人
+ static const String userMessageSystemAPi =
+ '${HttpString.messageBaseUrl}/x/sys-msg/query_user_notify';
+
/// 系统通知标记已读
static const String systemMarkRead =
'${HttpString.messageBaseUrl}/x/sys-msg/update_cursor';
@@ -575,4 +579,17 @@ class Api {
/// 我的关注 - 正在直播
static const String getFollowingLive =
'${HttpString.liveBaseUrl}/xlive/web-ucenter/user/following';
+
+ /// 稍后再看&收藏夹视频列表
+ static const String mediaList = '/x/v2/medialist/resource/list';
+
+ /// 用户专栏
+ static const String opusList = '/x/polymer/web-dynamic/v1/opus/feed/space';
+
+ ///
+ static const String getViewInfo = '/x/article/viewinfo';
+
+ /// 直播间记录
+ static const String liveRoomEntry =
+ '${HttpString.liveBaseUrl}/xlive/web-room/v1/index/roomEntryAction';
}
diff --git a/lib/http/live.dart b/lib/http/live.dart
index f5fd2a43..1405e9ea 100644
--- a/lib/http/live.dart
+++ b/lib/http/live.dart
@@ -142,4 +142,15 @@ class LiveHttp {
};
}
}
+
+ // 直播历史记录
+ static Future liveRoomEntry({required int roomId}) async {
+ await Request().post(Api.liveRoomEntry, queryParameters: {
+ 'room_id': roomId,
+ 'platform': 'pc',
+ 'csrf_token': await Request.getCsrf(),
+ 'csrf': await Request.getCsrf(),
+ 'visit_id': '',
+ });
+ }
}
diff --git a/lib/http/member.dart b/lib/http/member.dart
index e87aa42e..459d6747 100644
--- a/lib/http/member.dart
+++ b/lib/http/member.dart
@@ -1,5 +1,8 @@
+import 'dart:convert';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:hive/hive.dart';
+import 'package:html/parser.dart';
+import 'package:pilipala/models/member/article.dart';
import 'package:pilipala/models/member/like.dart';
import '../common/constants.dart';
import '../models/dynamics/result.dart';
@@ -556,4 +559,60 @@ class MemberHttp {
};
}
}
+
+ static Future getWWebid({required int mid}) async {
+ var res = await Request().get('https://space.bilibili.com/$mid/article');
+ String? headContent = parse(res.data).head?.outerHtml;
+ final regex = RegExp(
+ r'');
+ if (headContent != null) {
+ final match = regex.firstMatch(headContent);
+ if (match != null && match.groupCount >= 1) {
+ final content = match.group(1);
+ String decodedString = Uri.decodeComponent(content!);
+ Map map = jsonDecode(decodedString);
+ return {'status': true, 'data': map['access_id']};
+ } else {
+ return {'status': false, 'data': '请检查登录状态'};
+ }
+ }
+ return {'status': false, 'data': '请检查登录状态'};
+ }
+
+ // 获取用户专栏
+ static Future getMemberArticle({
+ required int mid,
+ required int pn,
+ required String wWebid,
+ String? offset,
+ }) async {
+ Map params = await WbiSign().makSign({
+ 'host_mid': mid,
+ 'page': pn,
+ 'offset': offset,
+ 'web_location': 333.999,
+ 'w_webid': wWebid,
+ });
+ var res = await Request().get(Api.opusList, data: {
+ 'host_mid': mid,
+ 'page': pn,
+ 'offset': offset,
+ 'web_location': 333.999,
+ 'w_webid': wWebid,
+ 'w_rid': params['w_rid'],
+ 'wts': params['wts'],
+ });
+ if (res.data['code'] == 0) {
+ return {
+ 'status': true,
+ 'data': MemberArticleDataModel.fromJson(res.data['data'])
+ };
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'] ?? '请求异常',
+ };
+ }
+ }
}
diff --git a/lib/http/msg.dart b/lib/http/msg.dart
index 2de9cd49..869b5a28 100644
--- a/lib/http/msg.dart
+++ b/lib/http/msg.dart
@@ -330,4 +330,27 @@ class MsgHttp {
};
}
}
+
+ static Future messageSystemAccount() async {
+ var res = await Request().get(Api.userMessageSystemAPi, data: {
+ 'csrf': await Request.getCsrf(),
+ 'page_size': 20,
+ 'build': 0,
+ 'mobi_app': 'web',
+ });
+ if (res.data['code'] == 0) {
+ try {
+ 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/http/read.dart b/lib/http/read.dart
new file mode 100644
index 00000000..68e72e59
--- /dev/null
+++ b/lib/http/read.dart
@@ -0,0 +1,116 @@
+import 'dart:convert';
+import 'package:html/parser.dart';
+import 'package:pilipala/models/read/opus.dart';
+import 'package:pilipala/models/read/read.dart';
+import 'package:pilipala/utils/wbi_sign.dart';
+import 'index.dart';
+
+class ReadHttp {
+ static List extractScriptContents(String htmlContent) {
+ RegExp scriptRegExp = RegExp(r'