From 5e63f0da7b93eb3e2d2b27ed0ba8b52d24518f50 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 15 Jun 2024 16:03:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=A7=81=E4=BF=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/msg.dart | 66 ++-- lib/pages/member/widgets/profile.dart | 12 +- lib/pages/whisper/controller.dart | 9 + lib/pages/whisper/view.dart | 23 +- lib/pages/whisper_detail/controller.dart | 37 +- lib/pages/whisper_detail/view.dart | 342 ++++++++++-------- .../whisper_detail/widget/chat_item.dart | 162 +++++---- 7 files changed, 373 insertions(+), 278 deletions(-) diff --git a/lib/http/msg.dart b/lib/http/msg.dart index d1d31958..7ac30bc1 100644 --- a/lib/http/msg.dart +++ b/lib/http/msg.dart @@ -1,4 +1,6 @@ +import 'dart:convert'; import 'dart:math'; +import 'package:dio/dio.dart'; import '../models/msg/account.dart'; import '../models/msg/session.dart'; import '../utils/wbi_sign.dart'; @@ -134,56 +136,42 @@ class MsgHttp { // 发送私信 static Future sendMsg({ - int? senderUid, - int? receiverId, + required int senderUid, + required int receiverId, int? receiverType, int? msgType, dynamic content, }) async { String csrf = await Request.getCsrf(); - Map params = await WbiSign().makSign({ - 'msg[sender_uid]': senderUid, - 'msg[receiver_id]': receiverId, - 'msg[receiver_type]': receiverType ?? 1, - 'msg[msg_type]': msgType ?? 1, - 'msg[msg_status]': 0, - 'msg[dev_id]': getDevId(), - 'msg[timestamp]': DateTime.now().millisecondsSinceEpoch ~/ 1000, - 'msg[new_face_version]': 0, - 'msg[content]': content, - 'from_firework': 0, - 'build': 0, - 'mobi_app': 'web', - 'csrf_token': csrf, - 'csrf': csrf, - }); - var res = - await Request().post(Api.sendMsg, queryParameters: { - ...params, - 'csrf_token': csrf, - 'csrf': csrf, - }, data: { - 'w_sender_uid': params['msg[sender_uid]'], - 'w_receiver_id': params['msg[receiver_id]'], - 'w_dev_id': params['msg[dev_id]'], - 'w_rid': params['w_rid'], - 'wts': params['wts'], - 'csrf_token': csrf, - 'csrf': csrf, - }); + var res = await Request().post( + Api.sendMsg, + data: { + 'msg[sender_uid]': senderUid, + 'msg[receiver_id]': receiverId, + 'msg[receiver_type]': 1, + 'msg[msg_type]': 1, + 'msg[msg_status]': 0, + 'msg[content]': jsonEncode(content), + 'msg[timestamp]': DateTime.now().millisecondsSinceEpoch ~/ 1000, + 'msg[new_face_version]': 0, + 'msg[dev_id]': getDevId(), + 'from_firework': 0, + 'build': 0, + 'mobi_app': 'web', + 'csrf_token': csrf, + 'csrf': csrf, + }, + options: Options( + contentType: Headers.formUrlEncodedContentType, + ), + ); if (res.data['code'] == 0) { return { 'status': true, 'data': res.data['data'], }; } else { - return { - 'status': false, - 'date': [], - 'msg': "message: ${res.data['message']}," - " msg: ${res.data['msg']}," - " code: ${res.data['code']}", - }; + return {'status': false, 'date': [], 'msg': res.data['message']}; } } diff --git a/lib/pages/member/widgets/profile.dart b/lib/pages/member/widgets/profile.dart index a708a35e..8c6385db 100644 --- a/lib/pages/member/widgets/profile.dart +++ b/lib/pages/member/widgets/profile.dart @@ -208,7 +208,17 @@ class ProfilePanel extends StatelessWidget { const SizedBox(width: 8), Expanded( child: TextButton( - onPressed: () {}, + onPressed: () { + Get.toNamed( + '/whisperDetail', + parameters: { + 'name': memberInfo.name!, + 'face': memberInfo.face!, + 'mid': memberInfo.mid.toString(), + 'heroTag': ctr.heroTag!, + }, + ); + }, style: TextButton.styleFrom( backgroundColor: Theme.of(context) .colorScheme diff --git a/lib/pages/whisper/controller.dart b/lib/pages/whisper/controller.dart index c82cab5b..b7c52d2e 100644 --- a/lib/pages/whisper/controller.dart +++ b/lib/pages/whisper/controller.dart @@ -62,4 +62,13 @@ class WhisperController extends GetxController { Future onRefresh() async { querySessionList('onRefresh'); } + + void refreshLastMsg(int talkerId, String content) { + final SessionList currentItem = + sessionList.where((p0) => p0.talkerId == talkerId).first; + currentItem.lastMsg!.content['content'] = content; + sessionList.removeWhere((p0) => p0.talkerId == talkerId); + sessionList.insert(0, currentItem); + sessionList.refresh(); + } } diff --git a/lib/pages/whisper/view.dart b/lib/pages/whisper/view.dart index fa95463b..6d2f281b 100644 --- a/lib/pages/whisper/view.dart +++ b/lib/pages/whisper/view.dart @@ -202,6 +202,7 @@ class SessionItem extends StatelessWidget { @override Widget build(BuildContext context) { + final String heroTag = Utils.makeHeroTag(sessionItem.accountInfo.mid); final content = sessionItem.lastMsg.content; return ListTile( onTap: () { @@ -214,6 +215,7 @@ class SessionItem extends StatelessWidget { 'name': sessionItem.accountInfo.name, 'face': sessionItem.accountInfo.face, 'mid': sessionItem.accountInfo.mid.toString(), + 'heroTag': heroTag, }, ); }, @@ -221,11 +223,14 @@ class SessionItem extends StatelessWidget { isLabelVisible: sessionItem.unreadCount > 0, label: Text(sessionItem.unreadCount.toString()), alignment: Alignment.topRight, - child: NetworkImgLayer( - width: 45, - height: 45, - type: 'avatar', - src: sessionItem.accountInfo.face, + child: Hero( + tag: heroTag, + child: NetworkImgLayer( + width: 45, + height: 45, + type: 'avatar', + src: sessionItem.accountInfo.face, + ), ), ), title: Text(sessionItem.accountInfo.name), @@ -245,10 +250,10 @@ class SessionItem extends StatelessWidget { .copyWith(color: Theme.of(context).colorScheme.outline)), trailing: Text( Utils.dateFormat(sessionItem.lastMsg.timestamp), - style: Theme.of(context) - .textTheme - .labelSmall! - .copyWith(color: Theme.of(context).colorScheme.outline), + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, + color: Theme.of(context).colorScheme.outline, + ), ), ); } diff --git a/lib/pages/whisper_detail/controller.dart b/lib/pages/whisper_detail/controller.dart index 6e950f81..3c7e0837 100644 --- a/lib/pages/whisper_detail/controller.dart +++ b/lib/pages/whisper_detail/controller.dart @@ -1,30 +1,39 @@ +import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/http/msg.dart'; import 'package:pilipala/models/msg/session.dart'; +import 'package:pilipala/pages/whisper/index.dart'; import '../../utils/feed_back.dart'; import '../../utils/storage.dart'; class WhisperDetailController extends GetxController { - late int talkerId; + int? talkerId; late String name; late String face; late String mid; + late String heroTag; RxList messageList = [].obs; //表情转换图片规则 - List? eInfos; + RxList eInfos = [].obs; final TextEditingController replyContentController = TextEditingController(); Box userInfoCache = GStrorage.userInfo; + List emoteList = []; @override void onInit() { super.onInit(); - talkerId = int.parse(Get.parameters['talkerId']!); + if (Get.parameters.containsKey('talkerId')) { + talkerId = int.parse(Get.parameters['talkerId']!); + } else { + talkerId = int.parse(Get.parameters['mid']!); + } name = Get.parameters['name']!; face = Get.parameters['face']!; mid = Get.parameters['mid']!; + heroTag = Get.parameters['heroTag']!; } Future querySessionMsg() async { @@ -34,7 +43,7 @@ class WhisperDetailController extends GetxController { if (messageList.isNotEmpty) { ackSessionMsg(); if (res['data'].eInfos != null) { - eInfos = res['data'].eInfos; + eInfos.value = res['data'].eInfos; } } } else { @@ -73,7 +82,25 @@ class WhisperDetailController extends GetxController { msgType: 1, ); if (result['status']) { - SmartDialog.showToast('发送成功'); + String content = jsonDecode(result['data']['msg_content'])['content']; + messageList.insert( + 0, + MessageItem( + msgSeqno: result['data']['msg_key'], + senderUid: userInfo.mid, + receiverId: int.parse(mid), + content: {'content': content}, + msgType: 1, + timestamp: DateTime.now().millisecondsSinceEpoch, + ), + ); + eInfos.addAll(emoteList); + replyContentController.clear(); + try { + late final WhisperController whisperController = + Get.find(); + whisperController.refreshLastMsg(talkerId!, message); + } catch (_) {} } else { SmartDialog.showToast(result['msg']); } diff --git a/lib/pages/whisper_detail/view.dart b/lib/pages/whisper_detail/view.dart index 1701be33..7c5762d9 100644 --- a/lib/pages/whisper_detail/view.dart +++ b/lib/pages/whisper_detail/view.dart @@ -1,9 +1,12 @@ import 'dart:async'; +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; +import 'package:pilipala/models/video/reply/emote.dart'; import 'package:pilipala/pages/emote/index.dart'; +import 'package:pilipala/pages/video/detail/reply_new/toolbar_icon_button.dart'; import 'package:pilipala/pages/whisper_detail/controller.dart'; import 'package:pilipala/utils/feed_back.dart'; import '../../utils/storage.dart'; @@ -24,9 +27,9 @@ class _WhisperDetailPageState extends State late TextEditingController _replyContentController; final FocusNode replyContentFocusNode = FocusNode(); final _debouncer = Debouncer(milliseconds: 200); // 设置延迟时间 - late double emoteHeight = 0.0; + late double emoteHeight = 230.0; double keyboardHeight = 0.0; // 键盘高度 - String toolbarType = 'input'; + RxString toolbarType = ''.obs; Box userInfoCache = GStrorage.userInfo; @override @@ -41,9 +44,7 @@ class _WhisperDetailPageState extends State _focuslistener() { replyContentFocusNode.addListener(() { if (replyContentFocusNode.hasFocus) { - setState(() { - toolbarType = 'input'; - }); + toolbarType.value = 'input'; } }); } @@ -52,7 +53,7 @@ class _WhisperDetailPageState extends State void didChangeMetrics() { super.didChangeMetrics(); final String routePath = Get.currentRoute; - if (mounted && routePath.startsWith('/whisper_detail')) { + if (mounted && routePath.startsWith('/whisperDetail')) { WidgetsBinding.instance.addPostFrameCallback((_) { // 键盘高度 final viewInsets = EdgeInsets.fromViewPadding( @@ -61,8 +62,11 @@ class _WhisperDetailPageState extends State if (mounted) { if (keyboardHeight == 0) { setState(() { - emoteHeight = keyboardHeight = + keyboardHeight = keyboardHeight == 0.0 ? viewInsets.bottom : keyboardHeight; + if (keyboardHeight != 0) { + emoteHeight = keyboardHeight; + } }); } } @@ -79,6 +83,23 @@ class _WhisperDetailPageState extends State super.dispose(); } + void onChooseEmote(PackageItem package, Emote emote) { + _whisperDetailController.emoteList.add( + {'text': emote.text, 'url': emote.url}, + ); + final int cursorPosition = + max(_replyContentController.selection.baseOffset, 0); + final String currentText = _replyContentController.text; + final String newText = currentText.substring(0, cursorPosition) + + emote.text! + + currentText.substring(cursorPosition); + _replyContentController.value = TextEditingValue( + text: newText, + selection: + TextSelection.collapsed(offset: cursorPosition + emote.text!.length), + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -88,30 +109,20 @@ class _WhisperDetailPageState extends State width: double.infinity, height: 50, child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SizedBox( width: 34, height: 34, child: IconButton( - style: ButtonStyle( - padding: MaterialStateProperty.all(EdgeInsets.zero), - backgroundColor: MaterialStateProperty.resolveWith( - (Set states) { - return Theme.of(context) - .colorScheme - .primaryContainer - .withOpacity(0.6); - }), - ), onPressed: () => Get.back(), icon: Icon( - Icons.arrow_back_outlined, + Icons.arrow_back_ios, size: 18, color: Theme.of(context).colorScheme.onPrimaryContainer, ), ), ), + const SizedBox(width: 10), GestureDetector( onTap: () { feedBack(); @@ -125,11 +136,14 @@ class _WhisperDetailPageState extends State }, child: Row( children: [ - NetworkImgLayer( - width: 34, - height: 34, - type: 'avatar', - src: _whisperDetailController.face, + Hero( + tag: _whisperDetailController.heroTag, + child: NetworkImgLayer( + width: 34, + height: 34, + type: 'avatar', + src: _whisperDetailController.face, + ), ), const SizedBox(width: 6), Text( @@ -143,155 +157,169 @@ class _WhisperDetailPageState extends State ], ), ), - ), - body: GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); - setState(() { - keyboardHeight = 0; - }); - }, - child: FutureBuilder( - future: _futureBuilderFuture, - builder: (BuildContext context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.data == null) { - return const SizedBox(); - } - final Map data = snapshot.data as Map; - if (data['status']) { - List messageList = _whisperDetailController.messageList; - return Obx( - () => messageList.isEmpty - ? const SizedBox() - : ListView.builder( - itemCount: messageList.length, - shrinkWrap: true, - reverse: true, - itemBuilder: (_, int i) { - if (i == 0) { - return Column( - children: [ - ChatItem( - item: messageList[i], - e_infos: _whisperDetailController.eInfos), - const SizedBox(height: 12), - ], - ); - } else { - return ChatItem( - item: messageList[i], - e_infos: _whisperDetailController.eInfos); - } - }, - ), - ); - } else { - // 请求错误 - return const SizedBox(); - } - } else { - // 骨架屏 - return const SizedBox(); - } - }, - ), - ), - // resizeToAvoidBottomInset: true, - bottomNavigationBar: Container( - width: double.infinity, - height: MediaQuery.of(context).padding.bottom + 70 + keyboardHeight, - padding: EdgeInsets.only( - left: 8, - right: 12, - top: 12, - bottom: MediaQuery.of(context).padding.bottom, - ), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - width: 4, - color: Theme.of(context).colorScheme.primary.withOpacity(0.1), + actions: [ + IconButton( + onPressed: () {}, + icon: const Icon( + Icons.more_vert_outlined, + size: 20, ), ), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // IconButton( - // onPressed: () {}, - // icon: Icon( - // Icons.add_circle_outline, - // color: Theme.of(context).colorScheme.outline, - // ), - // ), - IconButton( - onPressed: () { - // if (toolbarType == 'input') { - // setState(() { - // toolbarType = 'emote'; - // }); - // } - // FocusScope.of(context).unfocus(); - }, - icon: Icon( - Icons.emoji_emotions_outlined, - color: Theme.of(context).colorScheme.outline, + const SizedBox(width: 14) + ], + ), + body: Column( + children: [ + Expanded( + child: GestureDetector( + onTap: () { + FocusScope.of(context).unfocus(); + toolbarType.value = ''; + }, + child: FutureBuilder( + future: _futureBuilderFuture, + builder: (BuildContext context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.data == null) { + return const SizedBox(); + } + final Map data = snapshot.data as Map; + if (data['status']) { + List messageList = _whisperDetailController.messageList; + return Obx( + () => messageList.isEmpty + ? const SizedBox() + : Align( + alignment: Alignment.topCenter, + child: ListView.builder( + itemCount: messageList.length, + shrinkWrap: true, + reverse: true, + itemBuilder: (_, int i) { + if (i == 0) { + return Column( + children: [ + ChatItem( + item: messageList[i], + e_infos: _whisperDetailController + .eInfos), + const SizedBox(height: 20), + ], + ); + } else { + return ChatItem( + item: messageList[i], + e_infos: + _whisperDetailController.eInfos); + } + }, + ), + ), + ); + } else { + // 请求错误 + return const SizedBox(); + } + } else { + // 骨架屏 + return const SizedBox(); + } + }, + ), + ), + ), + Obx( + () => Container( + padding: EdgeInsets.fromLTRB( + 8, + 12, + 12, + toolbarType.value == '' + ? MediaQuery.of(context).padding.bottom + 6 + : 6, + ), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: 1, + color: Colors.grey.withOpacity(0.15), ), ), - Expanded( - child: Container( - height: 45, - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .primary - .withOpacity(0.08), - borderRadius: BorderRadius.circular(40.0), - ), - child: TextField( - readOnly: true, - style: Theme.of(context).textTheme.titleMedium, - controller: _replyContentController, - autofocus: false, - focusNode: replyContentFocusNode, - decoration: const InputDecoration( - border: InputBorder.none, // 移除默认边框 - hintText: '开发中 ...', // 提示文本 - contentPadding: EdgeInsets.symmetric( - horizontal: 16.0, vertical: 12.0), // 内边距 + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ToolbarIconButton( + onPressed: () { + if (toolbarType.value == '') { + toolbarType.value = 'emote'; + } else if (toolbarType.value == 'input') { + FocusScope.of(context).unfocus(); + toolbarType.value = 'emote'; + } else if (toolbarType.value == 'emote') { + FocusScope.of(context).requestFocus(); + } + }, + icon: const Icon(Icons.emoji_emotions_outlined, size: 22), + toolbarType: toolbarType.value, + selected: false, + ), + const SizedBox(width: 4), + Expanded( + child: Container( + height: 45, + decoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .outline + .withOpacity(0.05), + borderRadius: BorderRadius.circular(40.0), + ), + child: TextField( + style: Theme.of(context).textTheme.titleMedium, + controller: _replyContentController, + autofocus: false, + focusNode: replyContentFocusNode, + decoration: const InputDecoration( + border: InputBorder.none, // 移除默认边框 + hintText: '文明发言 ~', // 提示文本 + contentPadding: EdgeInsets.symmetric( + horizontal: 16.0, vertical: 12.0), // 内边距 + ), ), ), ), - ), - IconButton( - // onPressed: _whisperDetailController.sendMsg, - onPressed: null, - icon: Icon( - Icons.send, - color: Theme.of(context).colorScheme.outline, + IconButton( + onPressed: _whisperDetailController.sendMsg, + icon: Icon( + Icons.send, + color: Theme.of(context).colorScheme.outline, + ), ), - ), - // const SizedBox(width: 16), - ], + ], + ), ), - AnimatedSize( - curve: Curves.easeInOut, - duration: const Duration(milliseconds: 300), + ), + Obx( + () => AnimatedSize( + curve: Curves.linear, + duration: const Duration(milliseconds: 200), child: SizedBox( width: double.infinity, - height: toolbarType == 'input' ? keyboardHeight : emoteHeight, + height: toolbarType.value == 'input' + ? keyboardHeight + : toolbarType.value == 'emote' + ? emoteHeight + : 0, child: EmotePanel( - onChoose: (package, emote) => {}, + onChoose: (package, emote) => onChooseEmote(package, emote), ), ), ), - ], - ), + ), + ], ), + resizeToAvoidBottomInset: false, ); } } diff --git a/lib/pages/whisper_detail/widget/chat_item.dart b/lib/pages/whisper_detail/widget/chat_item.dart index 0d37e8b3..c0d87221 100644 --- a/lib/pages/whisper_detail/widget/chat_item.dart +++ b/lib/pages/whisper_detail/widget/chat_item.dart @@ -1,7 +1,6 @@ // ignore_for_file: must_be_immutable import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -69,9 +68,13 @@ class ChatItem extends StatelessWidget { Color textColor(BuildContext context) { return isOwner ? Theme.of(context).colorScheme.onPrimary - : Theme.of(context).colorScheme.onSecondaryContainer; + : Theme.of(context).colorScheme.onBackground; } + const double safeDistanceval = 6; + const double borderRadiusVal = 12; + const double paddingVal = 10; + Widget richTextMessage(BuildContext context) { var text = content['content']; if (e_infos != null) { @@ -386,73 +389,98 @@ class ChatItem extends StatelessWidget { ? messageContent(context) : isRevoke ? const SizedBox() - : Row( - children: [ - if (!isOwner) const SizedBox(width: 12), - if (isOwner) const Spacer(), - Container( - constraints: const BoxConstraints( - maxWidth: 300.0, // 设置最大宽度为200.0 - ), - decoration: BoxDecoration( - color: isOwner - ? Theme.of(context).colorScheme.primary - : Theme.of(context).colorScheme.secondaryContainer, - borderRadius: BorderRadius.only( - topLeft: const Radius.circular(16), - topRight: const Radius.circular(16), - bottomLeft: Radius.circular(isOwner ? 16 : 6), - bottomRight: Radius.circular(isOwner ? 6 : 16), + : Padding( + padding: const EdgeInsets.only(top: 12), + child: Row( + mainAxisAlignment: !isOwner + ? MainAxisAlignment.start + : MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(width: safeDistanceval), + if (isOwner) + Text( + Utils.dateFormat(item.timestamp), + style: Theme.of(context).textTheme.labelSmall!.copyWith( + color: Theme.of(context).colorScheme.outline), ), + Container( + constraints: const BoxConstraints( + maxWidth: 300.0, // 设置最大宽度为200.0 + ), + decoration: BoxDecoration( + color: isOwner + ? Theme.of(context) + .colorScheme + .primary + .withAlpha(180) + : Theme.of(context) + .colorScheme + .outlineVariant + .withOpacity(0.6) + .withAlpha(125), + borderRadius: BorderRadius.only( + topLeft: const Radius.circular(borderRadiusVal), + topRight: const Radius.circular(borderRadiusVal), + bottomLeft: + Radius.circular(isOwner ? borderRadiusVal : 2), + bottomRight: + Radius.circular(isOwner ? 2 : borderRadiusVal), + ), + ), + margin: const EdgeInsets.only( + left: 8, + right: 8, + ), + padding: const EdgeInsets.all(paddingVal), + child: messageContent(context), + // child: Column( + // crossAxisAlignment: isOwner + // ? CrossAxisAlignment.end + // : CrossAxisAlignment.start, + // children: [ + // messageContent(context), + // SizedBox(height: isPic ? 7 : 2), + // Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Text( + // Utils.dateFormat(item.timestamp), + // style: Theme.of(context) + // .textTheme + // .labelSmall! + // .copyWith( + // color: isOwner + // ? Theme.of(context) + // .colorScheme + // .onPrimary + // .withOpacity(0.8) + // : Theme.of(context) + // .colorScheme + // .onSecondaryContainer + // .withOpacity(0.8)), + // ), + // item.msgStatus == 1 + // ? Text( + // ' 已撤回', + // style: + // Theme.of(context).textTheme.labelSmall!, + // ) + // : const SizedBox() + // ], + // ) + // ], + // ), ), - margin: const EdgeInsets.only(top: 12), - padding: EdgeInsets.only( - top: 8, - bottom: 6, - left: isPic ? 8 : 12, - right: isPic ? 8 : 12, - ), - child: Column( - crossAxisAlignment: isOwner - ? CrossAxisAlignment.end - : CrossAxisAlignment.start, - children: [ - messageContent(context), - SizedBox(height: isPic ? 7 : 2), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - Utils.dateFormat(item.timestamp), - style: Theme.of(context) - .textTheme - .labelSmall! - .copyWith( - color: isOwner - ? Theme.of(context) - .colorScheme - .onPrimary - .withOpacity(0.8) - : Theme.of(context) - .colorScheme - .onSecondaryContainer - .withOpacity(0.8)), - ), - item.msgStatus == 1 - ? Text( - ' 已撤回', - style: - Theme.of(context).textTheme.labelSmall!, - ) - : const SizedBox() - ], - ) - ], - ), - ), - if (!isOwner) const Spacer(), - if (isOwner) const SizedBox(width: 12), - ], + if (!isOwner) + Text( + Utils.dateFormat(item.timestamp), + style: Theme.of(context).textTheme.labelSmall!.copyWith( + color: Theme.of(context).colorScheme.outline), + ), + const SizedBox(width: safeDistanceval), + ], + ), ); } }