topic_detail_page.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import 'dart:io';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_riverpod/flutter_riverpod.dart';
  5. import 'package:flutter_screenutil/flutter_screenutil.dart';
  6. import 'package:news_app/constant/color_res.dart';
  7. import 'package:news_app/model/topic_item_model.dart';
  8. import 'package:news_app/ui/topic/main_topic_page.dart';
  9. import 'package:news_app/ui/topic/topic_item_widget.dart';
  10. import '../../constant/config.dart';
  11. import '../../constant/size_res.dart';
  12. import '../../provider/topic_detail_provider.dart';
  13. import '../../util/device_util.dart';
  14. import '../../util/share_util.dart';
  15. import '../../widget/load_image.dart';
  16. import '../../widget/my_txt.dart';
  17. import '../../widget/right_action_widget.dart';
  18. import '../video/comment_page.dart';
  19. /// @author: bo.zeng
  20. /// @email: cnhbwds@gmail.com
  21. /// @date: 2025 2025/4/18 9:06
  22. /// @description:
  23. class TopicDetailPage extends ConsumerStatefulWidget {
  24. final String contentId;
  25. const TopicDetailPage({super.key, required this.contentId});
  26. @override
  27. ConsumerState<ConsumerStatefulWidget> createState() =>
  28. _TopicDetailPageState();
  29. }
  30. final topicDetailProvider =
  31. NotifierProvider<TopicDetailProvider, TopicRecordModel>(() {
  32. return TopicDetailProvider();
  33. });
  34. class _TopicDetailPageState extends ConsumerState<TopicDetailPage> {
  35. BuildContext? currentContext;
  36. bool _isWeChatInstalled = false;
  37. Future<void> _checkWeChatInstallation() async {
  38. if (Platform.isAndroid) {
  39. final installed = await isWeChatInstalledOnlyAndroid();
  40. setState(() => _isWeChatInstalled = installed);
  41. } else if (Platform.isIOS) {
  42. final installed = await fluwx.isWeChatInstalled;
  43. setState(() => _isWeChatInstalled = installed);
  44. }
  45. }
  46. @override
  47. void initState() {
  48. super.initState();
  49. ref.read(topicDetailProvider.notifier).fetchTopicDetail(widget.contentId);
  50. _checkWeChatInstallation();
  51. }
  52. Future<void> shareAction(TopicRecordModel data) async {
  53. showModalBottomSheet(
  54. context: context,
  55. builder:
  56. (context) => SafeArea(
  57. child: Column(
  58. mainAxisSize: MainAxisSize.min,
  59. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  60. children: [
  61. SizedBox(height: 10.h),
  62. Container(
  63. width: double.infinity,
  64. height: 80.h,
  65. decoration: BoxDecoration(
  66. borderRadius: BorderRadius.only(
  67. topLeft: Radius.circular(10.r),
  68. topRight: Radius.circular(10.r),
  69. ),
  70. color: Colors.white,
  71. ),
  72. child: Row(
  73. crossAxisAlignment: CrossAxisAlignment.center,
  74. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  75. children: [
  76. if (_isWeChatInstalled)
  77. GestureDetector(
  78. onTap: () {
  79. Navigator.pop(context);
  80. shareWeiXinUrl(
  81. title: data.shareDesc ?? "",
  82. url: data.shareUrl ?? "",
  83. );
  84. },
  85. child: Container(
  86. width: 100.w,
  87. height: 80.h,
  88. child: Column(
  89. crossAxisAlignment: CrossAxisAlignment.center,
  90. mainAxisAlignment: MainAxisAlignment.center,
  91. children: [
  92. LoadAssetImage(
  93. 'share_wxhy',
  94. width: 40.w,
  95. height: 40.h,
  96. ),
  97. SizedBox(height: 10.h),
  98. myTxt(
  99. text: "微信好友",
  100. color: Colors.black,
  101. fontSize: 12.sp,
  102. fontWeight: FontWeight.bold,
  103. ),
  104. ],
  105. ),
  106. ),
  107. ),
  108. if (_isWeChatInstalled)
  109. GestureDetector(
  110. onTap: () {
  111. Navigator.pop(context);
  112. shareWeiXinPYUrl(
  113. title: data.shareDesc ?? "",
  114. url: data.shareUrl ?? "",
  115. );
  116. },
  117. child: Container(
  118. width: 100.w,
  119. height: 80.h,
  120. child: Column(
  121. mainAxisAlignment: MainAxisAlignment.center,
  122. children: [
  123. LoadAssetImage(
  124. 'share_pyq',
  125. width: 40.w,
  126. height: 40.h,
  127. ),
  128. SizedBox(height: 10.h),
  129. myTxt(
  130. text: "朋友圈",
  131. color: Colors.black,
  132. fontSize: 12.sp,
  133. fontWeight: FontWeight.bold,
  134. ),
  135. ],
  136. ),
  137. ),
  138. ),
  139. GestureDetector(
  140. onTap: () {
  141. Navigator.pop(context);
  142. shareUrl(
  143. title: data.shareDesc ?? "",
  144. url: data.shareUrl ?? "",
  145. );
  146. },
  147. child: Container(
  148. width: 100.w,
  149. height: 80.h,
  150. child: Column(
  151. mainAxisAlignment: MainAxisAlignment.center,
  152. children: [
  153. LoadAssetImage(
  154. 'share_xtfx',
  155. width: 40.w,
  156. height: 40.h,
  157. ),
  158. SizedBox(height: 10.h),
  159. myTxt(
  160. text: "系统分享",
  161. color: Colors.black,
  162. fontSize: 12.sp,
  163. fontWeight: FontWeight.bold,
  164. ),
  165. ],
  166. ),
  167. ),
  168. ),
  169. ],
  170. ),
  171. ),
  172. ],
  173. ),
  174. ),
  175. );
  176. }
  177. void longTapAction(String contentId) {
  178. showCupertinoDialog(
  179. context: context,
  180. builder:
  181. (context) => CupertinoAlertDialog(
  182. title: const Text("举报该评论"),
  183. content: const Text("您确定要执行此操作吗?"),
  184. actions: [
  185. CupertinoDialogAction(
  186. child: const Text("取消"),
  187. onPressed: () => Navigator.pop(context),
  188. ),
  189. CupertinoDialogAction(
  190. isDestructiveAction: true, // 红色警示按钮
  191. child: const Text("确定"),
  192. onPressed: () {
  193. ref
  194. .read(topicDetailProvider.notifier)
  195. .reportComment("topicArticle", contentId);
  196. Navigator.pop(context);
  197. Future.delayed(const Duration(milliseconds: 500), () {
  198. if (mounted && currentContext != null) {
  199. eventBus.fire('topicCall');
  200. Navigator.of(currentContext!).pop();
  201. }
  202. });
  203. // 执行删除操作
  204. },
  205. ),
  206. ],
  207. ),
  208. );
  209. }
  210. @override
  211. Widget build(BuildContext context) {
  212. currentContext = context;
  213. final data = ref.watch(topicDetailProvider);
  214. return Scaffold(
  215. appBar: AppBar(
  216. title: myTxt(text: '话题', fontSize: 18.sp, fontWeight: FontWeight.bold),
  217. centerTitle: true,
  218. // 移除阴影
  219. scrolledUnderElevation: 0,
  220. actions: [
  221. Padding(
  222. padding: EdgeInsets.only(right: horizontalPadding),
  223. child: RightActionWidget(
  224. isLike: data.isLiked ?? false,
  225. isFavorite: data.isFavorite ?? false,
  226. tap: (value) {
  227. if (value == 0) {
  228. ref
  229. .read(topicListProvider.notifier)
  230. .fetchTopicLike(
  231. contentId: data.contentId,
  232. current: data.isLiked ?? false,
  233. );
  234. ref.read(topicDetailProvider.notifier).updateLike();
  235. } else if (value == 1) {
  236. ref
  237. .read(topicListProvider.notifier)
  238. .fetchTopicFavorite(
  239. contentId: data.contentId,
  240. current: data.isFavorite ?? false,
  241. );
  242. ref.read(topicDetailProvider.notifier).updateFavorite();
  243. } else if (value == 2) {
  244. // shareUrl(title: data.content ?? "", url: data.shareUrl ?? "");
  245. shareAction(data);
  246. if (uuid.isNotEmpty) {
  247. ref
  248. .read(topicDetailProvider.notifier)
  249. .fetchTopicShare(contentId: data.contentId);
  250. }
  251. }
  252. },
  253. ),
  254. ),
  255. ],
  256. // 禁用滚动时的阴影变化
  257. ),
  258. body: NestedScrollView(
  259. headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
  260. return [
  261. SliverToBoxAdapter(
  262. child: TopicItemWidget(longTapAction, isShow: true, item: data),
  263. ),
  264. SliverToBoxAdapter(
  265. child: Container(
  266. height: 8.h,
  267. width: screenWidth,
  268. color: colorF5F7FD,
  269. ),
  270. ),
  271. ];
  272. },
  273. body: Container(
  274. color: Colors.white,
  275. padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h),
  276. child: Column(
  277. crossAxisAlignment: CrossAxisAlignment.start,
  278. children: [
  279. myTxt(
  280. text:
  281. "评论${ref.watch(commentProvider(CommentType.topic)).total}",
  282. fontSize: 14.sp,
  283. color: color333333,
  284. fontWeight: FontWeight.bold,
  285. ),
  286. SizedBox(height: 12.h),
  287. Expanded(
  288. child: CommentPage(
  289. type: CommentType.topic,
  290. articleId: widget.contentId,
  291. ),
  292. ),
  293. ],
  294. ),
  295. ),
  296. ),
  297. );
  298. }
  299. }