Merge branch 'main' into feature-m3Design

This commit is contained in:
guozhigq
2023-07-23 21:14:25 +08:00
13 changed files with 401 additions and 273 deletions

View File

@ -12,7 +12,7 @@ class ReplyHttp {
'oid': oid, 'oid': oid,
'pn': pageNum, 'pn': pageNum,
'type': type, 'type': type,
'sort': 1, 'sort': sort,
}); });
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
return { return {

View File

@ -306,7 +306,7 @@ class VideoHttp {
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
return {'status': true, 'data': res.data['data']}; return {'status': true, 'data': res.data['data']};
} else { } else {
return {'status': false, 'data': []}; return {'status': false, 'data': [], 'msg': res.data['message']};
} }
} }

View File

@ -0,0 +1,6 @@
enum ReplySortType { time, like, reply }
extension ReplySortTypeExtension on ReplySortType {
String get titles => ['最新评论', '最热评论', '回复最多'][index];
String get labels => ['最新', '最热', '最多回复'][index];
}

View File

@ -28,7 +28,8 @@ enum ReplyType {
ticket, ticket,
// 音频 // 音频
audio, audio,
// 风纪委员会
unset3,
// 点评 // 点评
comment, comment,
// 动态 // 动态

View File

@ -33,10 +33,7 @@ class ReplyContent {
pictures = json['pictures'] ?? []; pictures = json['pictures'] ?? [];
vote = json['vote'] ?? {}; vote = json['vote'] ?? {};
richText = json['rich_text'] ?? {}; richText = json['rich_text'] ?? {};
isText = emote!.isEmpty && // 不包含@ 笔记 图片的时候,文字可折叠
atNameToMid!.isEmpty && isText = atNameToMid!.isEmpty && vote!.isEmpty && pictures!.isEmpty;
jumpUrl!.isEmpty &&
vote!.isEmpty &&
pictures!.isEmpty;
} }
} }

View File

@ -1,6 +1,6 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/reply.dart'; import 'package:pilipala/http/reply.dart';
import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/models/common/reply_sort_type.dart';
import 'package:pilipala/models/video/reply/data.dart'; import 'package:pilipala/models/video/reply/data.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
@ -16,6 +16,10 @@ class DynamicDetailController extends GetxController {
RxList<ReplyItemModel> replyList = [ReplyItemModel()].obs; RxList<ReplyItemModel> replyList = [ReplyItemModel()].obs;
RxInt acount = 0.obs; RxInt acount = 0.obs;
ReplySortType sortType = ReplySortType.time;
RxString sortTypeTitle = ReplySortType.time.titles.obs;
RxString sortTypeLabel = ReplySortType.time.labels.obs;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -35,6 +39,7 @@ class DynamicDetailController extends GetxController {
oid: oid!, oid: oid!,
pageNum: currentPage + 1, pageNum: currentPage + 1,
type: type!, type: type!,
sort: sortType.index,
); );
if (res['status']) { if (res['status']) {
res['data'] = ReplyData.fromJson(res['data']); res['data'] = ReplyData.fromJson(res['data']);
@ -42,7 +47,7 @@ class DynamicDetailController extends GetxController {
if (res['data'].replies.isNotEmpty) { if (res['data'].replies.isNotEmpty) {
currentPage = currentPage + 1; currentPage = currentPage + 1;
noMore.value = '加载中...'; noMore.value = '加载中...';
if (replyList.isEmpty) { if (res['data'].replies.isEmpty) {
noMore.value = '没有更多了'; noMore.value = '没有更多了';
return; return;
} }
@ -80,4 +85,24 @@ class DynamicDetailController extends GetxController {
isLoadingMore = false; isLoadingMore = false;
return res; return res;
} }
// 排序搜索评论
queryBySort() {
switch (sortType) {
case ReplySortType.time:
sortType = ReplySortType.like;
break;
case ReplySortType.like:
sortType = ReplySortType.reply;
break;
case ReplySortType.reply:
sortType = ReplySortType.time;
break;
default:
}
sortTypeTitle.value = sortType.titles;
sortTypeLabel.value = sortType.labels;
replyList.clear();
queryReplyList(reqType: 'init');
}
} }

View File

@ -72,7 +72,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
} }
void replyReply(replyItem) { void replyReply(replyItem) {
int oid = replyItem.replies!.first.oid; int oid = replyItem.oid;
int rpid = replyItem.rpid!; int rpid = replyItem.rpid!;
Get.to( Get.to(
() => Scaffold( () => Scaffold(
@ -85,6 +85,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
rpid: rpid, rpid: rpid,
source: 'dynamic', source: 'dynamic',
replyType: ReplyType.values[type], replyType: ReplyType.values[type],
firstFloor: replyItem,
), ),
), ),
); );
@ -158,27 +159,16 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
), ),
const Text('条回复'), const Text('条回复'),
const Spacer(), const Spacer(),
// TextButton.icon( SizedBox(
// onPressed: () {}, height: 35,
// icon: const Icon( child: TextButton.icon(
// Icons.subject_rounded, onPressed: () =>
// size: 15, _dynamicDetailController!.queryBySort(),
// ), icon: const Icon(Icons.sort, size: 17),
// style: TextButton.styleFrom( label: Obx(() => Text(
// padding: const EdgeInsets.fromLTRB(12, 0, 12, 0), _dynamicDetailController!.sortTypeLabel.value)),
// foregroundColor: ),
// Theme.of(context).colorScheme.outline, )
// ),
// label: Text(
// '按时间',
// style: TextStyle(
// fontSize: Theme.of(context)
// .textTheme
// .titleSmall!
// .fontSize,
// ),
// ),
// ),
], ],
), ),
), ),
@ -193,36 +183,49 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
if (snapshot.data['status']) { if (snapshot.data['status']) {
// 请求成功 // 请求成功
return Obx( return Obx(
() => SliverList( () => _dynamicDetailController!.replyList.isEmpty
? SliverList(
delegate:
SliverChildBuilderDelegate((context, index) {
return const VideoReplySkeleton();
}, childCount: 8),
)
: SliverList(
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
(context, index) { (context, index) {
if (index == if (index ==
_dynamicDetailController!.replyList.length) { _dynamicDetailController!
.replyList.length) {
return Container( return Container(
padding: EdgeInsets.only( padding: EdgeInsets.only(
bottom: bottom: MediaQuery.of(context)
MediaQuery.of(context).padding.bottom), .padding
height: .bottom),
MediaQuery.of(context).padding.bottom + 100, height: MediaQuery.of(context)
.padding
.bottom +
100,
child: Center( child: Center(
child: Obx(() => Text( child: Obx(() => Text(
_dynamicDetailController!.noMore.value)), _dynamicDetailController!
.noMore.value)),
), ),
); );
} else { } else {
return ReplyItem( return ReplyItem(
replyItem: replyItem: _dynamicDetailController!
_dynamicDetailController!.replyList[index], .replyList[index],
showReplyRow: true, showReplyRow: true,
replyLevel: '1', replyLevel: '1',
replyReply: (replyItem) => replyReply: (replyItem) =>
replyReply(replyItem), replyReply(replyItem),
replyType: ReplyType.album, replyType: ReplyType.values[type],
); );
} }
}, },
childCount: childCount:
_dynamicDetailController!.replyList.length + 1, _dynamicDetailController!.replyList.length +
1,
), ),
), ),
); );

View File

@ -5,6 +5,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/reply.dart'; import 'package:pilipala/http/reply.dart';
import 'package:pilipala/http/video.dart'; import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/common/reply_sort_type.dart';
import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/models/video/reply/data.dart'; import 'package:pilipala/models/video/reply/data.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
@ -27,7 +28,6 @@ class VideoReplyController extends GetxController {
int currentPage = 0; int currentPage = 0;
bool isLoadingMore = false; bool isLoadingMore = false;
RxString noMore = ''.obs; RxString noMore = ''.obs;
RxBool autoFocus = false.obs;
// 当前回复的回复 // 当前回复的回复
ReplyItemModel? currentReplyItem; ReplyItemModel? currentReplyItem;
// 回复来源 // 回复来源
@ -37,11 +37,19 @@ class VideoReplyController extends GetxController {
// 默认回复主楼 // 默认回复主楼
String replyLevel = '0'; String replyLevel = '0';
ReplySortType sortType = ReplySortType.time;
RxString sortTypeTitle = ReplySortType.time.titles.obs;
RxString sortTypeLabel = ReplySortType.time.labels.obs;
Future queryReplyList({type = 'init'}) async { Future queryReplyList({type = 'init'}) async {
isLoadingMore = true; isLoadingMore = true;
var res = level == '1' var res = level == '1'
? await ReplyHttp.replyList( ? await ReplyHttp.replyList(
oid: aid!, pageNum: currentPage + 1, type: 1) oid: aid!,
pageNum: currentPage + 1,
type: ReplyType.video.index,
sort: sortType.index,
)
: await ReplyHttp.replyReplyList( : await ReplyHttp.replyReplyList(
oid: aid!, root: rpid!, pageNum: currentPage + 1, type: 1); oid: aid!, root: rpid!, pageNum: currentPage + 1, type: 1);
if (res['status']) { if (res['status']) {
@ -91,33 +99,24 @@ class VideoReplyController extends GetxController {
queryReplyList(type: 'onLoad'); queryReplyList(type: 'onLoad');
} }
wakeUpReply() { // 排序搜索评论
autoFocus.value = true; queryBySort() {
} switch (sortType) {
case ReplySortType.time:
// 发表评论 sortType = ReplySortType.like;
Future submitReplyAdd() async { break;
var result = await VideoHttp.replyAdd( case ReplySortType.like:
type: ReplyType.video, sortType = ReplySortType.reply;
oid: aid!, break;
root: replyLevel == '0' case ReplySortType.reply:
? 0 sortType = ReplySortType.time;
: replyLevel == '1' break;
? currentReplyItem!.rpid default:
: rPid,
parent: replyLevel == '0'
? 0
: replyLevel == '1'
? currentReplyItem!.rpid
: currentReplyItem!.rpid,
message: replyLevel == '2'
? ' 回复 @${currentReplyItem!.member!.uname!} : 2楼31'
: '2楼31',
);
if (result['status']) {
SmartDialog.showToast(result['data']['success_toast']);
} else {
SmartDialog.showToast(result['message']);
} }
sortTypeTitle.value = sortType.titles;
sortTypeLabel.value = sortType.labels;
currentPage = 0;
replyList.clear();
queryReplyList(type: 'init');
} }
} }

View File

@ -34,7 +34,6 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
late VideoReplyController _videoReplyController; late VideoReplyController _videoReplyController;
late AnimationController fabAnimationCtr; late AnimationController fabAnimationCtr;
// List<ReplyItemModel>? replyList;
Future? _futureBuilderFuture; Future? _futureBuilderFuture;
bool _isFabVisible = true; bool _isFabVisible = true;
String replyLevel = '1'; String replyLevel = '1';
@ -112,15 +111,15 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
_videoReplyController.replyLevel = '0'; _videoReplyController.replyLevel = '0';
} }
await Future.delayed(const Duration(microseconds: 100)); // await Future.delayed(const Duration(microseconds: 100));
_videoReplyController.wakeUpReply(); // _videoReplyController.wakeUpReply();
} }
// 展示二级回复 // 展示二级回复
void replyReply(replyItem) { void replyReply(replyItem) {
VideoDetailController videoDetailCtr = VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']); Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
videoDetailCtr.oid = replyItem.replies!.first.oid; videoDetailCtr.oid = replyItem.oid;
videoDetailCtr.fRpid = replyItem.rpid!; videoDetailCtr.fRpid = replyItem.rpid!;
videoDetailCtr.firstFloor = replyItem; videoDetailCtr.firstFloor = replyItem;
videoDetailCtr.showReplyReplyPanel(); videoDetailCtr.showReplyReplyPanel();
@ -147,7 +146,46 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
controller: _videoReplyController.scrollController, controller: _videoReplyController.scrollController,
key: const PageStorageKey<String>('评论'), key: const PageStorageKey<String>('评论'),
slivers: <Widget>[ slivers: <Widget>[
const SliverToBoxAdapter(child: SizedBox(height: 12)), SliverPersistentHeader(
pinned: false,
floating: true,
delegate: _MySliverPersistentHeaderDelegate(
child: Container(
color: Theme.of(context).colorScheme.background,
padding: const EdgeInsets.fromLTRB(12, 6, 10, 6),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Obx(
() => AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
transitionBuilder:
(Widget child, Animation<double> animation) {
return ScaleTransition(
scale: animation, child: child);
},
child: Text(
_videoReplyController.sortTypeTitle.value,
key: ValueKey<String>(
_videoReplyController.sortTypeTitle.value),
),
),
),
SizedBox(
height: 35,
child: TextButton.icon(
onPressed: () =>
_videoReplyController.queryBySort(),
icon: const Icon(Icons.sort, size: 17),
label: Obx(() => Text(
_videoReplyController.sortTypeLabel.value)),
),
)
],
),
),
),
),
FutureBuilder( FutureBuilder(
future: _futureBuilderFuture, future: _futureBuilderFuture,
builder: (context, snapshot) { builder: (context, snapshot) {
@ -156,28 +194,38 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
if (data['status']) { if (data['status']) {
// 请求成功 // 请求成功
return Obx( return Obx(
() => SliverList( () => _videoReplyController.replyList.isEmpty
? SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return const VideoReplySkeleton();
}, childCount: 5),
)
: SliverList(
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
(context, index) { (context, index) {
if (index == if (index ==
_videoReplyController.replyList.length) { _videoReplyController
.replyList.length) {
return Container( return Container(
padding: EdgeInsets.only( padding: EdgeInsets.only(
bottom: MediaQuery.of(context) bottom: MediaQuery.of(context)
.padding .padding
.bottom), .bottom),
height: height: MediaQuery.of(context)
MediaQuery.of(context).padding.bottom + .padding
.bottom +
100, 100,
child: Center( child: Center(
child: Obx(() => Text( child: Obx(() => Text(
_videoReplyController.noMore.value)), _videoReplyController
.noMore.value)),
), ),
); );
} else { } else {
return ReplyItem( return ReplyItem(
replyItem: replyItem: _videoReplyController
_videoReplyController.replyList[index], .replyList[index],
showReplyRow: true, showReplyRow: true,
replyLevel: replyLevel, replyLevel: replyLevel,
replyReply: (replyItem) => replyReply: (replyItem) =>
@ -187,7 +235,8 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
} }
}, },
childCount: childCount:
_videoReplyController.replyList.length + 1, _videoReplyController.replyList.length +
1,
), ),
), ),
); );
@ -231,7 +280,6 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
isScrollControlled: true, isScrollControlled: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return VideoReplyNewDialog( return VideoReplyNewDialog(
replyLevel: '0',
oid: IdUtils.bv2av(Get.parameters['bvid']!), oid: IdUtils.bv2av(Get.parameters['bvid']!),
root: 0, root: 0,
parent: 0, parent: 0,
@ -256,3 +304,33 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
); );
} }
} }
class _MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
final double _minExtent = 45;
final double _maxExtent = 45;
final Widget child;
_MySliverPersistentHeaderDelegate({required this.child});
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
//创建child子组件
//shrinkOffsetchild偏移值minExtent~maxExtent
//overlapsContentSliverPersistentHeader覆盖其他子组件返回true否则返回false
return child;
}
//SliverPersistentHeader最大高度
@override
double get maxExtent => _maxExtent;
//SliverPersistentHeader最小高度
@override
double get minExtent => _minExtent;
@override
bool shouldRebuild(covariant _MySliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}

View File

@ -1,17 +1,12 @@
import 'dart:developer';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_meedu_media_kit/meedu_player.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/pages/video/detail/controller.dart'; import 'package:pilipala/pages/video/detail/controller.dart';
import 'package:pilipala/pages/video/detail/reply/index.dart';
import 'package:pilipala/pages/video/detail/replyNew/index.dart'; import 'package:pilipala/pages/video/detail/replyNew/index.dart';
import 'package:pilipala/pages/video/detail/replyReply/index.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
class ReplyItem extends StatelessWidget { class ReplyItem extends StatelessWidget {
@ -33,21 +28,14 @@ class ReplyItem extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return InkWell( return Material(
onTap: () {}, child: InkWell(
child: Column( // 点击整个评论区 评论详情/回复
children: [ onTap: () => replyReply!(replyItem),
Padding( child: Padding(
padding: const EdgeInsets.fromLTRB(12, 4, 8, 2), padding: const EdgeInsets.fromLTRB(12, 4, 8, 2),
child: content(context), child: content(context),
), ),
// Divider(
// height: 1,
// indent: 52,
// endIndent: 10,
// color: Theme.of(context).dividerColor.withOpacity(0.08),
// )
],
), ),
); );
} }
@ -84,14 +72,7 @@ class ReplyItem extends StatelessWidget {
), ),
), ),
], ],
) ),
// child:
// NetworkImgLayer(
// src: replyItem!.member!.avatar,
// width: 30,
// height: 30,
// type: 'avatar',
// ),
); );
} }
@ -122,7 +103,7 @@ class ReplyItem extends StatelessWidget {
replyItem!.member!.uname!, replyItem!.member!.uname!,
style: TextStyle( style: TextStyle(
color: replyItem!.isUp! || color: replyItem!.isUp! ||
replyItem!.member!.vip!['vipType'] > 0 replyItem!.member!.vip!['vipStatus'] > 0
? Theme.of(context).colorScheme.primary ? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline, : Theme.of(context).colorScheme.outline,
fontSize: fontSize:
@ -196,15 +177,15 @@ class ReplyItem extends StatelessWidget {
focusNode: FocusNode(), focusNode: FocusNode(),
selectionControls: MaterialTextSelectionControls(), selectionControls: MaterialTextSelectionControls(),
child: Text.rich( child: Text.rich(
style: const TextStyle(height: 1.65), style: const TextStyle(height: 1.75),
maxLines: maxLines:
replyItem!.content!.isText! && replyLevel == '1' ? 6 : 999, replyItem!.content!.isText! && replyLevel == '1' ? 3 : 999,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
TextSpan( TextSpan(
children: [ children: [
if (replyItem!.isTop!) if (replyItem!.isTop!)
WidgetSpan(child: UpTag(tagText: 'TOP')), WidgetSpan(child: UpTag(tagText: 'TOP')),
buildContent(context, replyItem!, replyReply), buildContent(context, replyItem!, replyReply, null),
], ],
), ),
), ),
@ -212,10 +193,12 @@ class ReplyItem extends StatelessWidget {
), ),
// 操作区域 // 操作区域
bottonAction(context, replyItem!.replyControl), bottonAction(context, replyItem!.replyControl),
const SizedBox(height: 3), // 一楼的评论
if (replyItem!.replies!.isNotEmpty && showReplyRow!) ...[ if ((replyItem!.replyControl!.isShow! ||
replyItem!.replies!.isNotEmpty) &&
showReplyRow!) ...[
Padding( Padding(
padding: const EdgeInsets.only(top: 2, bottom: 12), padding: const EdgeInsets.only(top: 5, bottom: 12),
child: ReplyItemRow( child: ReplyItemRow(
replies: replyItem!.replies, replies: replyItem!.replies,
replyControl: replyItem!.replyControl, replyControl: replyItem!.replyControl,
@ -281,16 +264,16 @@ class ReplyItem extends StatelessWidget {
isScrollControlled: true, isScrollControlled: true,
builder: (builder) { builder: (builder) {
return VideoReplyNewDialog( return VideoReplyNewDialog(
replyLevel: replyLevel,
oid: replyItem!.oid, oid: replyItem!.oid,
root: replyItem!.rpid, root: replyItem!.rpid,
parent: replyItem!.rpid, parent: replyItem!.rpid,
replyType: replyType, replyType: replyType,
replyItem: replyItem,
); );
}, },
).then((value) => { ).then((value) => {
// 完成评论,数据添加 // 完成评论,数据添加
if (value['data'] != null) if (value != null && value['data'] != null)
{ {
addReply!(value['data']) addReply!(value['data'])
// replyControl.replies.add(value['data']), // replyControl.replies.add(value['data']),
@ -358,8 +341,10 @@ class ReplyItemRow extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (replies!.isNotEmpty)
for (var i = 0; i < replies!.length; i++) ...[ for (var i = 0; i < replies!.length; i++) ...[
InkWell( InkWell(
// 一楼点击评论展开评论详情
onTap: () => replyReply!(replyItem), onTap: () => replyReply!(replyItem),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
@ -370,10 +355,8 @@ class ReplyItemRow extends StatelessWidget {
i == 0 && (extraRow == 1 || replies!.length > 1) ? 5 : 6, i == 0 && (extraRow == 1 || replies!.length > 1) ? 5 : 6,
), ),
child: Text.rich( child: Text.rich(
overflow: extraRow == 1 overflow: TextOverflow.ellipsis,
? TextOverflow.ellipsis maxLines: 2,
: TextOverflow.visible,
maxLines: extraRow == 1 ? 2 : null,
TextSpan( TextSpan(
children: [ children: [
TextSpan( TextSpan(
@ -401,7 +384,8 @@ class ReplyItemRow extends StatelessWidget {
WidgetSpan( WidgetSpan(
child: UpTag(), child: UpTag(),
), ),
buildContent(context, replies![i], replyReply), buildContent(
context, replies![i], replyReply, replyItem),
], ],
), ),
), ),
@ -410,6 +394,7 @@ class ReplyItemRow extends StatelessWidget {
], ],
if (extraRow == 1) if (extraRow == 1)
InkWell( InkWell(
// 一楼点击【共xx条回复】展开评论详情
onTap: () => replyReply!(replyItem), onTap: () => replyReply!(replyItem),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
@ -441,7 +426,11 @@ class ReplyItemRow extends StatelessWidget {
} }
} }
InlineSpan buildContent(BuildContext context, replyItem, replyReply) { InlineSpan buildContent(
BuildContext context, replyItem, replyReply, fReplyItem) {
// replyItem 当前回复内容
// replyReply 查看二楼回复(回复详情)回调
// fReplyItem 父级回复内容,用作二楼回复(回复详情)展示
var content = replyItem.content; var content = replyItem.content;
if (content.emote.isEmpty && if (content.emote.isEmpty &&
content.atNameToMid.isEmpty && content.atNameToMid.isEmpty &&
@ -450,7 +439,9 @@ InlineSpan buildContent(BuildContext context, replyItem, replyReply) {
content.pictures.isEmpty) { content.pictures.isEmpty) {
return TextSpan( return TextSpan(
text: content.message, text: content.message,
recognizer: TapGestureRecognizer()..onTap = () => replyReply(replyItem), recognizer: TapGestureRecognizer()
..onTap =
() => replyReply(replyItem.root == 0 ? replyItem : fReplyItem),
); );
} }
List<InlineSpan> spanChilds = []; List<InlineSpan> spanChilds = [];
@ -510,11 +501,19 @@ InlineSpan buildContent(BuildContext context, replyItem, replyReply) {
), ),
); );
} else { } else {
spanChilds.add(TextSpan(text: matchStr)); spanChilds.add(TextSpan(
text: matchStr,
recognizer: TapGestureRecognizer()
..onTap = () =>
replyReply(replyItem.root == 0 ? replyItem : fReplyItem)));
return matchStr; return matchStr;
} }
} else { } else {
spanChilds.add(TextSpan(text: matchStr)); spanChilds.add(TextSpan(
text: matchStr,
recognizer: TapGestureRecognizer()
..onTap = () =>
replyReply(replyItem.root == 0 ? replyItem : fReplyItem)));
return matchStr; return matchStr;
} }
return ''; return '';
@ -595,7 +594,11 @@ InlineSpan buildContent(BuildContext context, replyItem, replyReply) {
return ''; return '';
}, },
onNonMatch: (String str) { onNonMatch: (String str) {
spanChilds.add(TextSpan(text: str)); spanChilds.add(TextSpan(
text: str,
recognizer: TapGestureRecognizer()
..onTap = () => replyReply(
replyItem.root == 0 ? replyItem : fReplyItem)));
return str; return str;
}, },
); );
@ -628,7 +631,11 @@ InlineSpan buildContent(BuildContext context, replyItem, replyReply) {
); );
if (content.atNameToMid.isEmpty && content.jumpUrl.isEmpty) { if (content.atNameToMid.isEmpty && content.jumpUrl.isEmpty) {
spanChilds.add(TextSpan(text: str)); spanChilds.add(TextSpan(
text: str,
recognizer: TapGestureRecognizer()
..onTap = () =>
replyReply(replyItem.root == 0 ? replyItem : fReplyItem)));
} }
return str; return str;
}, },

View File

@ -12,16 +12,16 @@ import 'package:pilipala/utils/storage.dart';
class VideoReplyNewDialog extends StatefulWidget { class VideoReplyNewDialog extends StatefulWidget {
int? oid; int? oid;
int? root; int? root;
String? replyLevel;
int? parent; int? parent;
ReplyType? replyType; ReplyType? replyType;
ReplyItemModel? replyItem;
VideoReplyNewDialog({ VideoReplyNewDialog({
this.oid, this.oid,
this.root, this.root,
this.replyLevel,
this.parent, this.parent,
this.replyType, this.replyType,
this.replyItem,
}); });
@override @override
@ -36,14 +36,12 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
double _keyboardHeight = 0.0; // 键盘高度 double _keyboardHeight = 0.0; // 键盘高度
final _debouncer = Debouncer(milliseconds: 100); // 设置延迟时间 final _debouncer = Debouncer(milliseconds: 100); // 设置延迟时间
bool ableClean = false; bool ableClean = false;
bool autoFocus = false;
Timer? timer; Timer? timer;
Box localCache = GStrorage.localCache; Box localCache = GStrorage.localCache;
late double sheetHeight; late double sheetHeight;
@override @override
void initState() { void initState() {
// TODO: implement initState
super.initState(); super.initState();
// 监听输入框聚焦 // 监听输入框聚焦
// replyContentFocusNode.addListener(_onFocus); // replyContentFocusNode.addListener(_onFocus);
@ -74,14 +72,18 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
oid: widget.oid!, oid: widget.oid!,
root: widget.root!, root: widget.root!,
parent: widget.parent!, parent: widget.parent!,
message: message, message: widget.replyItem != null && widget.replyItem!.root != 0
? ' 回复 @${widget.replyItem!.member!.uname!} : $message'
: message,
); );
if (result['status']) { if (result['status']) {
SmartDialog.showToast(result['data']['success_toast']); SmartDialog.showToast(result['data']['success_toast']);
Get.back(result: { Get.back(result: {
'data': ReplyItemModel.fromJson(result['data']['reply'], ''), 'data': ReplyItemModel.fromJson(result['data']['reply'], ''),
}); });
} else {} } else {
SmartDialog.showToast(result['msg']);
}
} }
@override @override
@ -103,6 +105,12 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
}); });
} }
@override
void dispose() {
_replyContentController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(

View File

@ -123,7 +123,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
addReply: (replyItem) { addReply: (replyItem) {
_videoReplyReplyController.replyList.add(replyItem); _videoReplyReplyController.replyList.add(replyItem);
}, },
replyType: ReplyType.video, replyType: widget.replyType,
), ),
), ),
SliverToBoxAdapter( SliverToBoxAdapter(
@ -167,8 +167,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
), ),
); );
} else { } else {
return Material( return ReplyItem(
child: ReplyItem(
replyItem: _videoReplyReplyController replyItem: _videoReplyReplyController
.replyList[index], .replyList[index],
replyLevel: '2', replyLevel: '2',
@ -176,7 +175,8 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
addReply: (replyItem) { addReply: (replyItem) {
_videoReplyReplyController.replyList _videoReplyReplyController.replyList
.add(replyItem); .add(replyItem);
}), },
replyType: widget.replyType,
); );
} }
}, },

View File

@ -122,9 +122,9 @@ class Utils {
return timeStr; return timeStr;
} }
if (formatType == 'list' && int.parse(DD) > DateTime.now().day - 2) { // if (formatType == 'list' && int.parse(DD) > DateTime.now().day - 2) {
return '昨天'; // return '昨天';
} // }
date = date date = date
.replaceAll('YY', YY) .replaceAll('YY', YY)
@ -133,8 +133,12 @@ class Utils {
.replaceAll('hh', hh) .replaceAll('hh', hh)
.replaceAll('mm', mm) .replaceAll('mm', mm)
.replaceAll('ss', ss); .replaceAll('ss', ss);
if (int.parse(DD) < DateTime.now().day) { if (int.parse(YY) == DateTime.now().year &&
return date.split(' ')[0]; int.parse(MM) == DateTime.now().month) {
// 当天
if (int.parse(DD) == DateTime.now().day) {
return date.split(' ')[1];
}
} }
return date; return date;
} }