mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-07-25 23:45:40 -04:00
better time and status position
This commit is contained in:
parent
b8eca1161e
commit
8aaca62ea7
5 changed files with 119 additions and 116 deletions
|
@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue