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 42819d7d..ff49b314 100644
--- a/lib/http/api.dart
+++ b/lib/http/api.dart
@@ -578,4 +578,7 @@ class Api {
/// 稍后再看&收藏夹视频列表
static const String mediaList = '/x/v2/medialist/resource/list';
+
+ ///
+ static const String getViewInfo = '/x/article/viewinfo';
}
diff --git a/lib/http/read.dart b/lib/http/read.dart
index cc522505..68e72e59 100644
--- a/lib/http/read.dart
+++ b/lib/http/read.dart
@@ -1,7 +1,9 @@
import 'dart:convert';
import 'package:html/parser.dart';
import 'package:pilipala/models/read/opus.dart';
-import 'init.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) {
@@ -57,4 +59,58 @@ class ReadHttp {
'cvId': cvId,
};
}
+
+ // 解析专栏 cv格式
+ static Future parseArticleCv({required String id}) async {
+ var res = await Request().get(
+ 'https://www.bilibili.com/read/cv$id',
+ extra: {'ua': 'pc'},
+ );
+ String scriptContent =
+ extractScriptContents(parse(res.data).body!.outerHtml)[0];
+ int startIndex = scriptContent.indexOf('{');
+ int endIndex = scriptContent.lastIndexOf('};');
+ String jsonContent = scriptContent.substring(startIndex, endIndex + 1);
+ // 解析JSON字符串为Map
+ Map jsonData = json.decode(jsonContent);
+ return {
+ 'status': true,
+ 'data': ReadDataModel.fromJson(jsonData),
+ };
+ }
+
+ //
+ static Future getViewInfo({required String id}) async {
+ Map params = await WbiSign().makSign({
+ 'id': id,
+ 'mobi_app': 'pc',
+ 'from': 'web',
+ 'gaia_source': 'main_web',
+ 'web_location': 333.976,
+ });
+ var res = await Request().get(
+ Api.getViewInfo,
+ data: {
+ 'id': id,
+ 'mobi_app': 'pc',
+ 'from': 'web',
+ 'gaia_source': 'main_web',
+ 'web_location': 333.976,
+ 'w_rid': params['w_rid'],
+ 'wts': params['wts'],
+ },
+ );
+ if (res.data['code'] == 0) {
+ return {
+ 'status': true,
+ 'data': res.data['data'],
+ };
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
}
diff --git a/lib/http/search.dart b/lib/http/search.dart
index 403e6a37..00e51497 100644
--- a/lib/http/search.dart
+++ b/lib/http/search.dart
@@ -143,7 +143,11 @@ class SearchHttp {
}
final dynamic res =
await Request().get(Api.ab2c, data: {...data});
- return res.data['data'].first['cid'];
+ if (res.data['code'] == 0) {
+ return res.data['data'].first['cid'];
+ } else {
+ return -1;
+ }
}
static Future