better time and status position

This commit is contained in:
Christien Rioux 2025-05-28 13:34:57 -05:00
parent b8eca1161e
commit 8aaca62ea7
5 changed files with 119 additions and 116 deletions

View file

@ -22,7 +22,6 @@ class VcTextMessageWidget extends StatelessWidget {
this.timeStyle, this.timeStyle,
this.showTime = true, this.showTime = true,
this.showStatus = true, this.showStatus = true,
this.timeAndStatusPosition = TimeAndStatusPosition.end,
super.key, super.key,
}); });
@ -63,9 +62,6 @@ class VcTextMessageWidget extends StatelessWidget {
/// for sent messages. /// for sent messages.
final bool showStatus; final bool showStatus;
/// Position of the timestamp and status indicator relative to the text.
final TimeAndStatusPosition timeAndStatusPosition;
bool get _isOnlyEmoji => message.metadata?['isOnlyEmoji'] == true; bool get _isOnlyEmoji => message.metadata?['isOnlyEmoji'] == true;
@override @override
@ -98,7 +94,11 @@ class VcTextMessageWidget extends StatelessWidget {
: textStyle, : textStyle,
); );
return Container( return Column(
crossAxisAlignment:
isSentByMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Container(
padding: _isOnlyEmoji padding: _isOnlyEmoji
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
horizontal: (padding?.horizontal ?? 0) / 2, horizontal: (padding?.horizontal ?? 0) / 2,
@ -111,49 +111,9 @@ class VcTextMessageWidget extends StatelessWidget {
color: backgroundColor, color: backgroundColor,
borderRadius: borderRadius ?? chatTheme.shape, borderRadius: borderRadius ?? chatTheme.shape,
), ),
child: _buildContentBasedOnPosition( child: textContent),
context: context, if (timeAndStatus != null) timeAndStatus,
textContent: textContent, ]);
timeAndStatus: timeAndStatus,
textStyle: textStyle,
),
);
}
Widget _buildContentBasedOnPosition({
required BuildContext context,
required Widget textContent,
TimeAndStatus? timeAndStatus,
TextStyle? textStyle,
}) {
if (timeAndStatus == null) {
return textContent;
}
switch (timeAndStatusPosition) {
case TimeAndStatusPosition.start:
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [textContent, timeAndStatus],
);
case TimeAndStatusPosition.inline:
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(child: textContent),
const SizedBox(width: 4),
timeAndStatus,
],
);
case TimeAndStatusPosition.end:
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [textContent, timeAndStatus],
);
}
} }
Color _resolveBackgroundColor(bool isSentByMe, ScaleChatTheme theme) { Color _resolveBackgroundColor(bool isSentByMe, ScaleChatTheme theme) {
@ -170,11 +130,8 @@ class VcTextMessageWidget extends StatelessWidget {
return receivedTextStyle ?? theme.receivedMessageBodyTextStyle; return receivedTextStyle ?? theme.receivedMessageBodyTextStyle;
} }
TextStyle _resolveTimeStyle(bool isSentByMe, ScaleChatTheme theme) { TextStyle _resolveTimeStyle(bool isSentByMe, ScaleChatTheme theme) =>
final ts = _resolveTextStyle(isSentByMe, theme); theme.timeStyle;
return theme.timeStyle.copyWith(color: ts.color);
}
@override @override
void debugFillProperties(DiagnosticPropertiesBuilder properties) { void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@ -193,9 +150,7 @@ class VcTextMessageWidget extends StatelessWidget {
'receivedTextStyle', receivedTextStyle)) 'receivedTextStyle', receivedTextStyle))
..add(DiagnosticsProperty<TextStyle?>('timeStyle', timeStyle)) ..add(DiagnosticsProperty<TextStyle?>('timeStyle', timeStyle))
..add(DiagnosticsProperty<bool>('showTime', showTime)) ..add(DiagnosticsProperty<bool>('showTime', showTime))
..add(DiagnosticsProperty<bool>('showStatus', showStatus)) ..add(DiagnosticsProperty<bool>('showStatus', showStatus));
..add(EnumProperty<TimeAndStatusPosition>(
'timeAndStatusPosition', timeAndStatusPosition));
} }
} }

View file

@ -261,18 +261,36 @@ class _ChatComponentWidgetState extends State<ChatComponentWidget> {
chatAnimatedListBuilder: (context, itemBuilder) => chatAnimatedListBuilder: (context, itemBuilder) =>
ChatAnimatedListReversed( ChatAnimatedListReversed(
scrollController: _scrollController, scrollController: _scrollController,
messageGroupingTimeoutInSeconds: 60,
itemBuilder: itemBuilder), itemBuilder: itemBuilder),
// Text message builder // Text message builder
textMessageBuilder: (context, message, index) => textMessageBuilder: (context, message, index) {
VcTextMessageWidget( var showTime = true;
if (_chatController.messages.length > 1 &&
index < _chatController.messages.length - 1 &&
message.time != null) {
final nextMessage =
_chatController.messages[index + 1];
if (nextMessage.time != null) {
if (nextMessage.time!
.difference(message.time!)
.inSeconds <
60 &&
nextMessage.authorId == message.authorId) {
showTime = false;
}
}
}
return VcTextMessageWidget(
message: message, message: message,
index: index, index: index,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 12, horizontal: 16) vertical: 12, horizontal: 16)
.scaled(context) .scaled(context),
// showTime: true, showTime: showTime,
// showStatus: true, showStatus: showTime,
), );
},
// Composer builder // Composer builder
composerBuilder: (ctx) => VcComposerWidget( composerBuilder: (ctx) => VcComposerWidget(
autofocus: true, autofocus: true,

View file

@ -56,11 +56,9 @@ class ChatListWidget extends StatelessWidget {
valueMapper: (c) => c.value); valueMapper: (c) => c.value);
final chatListV = context.watch<ChatListCubit>().state; final chatListV = context.watch<ChatListCubit>().state;
return chatListV return chatListV.builder((context, chatList) => SizedBox.expand(
.builder((context, chatList) => SizedBox.expand( child: styledContainer(
child: styledTitleContainer(
context: context, context: context,
title: translate('chat_list.chats'),
child: (chatList.isEmpty) child: (chatList.isEmpty)
? const SizedBox.expand(child: EmptyChatListWidget()) ? const SizedBox.expand(child: EmptyChatListWidget())
: TapRegion( : TapRegion(
@ -77,22 +75,19 @@ class ChatListWidget extends StatelessWidget {
contactMap, contactMap,
); );
case proto.Chat_Kind.group: case proto.Chat_Kind.group:
return const Text( return const Text('group chats not yet supported!');
'group chats not yet supported!');
case proto.Chat_Kind.notSet: case proto.Chat_Kind.notSet:
throw StateError('unknown chat kind'); throw StateError('unknown chat kind');
} }
}, },
filter: (value) => filter: (value) =>
_itemFilter(contactMap, chatList, value), _itemFilter(contactMap, chatList, value),
searchFieldPadding: searchFieldPadding: const EdgeInsets.fromLTRB(0, 0, 0, 4),
const EdgeInsets.fromLTRB(0, 0, 0, 4),
inputDecoration: InputDecoration( inputDecoration: InputDecoration(
labelText: translate('chat_list.search'), labelText: translate('chat_list.search'),
), ),
)).paddingAll(8), )).paddingAll(8),
))) )));
.paddingLTRB(8, 0, 8, 8);
}); });
} }
} }

View file

@ -354,7 +354,10 @@ extension ScaleChatThemeExt on ScaleTheme {
: scheme.primaryScale.calloutText, : scheme.primaryScale.calloutText,
), ),
onlyEmojiFontSize: 64, onlyEmojiFontSize: 64,
timeStyle: textTheme.bodySmall!.copyWith(fontSize: 9), timeStyle: textTheme.bodySmall!.copyWith(fontSize: 9).copyWith(
color: config.preferBorders || config.useVisualIndicators
? scheme.primaryScale.calloutBackground
: scheme.primaryScale.borderText),
receivedMessageBodyTextStyle: textTheme.bodyLarge!.copyWith( receivedMessageBodyTextStyle: textTheme.bodyLarge!.copyWith(
color: config.preferBorders color: config.preferBorders
? scheme.secondaryScale.calloutBackground ? scheme.secondaryScale.calloutBackground

View file

@ -464,6 +464,38 @@ Widget styledTitleContainer({
])); ]));
} }
Widget styledContainer({
required BuildContext context,
required Widget child,
Color? borderColor,
Color? backgroundColor,
}) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
return DecoratedBox(
decoration: ShapeDecoration(
color: borderColor ?? scale.primaryScale.border,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
)),
child: Column(children: [
DecoratedBox(
decoration: ShapeDecoration(
color:
backgroundColor ?? scale.primaryScale.subtleBackground,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
8 * scaleConfig.borderRadiusScale),
)),
child: child)
.paddingAll(4)
.expanded()
]));
}
Widget styledCard({ Widget styledCard({
required BuildContext context, required BuildContext context,
required Widget child, required Widget child,