fix the response view

This commit is contained in:
otsmr 2026-06-07 12:44:57 +02:00
parent b49b9cf452
commit f66e1f17bf
3 changed files with 180 additions and 229 deletions

View file

@ -31,23 +31,13 @@ class ChatAudioEntry extends StatelessWidget {
return Container(); // media file was purged return Container(); // media file was purged
} }
return LayoutBuilder( final showTime = info.displayTime || message.modifiedAt != null;
builder: (context, constraints) {
final textWidth = measureTextWidth(info.text);
const timeWidth = 60.0;
final isExpanded =
info.expanded ||
(textWidth + timeWidth + 20 > constraints.maxWidth);
final effectiveSpacerWidth =
constraints.minWidth - textWidth - timeWidth;
final spacerWidth = effectiveSpacerWidth > 0
? effectiveSpacerWidth
: 0.0;
return Container( return IntrinsicWidth(
child: Container(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.8, maxWidth: MediaQuery.of(context).size.width * 0.8,
minWidth: 250, minWidth: 280,
), ),
padding: info.padding, padding: info.padding,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -56,9 +46,12 @@ class ChatAudioEntry extends StatelessWidget {
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [ children: [
if (info.displayUserName != '') if (info.displayUserName != '')
Text( Padding(
padding: const EdgeInsets.only(bottom: 2),
child: Text(
info.displayUserName, info.displayUserName,
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: const TextStyle( style: const TextStyle(
@ -66,42 +59,37 @@ class ChatAudioEntry extends StatelessWidget {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
),
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
if (isExpanded && info.text != '') if (info.text != '')
Expanded( Expanded(
child: BetterText( child: BetterText(
text: info.text, text: info.text,
textColor: info.textColor, textColor: info.textColor,
), ),
) )
else if (info.text != '') ...[ else
BetterText(text: info.text, textColor: info.textColor), Expanded(
SizedBox(width: spacerWidth), child: mediaService.mediaFile.downloadState ==
] else ...[
if (mediaService.mediaFile.downloadState ==
DownloadState.ready || DownloadState.ready ||
mediaService.mediaFile.downloadState == null) mediaService.mediaFile.downloadState == null
mediaService.tempPath.existsSync() ? (mediaService.tempPath.existsSync()
? InChatAudioPlayer( ? InChatAudioPlayer(
path: mediaService.tempPath.path, path: mediaService.tempPath.path,
message: message, message: message,
) )
: Container() : Container())
else : MessageSendStateIcon([message], [mediaService.mediaFile]),
MessageSendStateIcon([message], [mediaService.mediaFile]), ),
SizedBox(width: spacerWidth), if (showTime) FriendlyMessageTime(message: message),
],
if (info.displayTime || message.modifiedAt != null)
FriendlyMessageTime(message: message),
], ],
), ),
], ],
), ),
); ),
},
); );
} }
} }

View file

@ -34,20 +34,10 @@ class ChatTextEntry extends StatelessWidget {
); );
} }
return LayoutBuilder( final showTime = info.displayTime || message.modifiedAt != null;
builder: (context, constraints) {
final textWidth = measureTextWidth(info.text);
const timeWidth = 60.0;
final isExpanded =
info.expanded ||
(textWidth + timeWidth + 20 > constraints.maxWidth);
final effectiveSpacerWidth =
constraints.minWidth - textWidth - timeWidth;
final spacerWidth = effectiveSpacerWidth > 0
? effectiveSpacerWidth
: 0.0;
return Container( return IntrinsicWidth(
child: Container(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.8, maxWidth: MediaQuery.of(context).size.width * 0.8,
minWidth: info.minWidth, minWidth: info.minWidth,
@ -59,9 +49,12 @@ class ChatTextEntry extends StatelessWidget {
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [ children: [
if (info.displayUserName != '') if (info.displayUserName != '')
Text( Padding(
padding: const EdgeInsets.only(bottom: 2),
child: Text(
info.displayUserName, info.displayUserName,
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: const TextStyle( style: const TextStyle(
@ -69,31 +62,23 @@ class ChatTextEntry extends StatelessWidget {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
),
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
if (isExpanded)
Expanded( Expanded(
child: BetterText( child: BetterText(
text: info.text, text: info.text,
textColor: info.textColor, textColor: info.textColor,
), ),
)
else ...[
BetterText(text: info.text, textColor: info.textColor),
SizedBox(
width: spacerWidth,
), ),
], if (showTime) FriendlyMessageTime(message: message),
if (info.displayTime || message.modifiedAt != null)
FriendlyMessageTime(message: message),
], ],
), ),
], ],
), ),
); ),
},
); );
} }
} }

View file

@ -9,7 +9,7 @@ import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/visual/views/chats/chat_messages.view.dart'; import 'package:twonly/src/visual/views/chats/chat_messages.view.dart';
class ResponseContainer extends StatefulWidget { class ResponseContainer extends StatelessWidget {
const ResponseContainer({ const ResponseContainer({
required this.msg, required this.msg,
required this.group, required this.group,
@ -27,64 +27,34 @@ class ResponseContainer extends StatefulWidget {
final BorderRadius borderRadius; final BorderRadius borderRadius;
final void Function(String)? scrollToMessage; final void Function(String)? scrollToMessage;
@override
State<ResponseContainer> createState() => _ResponseContainerState();
}
class _ResponseContainerState extends State<ResponseContainer> {
double? minWidth;
final GlobalKey _message = GlobalKey();
final GlobalKey _preview = GlobalKey();
@override
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((_) {
final messageBox =
_message.currentContext?.findRenderObject() as RenderBox?;
final previewBox =
_preview.currentContext?.findRenderObject() as RenderBox?;
if (messageBox == null || previewBox == null) {
return;
}
setState(() {
if (messageBox.size.width > previewBox.size.width) {
minWidth = messageBox.size.width;
} else {
minWidth = previewBox.size.width;
}
});
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (widget.msg.quotesMessageId == null) { if (msg.quotesMessageId == null) {
if (widget.child == null) { if (child == null) {
return Container(); return Container();
} }
return widget.child!; return child!;
} }
return GestureDetector( return GestureDetector(
onTap: widget.scrollToMessage == null onTap: scrollToMessage == null
? null ? null
: () => widget.scrollToMessage!(widget.msg.quotesMessageId!), : () => scrollToMessage!(msg.quotesMessageId!),
child: Container( child: Container(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.8, maxWidth: MediaQuery.of(context).size.width * 0.8,
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: getMessageColor(widget.msg.senderId != null), color: getMessageColor(msg.senderId != null),
borderRadius: widget.borderRadius, borderRadius: borderRadius,
), ),
child: IntrinsicWidth(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Padding( Padding(
key: _preview,
padding: const EdgeInsets.only(top: 4, right: 4, left: 4), padding: const EdgeInsets.only(top: 4, right: 4, left: 4),
child: Container( child: Container(
width: minWidth,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.color.surface.withAlpha(150), color: context.color.surface.withAlpha(150),
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
@ -95,20 +65,19 @@ class _ResponseContainerState extends State<ResponseContainer> {
), ),
), ),
child: ResponsePreview( child: ResponsePreview(
group: widget.group, group: group,
messageId: widget.msg.quotesMessageId, messageId: msg.quotesMessageId,
showBorder: false, showBorder: false,
showLeftBorder: false,
colorUsername: false,
), ),
), ),
), ),
SizedBox( if (child != null) child!,
key: _message,
width: minWidth,
child: widget.child,
),
], ],
), ),
), ),
),
); );
} }
} }
@ -119,6 +88,8 @@ class ResponsePreview extends StatefulWidget {
required this.showBorder, required this.showBorder,
this.message, this.message,
this.messageId, this.messageId,
this.showLeftBorder = true,
this.colorUsername = false,
super.key, super.key,
}); });
@ -126,6 +97,8 @@ class ResponsePreview extends StatefulWidget {
final String? messageId; final String? messageId;
final Group group; final Group group;
final bool showBorder; final bool showBorder;
final bool showLeftBorder;
final bool colorUsername;
@override @override
State<ResponsePreview> createState() => _ResponsePreviewState(); State<ResponsePreview> createState() => _ResponsePreviewState();
@ -212,80 +185,85 @@ class _ResponsePreviewState extends State<ResponsePreview> {
if (_message!.senderId == null) { if (_message!.senderId == null) {
_username = context.lang.you; _username = context.lang.you;
// _username = _message!.senderId.toString();
} }
color = getMessageColor(_message!.senderId != null); color = getMessageColor(_message!.senderId != null);
if (!_message!.mediaStored) {
return Container(
padding: widget.showBorder
? const EdgeInsets.only(left: 10, right: 10)
: const EdgeInsets.symmetric(horizontal: 5),
decoration: (widget.showBorder)
? BoxDecoration(
border: Border(
left: BorderSide(
color: color,
width: 2,
),
),
)
: null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_username,
style: const TextStyle(fontWeight: FontWeight.bold),
),
if (subtitle != null) Text(subtitle),
],
),
);
}
} }
return Container( final hasImage =
padding: const EdgeInsets.only(left: 10), _message != null &&
width: 200, _message!.mediaStored &&
decoration: BoxDecoration( _mediaService != null &&
border: Border( _mediaService!.mediaFile.type != MediaType.audio;
left: BorderSide(
color: color, Widget? imageWidget;
width: 2, if (hasImage) {
),
),
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_username,
style: const TextStyle(fontWeight: FontWeight.bold),
),
if (subtitle != null) Text(subtitle),
],
),
),
if (_mediaService != null &&
_mediaService!.mediaFile.type != MediaType.audio)
() {
final isVideo = _mediaService!.mediaFile.type == MediaType.video; final isVideo = _mediaService!.mediaFile.type == MediaType.video;
final pathToCheck = isVideo final pathToCheck = isVideo
? _mediaService!.thumbnailPath ? _mediaService!.thumbnailPath
: _mediaService!.storedPath; : _mediaService!.storedPath;
if (pathToCheck.existsSync() && pathToCheck.lengthSync() > 0) { if (pathToCheck.existsSync() && pathToCheck.lengthSync() > 0) {
return SizedBox( imageWidget = Container(
height: widget.showBorder ? 100 : 210, height: 40,
child: Image.file(pathToCheck), width: 40,
margin: const EdgeInsets.only(left: 8),
child: ClipRRect(
borderRadius: BorderRadius.circular(4),
child: Image.file(
pathToCheck,
fit: BoxFit.cover,
),
),
); );
} }
return const SizedBox.shrink(); }
}(),
return Container(
padding: EdgeInsets.only(
left: widget.showLeftBorder ? 8 : 4,
right: 6,
top: 4,
bottom: 4,
),
constraints: BoxConstraints(
minWidth: 60,
maxWidth: MediaQuery.of(context).size.width * 0.7,
),
decoration: widget.showLeftBorder
? BoxDecoration(
border: Border(
left: BorderSide(
color: color,
width: 2.5,
),
),
)
: null,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
_username,
style: TextStyle(
fontWeight: FontWeight.bold,
color: widget.colorUsername ? color : null,
),
),
if (subtitle != null)
Text(
subtitle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
if (imageWidget != null) imageWidget,
], ],
), ),
); );