This commit is contained in:
2026-03-07 17:24:59 +08:00
parent 4418ebecac
commit b0ec8ab4bd
417 changed files with 42546 additions and 2 deletions

View File

@@ -0,0 +1,398 @@
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dmzj/app/app_color.dart';
import 'package:flutter_dmzj/app/app_constant.dart';
import 'package:flutter_dmzj/app/app_style.dart';
import 'package:flutter_dmzj/app/controller/base_controller.dart';
import 'package:flutter_dmzj/app/dialog_utils.dart';
import 'package:flutter_dmzj/app/log.dart';
import 'package:flutter_dmzj/app/utils.dart';
import 'package:flutter_dmzj/requests/news_request.dart';
import 'package:flutter_dmzj/routes/app_navigator.dart';
import 'package:flutter_dmzj/services/app_settings_service.dart';
import 'package:flutter_dmzj/services/db_service.dart';
import 'package:flutter_dmzj/services/user_service.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:universal_html/html.dart' as html;
import 'package:universal_html/parsing.dart';
import 'package:webview_flutter/webview_flutter.dart';
class NewsDetailController extends BaseController {
final String newsUrl;
final String title;
final int id;
final NewsRequest request = NewsRequest();
AppSettingsService get settings => AppSettingsService.instance;
NewsDetailController(
{required this.newsUrl, this.title = "资讯详情", required this.id}) {
newsTitle.value = title;
if (id == 0) {
newsId = int.tryParse(
RegExp(r"/(\d+).html").firstMatch(newsUrl)?.group(1) ?? "0") ??
0;
} else {
newsId = id;
}
}
WebViewController? webViewController =
(Platform.isAndroid || Platform.isIOS) ? WebViewController() : null;
/// 评论数
var commentAmount = 0.obs;
/// 点赞数
var moodAmount = 0.obs;
/// 是否点过赞
var liked = false.obs;
/// 是否已经收藏
var collected = false.obs;
var newsId = 0;
var newsTitle = "资讯详情".obs;
var htmlContent = "".obs;
var author = "".obs;
var photo = "".obs;
var src = "".obs;
var time = "".obs;
var images = <String>[];
@override
void onInit() {
liked.value = DBService.instance.newsLikeBox.containsKey(newsId);
if (Platform.isAndroid || Platform.isIOS) {
initWebView();
} else {
loadHtml();
}
// loadStat();
// checkCollected();
super.onInit();
}
var currentUrl = "";
void initWebView() {
webViewController!.setJavaScriptMode(JavaScriptMode.unrestricted);
webViewController!.setBackgroundColor(
Get.isDarkMode ? Colors.black : AppColor.backgroundColor);
webViewController!.setNavigationDelegate(
NavigationDelegate(
onPageStarted: (String url) {
pageLoadding.value = true;
},
onPageFinished: (String url) async {
try {
await setFontSize();
//防止亮瞎24K钛合金狗眼
if (Get.isDarkMode) {
await webViewController!.runJavaScript("""
document.body.style.background="#000000";
document.getElementsByClassName("min_box")[0].style.background="#000000";
document.getElementsByClassName("news_box")[0].style.color="#f1f2f6";
document.getElementsByClassName("min_box_tit")[0].style.color="#fff";
""");
}
//加载前5张图片
//当Web没有滚动条时图片不会加载这里手动给他加载出来
await webViewController!.runJavaScript("""
\$('.news_box img:lt(5)').each(function () {
\$(this).lazyload({
effect: "fadeIn"
});
});""");
//读取全部的图片
var imagesResult =
await webViewController?.runJavaScriptReturningResult('''
function getImgLinks(){
var imgLinks = [];
\$('img').each(function() {
var src = \$(this).attr('data-original');
if (src && src.startsWith('https://images')) {
imgLinks.push(src);
}
});
console.log(imgLinks);
return ${Platform.isIOS ? "JSON.stringify(imgLinks)" : "imgLinks"};
}
getImgLinks();
''');
if (imagesResult != null && imagesResult != "null") {
List list = json.decode(imagesResult.toString());
images = list.map((e) => e.toString()).toList();
}
} finally {
pageLoadding.value = false;
}
},
onWebResourceError: (WebResourceError error) {},
onNavigationRequest: (NavigationRequest request) async {
var result = await onTapUrl(request.url);
return result
? NavigationDecision.prevent
: NavigationDecision.navigate;
},
),
);
Log.d(newsUrl);
currentUrl = "https://v3api.zaimanhua.com/v3/article/show/$newsId.html";
webViewController!.loadRequest(Uri.parse(currentUrl));
}
void loadHtml() async {
try {
pageError.value = false;
pageLoadding.value = true;
var result = await Dio().get(
newsUrl,
options: Options(
responseType: ResponseType.plain,
),
);
final htmlDocument = parseHtmlDocument(result.data);
var news = htmlDocument.documentElement!.querySelector('.news_box');
htmlContent.value = news!.innerHtml ?? "";
author.value =
htmlDocument.documentElement?.querySelector('.txt1')?.innerText ?? "";
src.value =
htmlDocument.documentElement?.querySelector('.txt2')?.innerText ?? "";
time.value =
htmlDocument.documentElement?.querySelector('.txt3')?.innerText ?? "";
var imgList = htmlDocument.documentElement?.querySelectorAll('img');
var imagesList = <String>[];
for (html.Element img in imgList ?? []) {
var imgSrc = img.getAttribute("data-original");
if (imgSrc != null) {
imagesList.add(imgSrc);
}
}
images = imagesList;
} catch (e) {
pageError.value = true;
errorMsg.value = e.toString();
} finally {
pageLoadding.value = false;
}
}
void loadStat() async {
try {
var result = await request.stat(newsId);
commentAmount.value = result.commentAmount;
moodAmount.value = result.moodAmount;
newsTitle.value = result.title;
} catch (e) {
SmartDialog.showToast(e.toString());
SmartDialog.showToast("读取新闻数据失败:$e");
}
}
void checkCollected() async {
if (!UserService.instance.logined.value) {
return;
}
try {
collected.value = await request.checkCollect(newsId);
} catch (e) {
Log.logPrint(e);
SmartDialog.showToast("检查用户收藏状态失败:$e");
}
}
void refershContent() {
webViewController!.reload();
}
void collect() async {
if (!await UserService.instance.login()) {
return;
}
try {
SmartDialog.showLoading();
await (collected.value
? request.delCollect(newsId)
: request.collect(newsId));
collected.value = !collected.value;
} catch (e) {
Log.logPrint(e);
SmartDialog.showToast(e.toString());
} finally {
SmartDialog.dismiss(status: SmartStatus.loading);
}
}
void like() async {
if (liked.value) {
SmartDialog.showToast("已经点过赞了");
return;
}
try {
SmartDialog.showLoading();
await request.like(newsId);
liked.value = true;
moodAmount.value += 1;
DBService.instance.newsLikeBox.put(newsId, true);
} catch (e) {
SmartDialog.showToast(e.toString());
} finally {
SmartDialog.dismiss(status: SmartStatus.loading);
}
}
void share() {
Utils.share(newsUrl, content: title);
}
void comment() async {
AppNavigator.toComment(objId: newsId, type: AppConstant.kTypeNews);
}
void photoView() {
DialogUtils.showImageViewer(0, images);
}
void showImageView(String imgSrc) {
if (imgSrc.isEmpty) {
return;
}
if (images.contains(imgSrc)) {
DialogUtils.showImageViewer(
images.indexOf(imgSrc),
images,
);
} else {
DialogUtils.showImageViewer(0, [imgSrc]);
}
}
Future<bool> onTapUrl(url) async {
//iOS处理
if (url == currentUrl) {
return false;
}
var uri = Uri.parse(url);
Log.d(url);
if (uri.scheme == "dmzjimage") {
//打开图片
showImageView(uri.queryParameters['src'].toString());
return true;
} else if (uri.scheme == "dmzjandroid") {
var id = int.tryParse(uri.queryParameters["id"].toString()) ?? 0;
if (uri.path == "/cartoon_description") {
AppNavigator.toComicDetail(id);
} else {
AppNavigator.toNovelDetail(id);
}
return true;
} else if (uri.scheme == "https" || uri.scheme == "http") {
if (uri.path.contains("article/")) {
AppNavigator.toNewsDetail(url: url);
} else {
AppNavigator.toWebView(url);
}
return true;
} else {
SmartDialog.showToast("无法打开链接:$url");
return true;
}
}
void showSettings() {
AppNavigator.showBottomSheet(
SizedBox(
height: 400,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const ListTile(
title: Text("设置"),
trailing: IconButton(
onPressed: AppNavigator.closePage,
icon: Icon(Icons.close),
),
contentPadding: AppStyle.edgeInsetsL12,
),
Divider(
height: 1.0,
color: Colors.grey.withOpacity(.2),
),
Obx(
() => ListTile(
title: const Text("字体大小"),
leading: const Icon(Icons.text_fields_rounded),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
OutlinedButton(
onPressed: () {
settings.setNewsFontSize(
settings.newsFontSize.value + 1,
);
setFontSize();
},
child: const Icon(
Icons.add,
color: Colors.grey,
),
),
AppStyle.hGap12,
Text("${settings.newsFontSize.value}"),
AppStyle.hGap12,
OutlinedButton(
onPressed: () {
settings.setNewsFontSize(
settings.newsFontSize.value - 1,
);
setFontSize();
},
child: const Icon(
Icons.remove,
color: Colors.grey,
),
),
],
),
),
),
ListTile(
leading: const Icon(Icons.photo),
title: const Text("进入看图模式"),
onTap: () {
AppNavigator.closePage();
photoView();
},
trailing: const Icon(Icons.chevron_right),
),
],
),
),
);
}
Future setFontSize() async {
try {
if (webViewController == null) {
return;
}
await webViewController!.runJavaScript(
'''document.getElementsByClassName("news_box")[0].style.fontSize="${settings.newsFontSize}px";
document.getElementsByClassName("news_box")[0].style.lineHeight="1.6em";
''');
} catch (e) {
Log.logPrint(e);
}
}
}