Files
DMZJ_F/lib/modules/news/detail/news_detail_controller.dart
2026-03-07 17:24:59 +08:00

399 lines
11 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}
}