💄 Optimize chat input a step further

This commit is contained in:
2025-09-27 15:31:57 +08:00
parent b9dc724f0b
commit 1fbaac8d88
3 changed files with 379 additions and 357 deletions

View File

@@ -541,7 +541,10 @@ class ChatRoomScreen extends HookConsumerWidget {
Widget chatMessageListWidget(List<LocalChatMessage> messageList) =>
SuperListView.builder(
listController: listController,
padding: EdgeInsets.symmetric(vertical: 16),
padding: EdgeInsets.only(
top: 16,
bottom: 96 + MediaQuery.of(context).padding.bottom,
),
controller: scrollController,
reverse: true, // Show newest messages at the bottom
itemCount: messageList.length,
@@ -735,17 +738,15 @@ class ChatRoomScreen extends HookConsumerWidget {
),
body: Stack(
children: [
Column(
children: [
Expanded(
// Messages
Positioned.fill(
child: messages.when(
data:
(messageList) =>
messageList.isEmpty
? Center(child: Text('No messages yet'.tr()))
: chatMessageListWidget(messageList),
loading:
() => const Center(child: CircularProgressIndicator()),
loading: () => const Center(child: CircularProgressIndicator()),
error:
(error, _) => ResponseErrorWidget(
error: error,
@@ -753,7 +754,12 @@ class ChatRoomScreen extends HookConsumerWidget {
),
),
),
chatRoom.when(
// Input
Positioned(
bottom: 0,
left: 0,
right: 0,
child: chatRoom.when(
data:
(room) => Column(
mainAxisSize: MainAxisSize.min,
@@ -880,12 +886,12 @@ class ChatRoomScreen extends HookConsumerWidget {
},
attachmentProgress: attachmentProgress.value,
),
Gap(MediaQuery.of(context).padding.bottom),
],
),
error: (_, _) => const SizedBox.shrink(),
loading: () => const SizedBox.shrink(),
),
],
),
Positioned(
left: 0,

View File

@@ -115,9 +115,14 @@ class ChatInput extends HookConsumerWidget {
return KeyEventResult.ignored;
};
return Material(
elevation: 8,
color: Theme.of(context).colorScheme.surface,
return Container(
margin: const EdgeInsets.all(16),
child: Material(
elevation: 2,
color: Theme.of(context).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(32),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
child: Column(
children: [
if (attachments.isNotEmpty)
@@ -151,12 +156,20 @@ class ChatInput extends HookConsumerWidget {
messageForwardingTo != null ||
messageEditingTo != null)
Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(8),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 4,
),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(32),
),
margin: const EdgeInsets.only(
left: 8,
right: 8,
top: 8,
bottom: 4,
),
margin: const EdgeInsets.only(left: 8, right: 8, top: 8),
child: Row(
children: [
Icon(
@@ -181,20 +194,18 @@ class ChatInput extends HookConsumerWidget {
overflow: TextOverflow.ellipsis,
),
),
IconButton(
icon: const Icon(Icons.close, size: 20),
onPressed: onClear,
padding: EdgeInsets.zero,
style: ButtonStyle(
minimumSize: WidgetStatePropertyAll(Size(28, 28)),
SizedBox(
width: 28,
height: 28,
child: InkWell(
onTap: onClear,
child: const Icon(Icons.close, size: 20).center(),
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
child: Row(
Row(
children: [
Row(
mainAxisSize: MainAxisSize.min,
@@ -306,10 +317,11 @@ class ChatInput extends HookConsumerWidget {
onPressed: send,
),
],
).padding(bottom: MediaQuery.of(context).padding.bottom),
),
],
),
),
),
);
}
}

View File

@@ -56,7 +56,7 @@ class MessageContent extends StatelessWidget {
case 'messages.update.links':
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Symbols.edit,
@@ -64,10 +64,11 @@ class MessageContent extends StatelessWidget {
color: Theme.of(
context,
).colorScheme.onSurfaceVariant.withOpacity(0.6),
),
).padding(top: 2),
const Gap(4),
if (item.meta['previous_content'] is String)
PrettyDiffText(
Flexible(
child: PrettyDiffText(
oldText: item.meta['previous_content'],
newText: item.content ?? 'Edited a message',
defaultTextStyle: Theme.of(
@@ -86,6 +87,7 @@ class MessageContent extends StatelessWidget {
context,
).colorScheme.onSurfaceVariant.withOpacity(0.7),
),
),
)
else
Text(
@@ -104,11 +106,13 @@ class MessageContent extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MarkdownTextContent(
Flexible(
child: MarkdownTextContent(
content: item.content ?? '*${item.type} has no content*',
isSelectable: true,
linesMargin: EdgeInsets.zero,
),
),
if (translatedText?.isNotEmpty ?? false)
...([
ConstrainedBox(