mirror of
https://github.com/Iconica-Development/flutter_chat.git
synced 2025-05-18 18:33:49 +02:00
feat: add semantics for texts
This commit is contained in:
parent
6ecf073f15
commit
30fc7b4368
13 changed files with 456 additions and 125 deletions
|
@ -169,6 +169,9 @@ typedef ChatMessageBuilder = Widget? Function(
|
||||||
MessageModel? previousMessage,
|
MessageModel? previousMessage,
|
||||||
UserModel? sender,
|
UserModel? sender,
|
||||||
Function(UserModel sender) onPressSender,
|
Function(UserModel sender) onPressSender,
|
||||||
|
String semanticIdTitle,
|
||||||
|
String semanticIdText,
|
||||||
|
String semanticIdTime,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// The group avatar builder
|
/// The group avatar builder
|
||||||
|
|
|
@ -2,6 +2,7 @@ import "package:cached_network_image/cached_network_image.dart";
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
import "package:chat_repository_interface/chat_repository_interface.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_chat/src/config/chat_builders.dart";
|
import "package:flutter_chat/src/config/chat_builders.dart";
|
||||||
|
import "package:flutter_chat/src/config/chat_semantics.dart";
|
||||||
import "package:flutter_chat/src/config/chat_translations.dart";
|
import "package:flutter_chat/src/config/chat_translations.dart";
|
||||||
|
|
||||||
/// The chat options
|
/// The chat options
|
||||||
|
@ -13,6 +14,7 @@ class ChatOptions {
|
||||||
this.groupChatEnabled = true,
|
this.groupChatEnabled = true,
|
||||||
this.enableLoadingIndicator = true,
|
this.enableLoadingIndicator = true,
|
||||||
this.translations = const ChatTranslations.empty(),
|
this.translations = const ChatTranslations.empty(),
|
||||||
|
this.semantics = const ChatSemantics.standard(),
|
||||||
this.builders = const ChatBuilders(),
|
this.builders = const ChatBuilders(),
|
||||||
this.spacing = const ChatSpacing(),
|
this.spacing = const ChatSpacing(),
|
||||||
this.paginationControls = const ChatPaginationControls(),
|
this.paginationControls = const ChatPaginationControls(),
|
||||||
|
@ -43,6 +45,9 @@ class ChatOptions {
|
||||||
/// [translations] is the chat translations.
|
/// [translations] is the chat translations.
|
||||||
final ChatTranslations translations;
|
final ChatTranslations translations;
|
||||||
|
|
||||||
|
/// [semantics] is the chat semantics.
|
||||||
|
final ChatSemantics semantics;
|
||||||
|
|
||||||
/// [builders] is the chat builders.
|
/// [builders] is the chat builders.
|
||||||
final ChatBuilders builders;
|
final ChatBuilders builders;
|
||||||
|
|
||||||
|
|
124
packages/flutter_chat/lib/src/config/chat_semantics.dart
Normal file
124
packages/flutter_chat/lib/src/config/chat_semantics.dart
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Iconica
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
/// Class that holds all the semantic ids for the chat component view and
|
||||||
|
/// the corresponding userstory
|
||||||
|
class ChatSemantics {
|
||||||
|
/// ChatTranslations constructor where everything is required use this
|
||||||
|
/// if you want to be sure to have all translations specified
|
||||||
|
/// If you just want the default values use the empty constructor
|
||||||
|
/// and optionally override the values with the copyWith method
|
||||||
|
const ChatSemantics({
|
||||||
|
required this.profileTitle,
|
||||||
|
required this.profileDescription,
|
||||||
|
required this.chatUnreadMessages,
|
||||||
|
required this.chatChatTitle,
|
||||||
|
required this.chatNoMessages,
|
||||||
|
required this.newChatGetUsersError,
|
||||||
|
required this.newGroupChatMemberAmount,
|
||||||
|
required this.newGroupChatGetUsersError,
|
||||||
|
required this.newChatUserListUserFullName,
|
||||||
|
required this.chatBubbleTitle,
|
||||||
|
required this.chatBubbleTime,
|
||||||
|
required this.chatBubbleText,
|
||||||
|
required this.chatsChatTitle,
|
||||||
|
required this.chatsChatSubTitle,
|
||||||
|
required this.chatsChatLastUsed,
|
||||||
|
required this.chatsChatUnreadMessages,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Default translations for the chat component view
|
||||||
|
const ChatSemantics.standard({
|
||||||
|
this.profileTitle = "text_profile_title",
|
||||||
|
this.profileDescription = "text_profile_description",
|
||||||
|
this.chatUnreadMessages = "text_unread_messages",
|
||||||
|
this.chatChatTitle = "text_chat_title",
|
||||||
|
this.chatNoMessages = "text_no_messages",
|
||||||
|
this.newChatGetUsersError = "text_get_users_error",
|
||||||
|
this.newGroupChatMemberAmount = "text_member_amount",
|
||||||
|
this.newGroupChatGetUsersError = "text_get_users_error",
|
||||||
|
this.newChatUserListUserFullName = _defaultNewChatUserListUserFullName,
|
||||||
|
this.chatBubbleTitle = _defaultChatBubbleTitle,
|
||||||
|
this.chatBubbleTime = _defaultChatBubbleTime,
|
||||||
|
this.chatBubbleText = _defaultChatBubbleText,
|
||||||
|
this.chatsChatTitle = _defaultChatsChatTitle,
|
||||||
|
this.chatsChatSubTitle = _defaultChatsChatSubTitle,
|
||||||
|
this.chatsChatLastUsed = _defaultChatsChatLastUsed,
|
||||||
|
this.chatsChatUnreadMessages = _defaultChatsChatUnreadMessages,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Text
|
||||||
|
final String profileTitle;
|
||||||
|
final String profileDescription;
|
||||||
|
final String chatUnreadMessages;
|
||||||
|
final String chatChatTitle;
|
||||||
|
final String chatNoMessages;
|
||||||
|
final String newChatGetUsersError;
|
||||||
|
final String newGroupChatMemberAmount;
|
||||||
|
final String newGroupChatGetUsersError;
|
||||||
|
|
||||||
|
// Indexed text
|
||||||
|
final String Function(int index) newChatUserListUserFullName;
|
||||||
|
final String Function(int index) chatBubbleTitle;
|
||||||
|
final String Function(int index) chatBubbleTime;
|
||||||
|
final String Function(int index) chatBubbleText;
|
||||||
|
final String Function(int index) chatsChatTitle;
|
||||||
|
final String Function(int index) chatsChatSubTitle;
|
||||||
|
final String Function(int index) chatsChatLastUsed;
|
||||||
|
final String Function(int index) chatsChatUnreadMessages;
|
||||||
|
|
||||||
|
ChatSemantics copyWith({
|
||||||
|
String? profileTitle,
|
||||||
|
String? profileDescription,
|
||||||
|
String? chatUnreadMessages,
|
||||||
|
String? chatChatTitle,
|
||||||
|
String? chatNoMessages,
|
||||||
|
String? newChatGetUsersError,
|
||||||
|
String? newGroupChatMemberAmount,
|
||||||
|
String? newGroupChatGetUsersError,
|
||||||
|
String Function(int)? newChatUserListUserFullName,
|
||||||
|
String Function(int)? chatBubbleTitle,
|
||||||
|
String Function(int)? chatBubbleTime,
|
||||||
|
String Function(int)? chatBubbleText,
|
||||||
|
String Function(int)? chatsChatTitle,
|
||||||
|
String Function(int)? chatsChatSubTitle,
|
||||||
|
String Function(int)? chatsChatLastUsed,
|
||||||
|
String Function(int)? chatsChatUnreadMessages,
|
||||||
|
}) =>
|
||||||
|
ChatSemantics(
|
||||||
|
profileTitle: profileTitle ?? this.profileTitle,
|
||||||
|
profileDescription: profileDescription ?? this.profileDescription,
|
||||||
|
chatUnreadMessages: chatUnreadMessages ?? this.chatUnreadMessages,
|
||||||
|
chatChatTitle: chatChatTitle ?? this.chatChatTitle,
|
||||||
|
chatNoMessages: chatNoMessages ?? this.chatNoMessages,
|
||||||
|
newChatGetUsersError: newChatGetUsersError ?? this.newChatGetUsersError,
|
||||||
|
newGroupChatMemberAmount:
|
||||||
|
newGroupChatMemberAmount ?? this.newGroupChatMemberAmount,
|
||||||
|
newGroupChatGetUsersError:
|
||||||
|
newGroupChatGetUsersError ?? this.newGroupChatGetUsersError,
|
||||||
|
newChatUserListUserFullName:
|
||||||
|
newChatUserListUserFullName ?? this.newChatUserListUserFullName,
|
||||||
|
chatBubbleTitle: chatBubbleTitle ?? this.chatBubbleTitle,
|
||||||
|
chatBubbleTime: chatBubbleTime ?? this.chatBubbleTime,
|
||||||
|
chatBubbleText: chatBubbleText ?? this.chatBubbleText,
|
||||||
|
chatsChatTitle: chatsChatTitle ?? this.chatsChatTitle,
|
||||||
|
chatsChatSubTitle: chatsChatSubTitle ?? this.chatsChatSubTitle,
|
||||||
|
chatsChatLastUsed: chatsChatLastUsed ?? this.chatsChatLastUsed,
|
||||||
|
chatsChatUnreadMessages:
|
||||||
|
chatsChatUnreadMessages ?? this.chatsChatUnreadMessages,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _defaultNewChatUserListUserFullName(int index) =>
|
||||||
|
"text_user_fullname_$index";
|
||||||
|
String _defaultChatBubbleTitle(int index) => "text_chat_bubble_title_$index";
|
||||||
|
String _defaultChatBubbleTime(int index) => "text_chat_bubble_time_$index";
|
||||||
|
String _defaultChatBubbleText(int index) => "text_chat_bubble_text_$index";
|
||||||
|
String _defaultChatsChatTitle(int index) => "text_chat_title_$index";
|
||||||
|
String _defaultChatsChatSubTitle(int index) => "text_chat_sub_title_$index";
|
||||||
|
String _defaultChatsChatLastUsed(int index) => "text_chat_last_used_$index";
|
||||||
|
String _defaultChatsChatUnreadMessages(int index) =>
|
||||||
|
"text_chat_unread_messages_$index";
|
|
@ -1,6 +1,7 @@
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
|
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/flutter_chat.dart";
|
import "package:flutter_chat/flutter_chat.dart";
|
||||||
|
|
||||||
/// A widget representing an entry point for a chat UI.
|
/// A widget representing an entry point for a chat UI.
|
||||||
|
@ -16,6 +17,7 @@ class FlutterChatEntryWidget extends StatefulWidget {
|
||||||
this.iconColor = Colors.black,
|
this.iconColor = Colors.black,
|
||||||
this.counterBackgroundColor = Colors.red,
|
this.counterBackgroundColor = Colors.red,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
|
this.semanticIdUnreadMessages = "text_unread_messages_count",
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -46,6 +48,9 @@ class FlutterChatEntryWidget extends StatefulWidget {
|
||||||
/// The chat options
|
/// The chat options
|
||||||
final ChatOptions? options;
|
final ChatOptions? options;
|
||||||
|
|
||||||
|
/// Semantic Id for the unread messages text
|
||||||
|
final String semanticIdUnreadMessages;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<FlutterChatEntryWidget> createState() => _FlutterChatEntryWidgetState();
|
State<FlutterChatEntryWidget> createState() => _FlutterChatEntryWidgetState();
|
||||||
}
|
}
|
||||||
|
@ -121,9 +126,13 @@ class _FlutterChatEntryWidgetState extends State<FlutterChatEntryWidget> {
|
||||||
color: widget.counterBackgroundColor,
|
color: widget.counterBackgroundColor,
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: CustomSemantics(
|
||||||
snapshot.data?.toString() ?? "0",
|
identifier: widget.semanticIdUnreadMessages,
|
||||||
style: widget.textStyle,
|
value: snapshot.data?.toString() ?? "0",
|
||||||
|
child: Text(
|
||||||
|
snapshot.data?.toString() ?? "0",
|
||||||
|
style: widget.textStyle,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,6 +4,7 @@ import "dart:typed_data";
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
import "package:chat_repository_interface/chat_repository_interface.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_chat/src/config/chat_options.dart";
|
import "package:flutter_chat/src/config/chat_options.dart";
|
||||||
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/config/screen_types.dart";
|
import "package:flutter_chat/src/config/screen_types.dart";
|
||||||
import "package:flutter_chat/src/screens/chat_detail/widgets/chat_bottom.dart";
|
import "package:flutter_chat/src/screens/chat_detail/widgets/chat_bottom.dart";
|
||||||
import "package:flutter_chat/src/screens/chat_detail/widgets/chat_widgets.dart";
|
import "package:flutter_chat/src/screens/chat_detail/widgets/chat_widgets.dart";
|
||||||
|
@ -213,11 +214,15 @@ class _ChatAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
highlightColor: Colors.transparent,
|
highlightColor: Colors.transparent,
|
||||||
hoverColor: Colors.transparent,
|
hoverColor: Colors.transparent,
|
||||||
onTap: onPressChatTitle,
|
onTap: onPressChatTitle,
|
||||||
child: options.builders.chatTitleBuilder?.call(chatTitle ?? "") ??
|
child: CustomSemantics(
|
||||||
Text(
|
identifier: options.semantics.chatChatTitle,
|
||||||
chatTitle ?? "",
|
value: chatTitle ?? "",
|
||||||
overflow: TextOverflow.ellipsis,
|
child: options.builders.chatTitleBuilder?.call(chatTitle ?? "") ??
|
||||||
),
|
Text(
|
||||||
|
chatTitle ?? "",
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -458,6 +463,9 @@ class _ChatBody extends HookWidget {
|
||||||
previousMessage: prevMsg,
|
previousMessage: prevMsg,
|
||||||
sender: userMap[msg.senderId],
|
sender: userMap[msg.senderId],
|
||||||
onPressSender: onPressUserProfile,
|
onPressSender: onPressUserProfile,
|
||||||
|
semanticIdTitle: options.semantics.chatBubbleTitle(index),
|
||||||
|
semanticIdTime: options.semantics.chatBubbleTime(index),
|
||||||
|
semanticIdText: options.semantics.chatBubbleText(index),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
import "package:chat_repository_interface/chat_repository_interface.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/screens/chat_detail/widgets/default_message_builder.dart";
|
import "package:flutter_chat/src/screens/chat_detail/widgets/default_message_builder.dart";
|
||||||
import "package:flutter_chat/src/util/scope.dart";
|
import "package:flutter_chat/src/util/scope.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
|
@ -18,15 +19,22 @@ class ChatNoMessages extends HookWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var chatScope = ChatScope.of(context);
|
var chatScope = ChatScope.of(context);
|
||||||
var translations = chatScope.options.translations;
|
var options = chatScope.options;
|
||||||
|
var translations = options.translations;
|
||||||
var theme = Theme.of(context);
|
var theme = Theme.of(context);
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: CustomSemantics(
|
||||||
isGroupChat
|
identifier: options.semantics.chatNoMessages,
|
||||||
|
value: isGroupChat
|
||||||
? translations.writeFirstMessageInGroupChat
|
? translations.writeFirstMessageInGroupChat
|
||||||
: translations.writeMessageToStartChat,
|
: translations.writeMessageToStartChat,
|
||||||
style: theme.textTheme.bodySmall,
|
child: Text(
|
||||||
|
isGroupChat
|
||||||
|
? translations.writeFirstMessageInGroupChat
|
||||||
|
: translations.writeMessageToStartChat,
|
||||||
|
style: theme.textTheme.bodySmall,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +47,9 @@ class ChatBubble extends HookWidget {
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.sender,
|
required this.sender,
|
||||||
required this.onPressSender,
|
required this.onPressSender,
|
||||||
|
required this.semanticIdTitle,
|
||||||
|
required this.semanticIdText,
|
||||||
|
required this.semanticIdTime,
|
||||||
this.previousMessage,
|
this.previousMessage,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
@ -56,6 +67,15 @@ class ChatBubble extends HookWidget {
|
||||||
/// Callback function when a message sender is pressed.
|
/// Callback function when a message sender is pressed.
|
||||||
final Function(UserModel user) onPressSender;
|
final Function(UserModel user) onPressSender;
|
||||||
|
|
||||||
|
/// Semantic id for message title
|
||||||
|
final String semanticIdTitle;
|
||||||
|
|
||||||
|
/// Semantic id for message time
|
||||||
|
final String semanticIdTime;
|
||||||
|
|
||||||
|
/// Semantic id for message text
|
||||||
|
final String semanticIdText;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var chatScope = ChatScope.of(context);
|
var chatScope = ChatScope.of(context);
|
||||||
|
@ -67,12 +87,18 @@ class ChatBubble extends HookWidget {
|
||||||
previousMessage,
|
previousMessage,
|
||||||
sender,
|
sender,
|
||||||
onPressSender,
|
onPressSender,
|
||||||
|
semanticIdTitle,
|
||||||
|
semanticIdTime,
|
||||||
|
semanticIdText,
|
||||||
) ??
|
) ??
|
||||||
DefaultChatMessageBuilder(
|
DefaultChatMessageBuilder(
|
||||||
message: message,
|
message: message,
|
||||||
previousMessage: previousMessage,
|
previousMessage: previousMessage,
|
||||||
sender: sender,
|
sender: sender,
|
||||||
onPressSender: onPressSender,
|
onPressSender: onPressSender,
|
||||||
|
semanticIdTitle: semanticIdTitle,
|
||||||
|
semanticIdTime: semanticIdTime,
|
||||||
|
semanticIdText: semanticIdText,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
import "package:chat_repository_interface/chat_repository_interface.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/config/chat_options.dart";
|
import "package:flutter_chat/src/config/chat_options.dart";
|
||||||
import "package:flutter_chat/src/services/date_formatter.dart";
|
import "package:flutter_chat/src/services/date_formatter.dart";
|
||||||
import "package:flutter_chat/src/util/scope.dart";
|
import "package:flutter_chat/src/util/scope.dart";
|
||||||
|
@ -14,6 +15,9 @@ class DefaultChatMessageBuilder extends StatelessWidget {
|
||||||
required this.previousMessage,
|
required this.previousMessage,
|
||||||
required this.sender,
|
required this.sender,
|
||||||
required this.onPressSender,
|
required this.onPressSender,
|
||||||
|
required this.semanticIdTitle,
|
||||||
|
required this.semanticIdText,
|
||||||
|
required this.semanticIdTime,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -30,6 +34,15 @@ class DefaultChatMessageBuilder extends StatelessWidget {
|
||||||
/// The function that is called when the sender is clicked
|
/// The function that is called when the sender is clicked
|
||||||
final Function(UserModel user) onPressSender;
|
final Function(UserModel user) onPressSender;
|
||||||
|
|
||||||
|
/// Semantic id for message title
|
||||||
|
final String semanticIdTitle;
|
||||||
|
|
||||||
|
/// Semantic id for message time
|
||||||
|
final String semanticIdTime;
|
||||||
|
|
||||||
|
/// Semantic id for message text
|
||||||
|
final String semanticIdText;
|
||||||
|
|
||||||
/// implements [ChatMessageBuilder]
|
/// implements [ChatMessageBuilder]
|
||||||
static Widget builder(
|
static Widget builder(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
@ -37,12 +50,18 @@ class DefaultChatMessageBuilder extends StatelessWidget {
|
||||||
MessageModel? previousMessage,
|
MessageModel? previousMessage,
|
||||||
UserModel? sender,
|
UserModel? sender,
|
||||||
Function(UserModel sender) onPressSender,
|
Function(UserModel sender) onPressSender,
|
||||||
|
String semanticIdTitle,
|
||||||
|
String semanticIdText,
|
||||||
|
String semanticIdTime,
|
||||||
) =>
|
) =>
|
||||||
DefaultChatMessageBuilder(
|
DefaultChatMessageBuilder(
|
||||||
message: message,
|
message: message,
|
||||||
previousMessage: previousMessage,
|
previousMessage: previousMessage,
|
||||||
sender: sender,
|
sender: sender,
|
||||||
onPressSender: onPressSender,
|
onPressSender: onPressSender,
|
||||||
|
semanticIdTitle: semanticIdTitle,
|
||||||
|
semanticIdTime: semanticIdTime,
|
||||||
|
semanticIdText: semanticIdText,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merges the [MessageTheme] from the themeresolver with the [MessageTheme]
|
/// Merges the [MessageTheme] from the themeresolver with the [MessageTheme]
|
||||||
|
@ -87,6 +106,9 @@ class DefaultChatMessageBuilder extends StatelessWidget {
|
||||||
message: message,
|
message: message,
|
||||||
messageTheme: messageTheme,
|
messageTheme: messageTheme,
|
||||||
sender: sender,
|
sender: sender,
|
||||||
|
semanticIdTitle: semanticIdTitle,
|
||||||
|
semanticIdTime: semanticIdTime,
|
||||||
|
semanticIdText: semanticIdText,
|
||||||
);
|
);
|
||||||
|
|
||||||
var messagePadding = messageTheme.messageSidePadding!;
|
var messagePadding = messageTheme.messageSidePadding!;
|
||||||
|
@ -126,6 +148,9 @@ class _ChatMessageBubble extends StatelessWidget {
|
||||||
required this.previousMessage,
|
required this.previousMessage,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
required this.sender,
|
required this.sender,
|
||||||
|
required this.semanticIdTitle,
|
||||||
|
required this.semanticIdTime,
|
||||||
|
required this.semanticIdText,
|
||||||
});
|
});
|
||||||
|
|
||||||
final bool isSameSender;
|
final bool isSameSender;
|
||||||
|
@ -134,6 +159,9 @@ class _ChatMessageBubble extends StatelessWidget {
|
||||||
final MessageModel? previousMessage;
|
final MessageModel? previousMessage;
|
||||||
final MessageTheme messageTheme;
|
final MessageTheme messageTheme;
|
||||||
final UserModel? sender;
|
final UserModel? sender;
|
||||||
|
final String semanticIdTitle;
|
||||||
|
final String semanticIdTime;
|
||||||
|
final String semanticIdText;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -154,9 +182,13 @@ class _ChatMessageBubble extends StatelessWidget {
|
||||||
|
|
||||||
var senderTitle =
|
var senderTitle =
|
||||||
options.senderTitleResolver?.call(sender) ?? sender?.firstName ?? "";
|
options.senderTitleResolver?.call(sender) ?? sender?.firstName ?? "";
|
||||||
var senderTitleText = Text(
|
var senderTitleText = CustomSemantics(
|
||||||
senderTitle,
|
identifier: semanticIdTitle,
|
||||||
style: theme.textTheme.titleMedium,
|
value: senderTitle,
|
||||||
|
child: Text(
|
||||||
|
senderTitle,
|
||||||
|
style: theme.textTheme.titleMedium,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
var messageTimeRow = Row(
|
var messageTimeRow = Row(
|
||||||
|
@ -164,12 +196,16 @@ class _ChatMessageBubble extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 8, bottom: 4),
|
padding: const EdgeInsets.only(right: 8, bottom: 4),
|
||||||
child: Text(
|
child: CustomSemantics(
|
||||||
messageTime,
|
identifier: semanticIdTime,
|
||||||
style: textTheme.bodySmall?.copyWith(
|
value: messageTime,
|
||||||
color: messageTheme.textColor,
|
child: Text(
|
||||||
|
messageTime,
|
||||||
|
style: textTheme.bodySmall?.copyWith(
|
||||||
|
color: messageTheme.textColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.end,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.end,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -207,12 +243,16 @@ class _ChatMessageBubble extends StatelessWidget {
|
||||||
right: 12,
|
right: 12,
|
||||||
bottom: 4,
|
bottom: 4,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Semantics(
|
||||||
message.text!,
|
identifier: semanticIdText,
|
||||||
style: textTheme.bodyLarge?.copyWith(
|
value: message.text,
|
||||||
color: messageTheme.textColor,
|
child: Text(
|
||||||
|
message.text!,
|
||||||
|
style: textTheme.bodyLarge?.copyWith(
|
||||||
|
color: messageTheme.textColor,
|
||||||
|
),
|
||||||
|
textAlign: messageTheme.textAlignment,
|
||||||
),
|
),
|
||||||
textAlign: messageTheme.textAlignment,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -257,6 +297,7 @@ class _DefaultChatImage extends StatelessWidget {
|
||||||
options.imageProviderResolver(context, Uri.parse(imageUrl)),
|
options.imageProviderResolver(context, Uri.parse(imageUrl)),
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
errorBuilder: (context, error, stackTrace) => Text(
|
errorBuilder: (context, error, stackTrace) => Text(
|
||||||
|
// TODO: Non-replaceable text
|
||||||
"Something went wrong with loading the image",
|
"Something went wrong with loading the image",
|
||||||
style: textTheme.bodyLarge?.copyWith(
|
style: textTheme.bodyLarge?.copyWith(
|
||||||
color: messageTheme.textColor,
|
color: messageTheme.textColor,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
import "package:chat_repository_interface/chat_repository_interface.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/config/screen_types.dart";
|
import "package:flutter_chat/src/config/screen_types.dart";
|
||||||
import "package:flutter_chat/src/util/scope.dart";
|
import "package:flutter_chat/src/util/scope.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
|
@ -50,7 +51,10 @@ class ChatProfileScreen extends HookWidget {
|
||||||
? chatModel?.chatName ?? options.translations.groupNameEmpty
|
? chatModel?.chatName ?? options.translations.groupNameEmpty
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
var appBar = _AppBar(title: chatTitle);
|
var appBar = _AppBar(
|
||||||
|
title: chatTitle,
|
||||||
|
semanticId: options.semantics.profileTitle,
|
||||||
|
);
|
||||||
|
|
||||||
var body = _Body(
|
var body = _Body(
|
||||||
user: userModel,
|
user: userModel,
|
||||||
|
@ -79,16 +83,22 @@ class ChatProfileScreen extends HookWidget {
|
||||||
class _AppBar extends StatelessWidget implements PreferredSizeWidget {
|
class _AppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
const _AppBar({
|
const _AppBar({
|
||||||
required this.title,
|
required this.title,
|
||||||
|
required this.semanticId,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
final String semanticId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
var theme = Theme.of(context);
|
||||||
return AppBar(
|
return AppBar(
|
||||||
iconTheme: theme.appBarTheme.iconTheme,
|
iconTheme: theme.appBarTheme.iconTheme,
|
||||||
title: Text(title),
|
title: CustomSemantics(
|
||||||
|
identifier: semanticId,
|
||||||
|
value: title,
|
||||||
|
child: Text(title),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,9 +257,13 @@ class _Body extends StatelessWidget {
|
||||||
style: theme.textTheme.titleMedium,
|
style: theme.textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Text(
|
CustomSemantics(
|
||||||
chat!.description ?? "",
|
identifier: options.semantics.profileDescription,
|
||||||
style: theme.textTheme.bodyMedium,
|
value: chat!.description ?? "",
|
||||||
|
child: Text(
|
||||||
|
chat!.description ?? "",
|
||||||
|
style: theme.textTheme.bodyMedium,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Text(
|
Text(
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
import "package:chat_repository_interface/chat_repository_interface.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/config/chat_translations.dart";
|
import "package:flutter_chat/src/config/chat_translations.dart";
|
||||||
import "package:flutter_chat/src/config/screen_types.dart";
|
import "package:flutter_chat/src/config/screen_types.dart";
|
||||||
import "package:flutter_chat/src/services/date_formatter.dart";
|
import "package:flutter_chat/src/services/date_formatter.dart";
|
||||||
|
@ -92,9 +93,13 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
visible: (snapshot.data ?? 0) > 0,
|
visible: (snapshot.data ?? 0) > 0,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(right: 22.0),
|
padding: const EdgeInsets.only(right: 22.0),
|
||||||
child: Text(
|
child: CustomSemantics(
|
||||||
"${snapshot.data ?? 0} ${translations.chatsUnread}",
|
identifier: options.semantics.chatUnreadMessages,
|
||||||
style: theme.textTheme.bodySmall,
|
value: "${snapshot.data ?? 0} ${translations.chatsUnread}",
|
||||||
|
child: Text(
|
||||||
|
"${snapshot.data ?? 0} ${translations.chatsUnread}",
|
||||||
|
style: theme.textTheme.bodySmall,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -166,7 +171,8 @@ class _BodyState extends State<_Body> {
|
||||||
}
|
}
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
for (ChatModel chat in snapshot.data ?? []) ...[
|
for (var (index, ChatModel chat)
|
||||||
|
in (snapshot.data ?? []).indexed) ...[
|
||||||
DecoratedBox(
|
DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
|
@ -177,66 +183,77 @@ class _BodyState extends State<_Body> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) => !chat.canBeDeleted
|
builder: (context) {
|
||||||
? Dismissible(
|
var semantics = options.semantics;
|
||||||
confirmDismiss: (_) async {
|
|
||||||
await options
|
var chatItem = _ChatItem(
|
||||||
.builders.deleteChatDialogBuilder
|
chat: chat,
|
||||||
?.call(context, chat) ??
|
onPressChat: widget.onPressChat,
|
||||||
_deleteDialog(
|
semanticIdTitle:
|
||||||
chat,
|
semantics.chatsChatTitle(index),
|
||||||
translations,
|
semanticIdSubTitle:
|
||||||
// ignore: use_build_context_synchronously
|
semantics.chatsChatSubTitle(index),
|
||||||
context,
|
semanticIdLastUsed:
|
||||||
);
|
semantics.chatsChatLastUsed(index),
|
||||||
return _deleteDialog(
|
semanticIdUnreadMessages:
|
||||||
chat,
|
semantics.chatsChatUnreadMessages(index),
|
||||||
translations,
|
);
|
||||||
// ignore: use_build_context_synchronously
|
|
||||||
context,
|
return !chat.canBeDeleted
|
||||||
);
|
? Dismissible(
|
||||||
},
|
confirmDismiss: (_) async {
|
||||||
onDismissed: (_) {
|
await options.builders
|
||||||
widget.onDeleteChat(chat);
|
.deleteChatDialogBuilder
|
||||||
},
|
?.call(context, chat) ??
|
||||||
secondaryBackground: const ColoredBox(
|
_deleteDialog(
|
||||||
color: Colors.red,
|
chat,
|
||||||
child: Align(
|
translations,
|
||||||
alignment: Alignment.centerRight,
|
// ignore: use_build_context_synchronously
|
||||||
child: Padding(
|
context,
|
||||||
padding: EdgeInsets.all(8.0),
|
);
|
||||||
child: Icon(
|
return _deleteDialog(
|
||||||
Icons.delete,
|
chat,
|
||||||
color: Colors.white,
|
translations,
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onDismissed: (_) {
|
||||||
|
widget.onDeleteChat(chat);
|
||||||
|
},
|
||||||
|
secondaryBackground: const ColoredBox(
|
||||||
|
color: Colors.red,
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Icon(
|
||||||
|
Icons.delete,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
background: const ColoredBox(
|
||||||
background: const ColoredBox(
|
color: Colors.red,
|
||||||
color: Colors.red,
|
child: Align(
|
||||||
child: Align(
|
alignment: Alignment.centerLeft,
|
||||||
alignment: Alignment.centerLeft,
|
child: Padding(
|
||||||
child: Padding(
|
padding: EdgeInsets.all(8.0),
|
||||||
padding: EdgeInsets.all(8.0),
|
child: Icon(
|
||||||
child: Icon(
|
Icons.delete,
|
||||||
Icons.delete,
|
color: Colors.white,
|
||||||
color: Colors.white,
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
key: ValueKey(
|
||||||
key: ValueKey(
|
chat.id,
|
||||||
chat.id,
|
),
|
||||||
),
|
child: chatItem,
|
||||||
child: _ChatItem(
|
)
|
||||||
chat: chat,
|
: chatItem;
|
||||||
onPressChat: widget.onPressChat,
|
},
|
||||||
),
|
|
||||||
)
|
|
||||||
: _ChatItem(
|
|
||||||
chat: chat,
|
|
||||||
onPressChat: widget.onPressChat,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -282,10 +299,18 @@ class _ChatItem extends StatelessWidget {
|
||||||
const _ChatItem({
|
const _ChatItem({
|
||||||
required this.chat,
|
required this.chat,
|
||||||
required this.onPressChat,
|
required this.onPressChat,
|
||||||
|
required this.semanticIdTitle,
|
||||||
|
required this.semanticIdSubTitle,
|
||||||
|
required this.semanticIdLastUsed,
|
||||||
|
required this.semanticIdUnreadMessages,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ChatModel chat;
|
final ChatModel chat;
|
||||||
final Function(ChatModel chat) onPressChat;
|
final Function(ChatModel chat) onPressChat;
|
||||||
|
final String semanticIdTitle;
|
||||||
|
final String semanticIdSubTitle;
|
||||||
|
final String semanticIdLastUsed;
|
||||||
|
final String semanticIdUnreadMessages;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -295,16 +320,23 @@ class _ChatItem extends StatelessWidget {
|
||||||
options: options,
|
options: options,
|
||||||
);
|
);
|
||||||
var theme = Theme.of(context);
|
var theme = Theme.of(context);
|
||||||
|
|
||||||
|
var chatListItem = _ChatListItem(
|
||||||
|
chat: chat,
|
||||||
|
dateFormatter: dateFormatter,
|
||||||
|
semanticIdTitle: semanticIdTitle,
|
||||||
|
semanticIdSubTitle: semanticIdSubTitle,
|
||||||
|
semanticIdLastUsed: semanticIdLastUsed,
|
||||||
|
semanticIdUnreadMessages: semanticIdUnreadMessages,
|
||||||
|
);
|
||||||
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
onPressChat(chat);
|
onPressChat(chat);
|
||||||
},
|
},
|
||||||
child: options.builders.chatRowContainerBuilder?.call(
|
child: options.builders.chatRowContainerBuilder?.call(
|
||||||
context,
|
context,
|
||||||
_ChatListItem(
|
chatListItem,
|
||||||
chat: chat,
|
|
||||||
dateFormatter: dateFormatter,
|
|
||||||
),
|
|
||||||
) ??
|
) ??
|
||||||
DecoratedBox(
|
DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -318,10 +350,7 @@ class _ChatItem extends StatelessWidget {
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
child: _ChatListItem(
|
child: chatListItem,
|
||||||
chat: chat,
|
|
||||||
dateFormatter: dateFormatter,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -332,10 +361,18 @@ class _ChatListItem extends StatelessWidget {
|
||||||
const _ChatListItem({
|
const _ChatListItem({
|
||||||
required this.chat,
|
required this.chat,
|
||||||
required this.dateFormatter,
|
required this.dateFormatter,
|
||||||
|
required this.semanticIdTitle,
|
||||||
|
required this.semanticIdSubTitle,
|
||||||
|
required this.semanticIdLastUsed,
|
||||||
|
required this.semanticIdUnreadMessages,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ChatModel chat;
|
final ChatModel chat;
|
||||||
final DateFormatter dateFormatter;
|
final DateFormatter dateFormatter;
|
||||||
|
final String semanticIdTitle;
|
||||||
|
final String semanticIdSubTitle;
|
||||||
|
final String semanticIdLastUsed;
|
||||||
|
final String semanticIdUnreadMessages;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -366,6 +403,10 @@ class _ChatListItem extends StatelessWidget {
|
||||||
|
|
||||||
return _ChatRow(
|
return _ChatRow(
|
||||||
title: chat.chatName ?? translations.groupNameEmpty,
|
title: chat.chatName ?? translations.groupNameEmpty,
|
||||||
|
semanticIdTitle: semanticIdTitle,
|
||||||
|
semanticIdSubTitle: semanticIdSubTitle,
|
||||||
|
semanticIdLastUsed: semanticIdLastUsed,
|
||||||
|
semanticIdUnreadMessages: semanticIdUnreadMessages,
|
||||||
unreadMessages:
|
unreadMessages:
|
||||||
showUnreadMessageCount ? chat.unreadMessageCount : 0,
|
showUnreadMessageCount ? chat.unreadMessageCount : 0,
|
||||||
subTitle: data != null
|
subTitle: data != null
|
||||||
|
@ -441,6 +482,10 @@ class _ChatListItem extends StatelessWidget {
|
||||||
return _ChatRow(
|
return _ChatRow(
|
||||||
unreadMessages:
|
unreadMessages:
|
||||||
showUnreadMessageCount ? chat.unreadMessageCount : 0,
|
showUnreadMessageCount ? chat.unreadMessageCount : 0,
|
||||||
|
semanticIdTitle: semanticIdTitle,
|
||||||
|
semanticIdSubTitle: semanticIdSubTitle,
|
||||||
|
semanticIdLastUsed: semanticIdLastUsed,
|
||||||
|
semanticIdUnreadMessages: semanticIdUnreadMessages,
|
||||||
avatar: options.builders.userAvatarBuilder?.call(
|
avatar: options.builders.userAvatarBuilder?.call(
|
||||||
context,
|
context,
|
||||||
otherUser,
|
otherUser,
|
||||||
|
@ -536,6 +581,10 @@ Future<bool?> _deleteDialog(
|
||||||
class _ChatRow extends StatelessWidget {
|
class _ChatRow extends StatelessWidget {
|
||||||
const _ChatRow({
|
const _ChatRow({
|
||||||
required this.title,
|
required this.title,
|
||||||
|
required this.semanticIdTitle,
|
||||||
|
required this.semanticIdSubTitle,
|
||||||
|
required this.semanticIdLastUsed,
|
||||||
|
required this.semanticIdUnreadMessages,
|
||||||
this.unreadMessages = 0,
|
this.unreadMessages = 0,
|
||||||
this.lastUsed,
|
this.lastUsed,
|
||||||
this.subTitle,
|
this.subTitle,
|
||||||
|
@ -544,15 +593,19 @@ class _ChatRow extends StatelessWidget {
|
||||||
|
|
||||||
/// The title of the chat.
|
/// The title of the chat.
|
||||||
final String title;
|
final String title;
|
||||||
|
final String semanticIdTitle;
|
||||||
|
|
||||||
/// The number of unread messages in the chat.
|
/// The number of unread messages in the chat.
|
||||||
final int unreadMessages;
|
final int unreadMessages;
|
||||||
|
final String semanticIdUnreadMessages;
|
||||||
|
|
||||||
/// The last time the chat was used.
|
/// The last time the chat was used.
|
||||||
final String? lastUsed;
|
final String? lastUsed;
|
||||||
|
final String semanticIdLastUsed;
|
||||||
|
|
||||||
/// The subtitle of the chat.
|
/// The subtitle of the chat.
|
||||||
final String? subTitle;
|
final String? subTitle;
|
||||||
|
final String semanticIdSubTitle;
|
||||||
|
|
||||||
/// The avatar associated with the chat.
|
/// The avatar associated with the chat.
|
||||||
final Widget? avatar;
|
final Widget? avatar;
|
||||||
|
@ -573,20 +626,28 @@ class _ChatRow extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
CustomSemantics(
|
||||||
title,
|
identifier: semanticIdTitle,
|
||||||
maxLines: 1,
|
value: title,
|
||||||
overflow: TextOverflow.ellipsis,
|
child: Text(
|
||||||
style: theme.textTheme.titleMedium,
|
title,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: theme.textTheme.titleMedium,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (subTitle != null) ...[
|
if (subTitle != null) ...[
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 3.0),
|
padding: const EdgeInsets.only(top: 3.0),
|
||||||
child: Text(
|
child: CustomSemantics(
|
||||||
subTitle!,
|
identifier: semanticIdSubTitle,
|
||||||
style: theme.textTheme.bodySmall,
|
value: subTitle,
|
||||||
overflow: TextOverflow.ellipsis,
|
child: Text(
|
||||||
maxLines: 2,
|
subTitle!,
|
||||||
|
style: theme.textTheme.bodySmall,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 2,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -601,9 +662,13 @@ class _ChatRow extends StatelessWidget {
|
||||||
if (lastUsed != null) ...[
|
if (lastUsed != null) ...[
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 4.0),
|
padding: const EdgeInsets.only(bottom: 4.0),
|
||||||
child: Text(
|
child: CustomSemantics(
|
||||||
lastUsed!,
|
identifier: semanticIdLastUsed,
|
||||||
style: theme.textTheme.labelSmall,
|
value: lastUsed,
|
||||||
|
child: Text(
|
||||||
|
lastUsed!,
|
||||||
|
style: theme.textTheme.labelSmall,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -616,10 +681,14 @@ class _ChatRow extends StatelessWidget {
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: CustomSemantics(
|
||||||
unreadMessages.toString(),
|
identifier: semanticIdUnreadMessages,
|
||||||
style: const TextStyle(
|
value: unreadMessages.toString(),
|
||||||
fontSize: 14,
|
child: Text(
|
||||||
|
unreadMessages.toString(),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
import "package:chat_repository_interface/chat_repository_interface.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/config/screen_types.dart";
|
import "package:flutter_chat/src/config/screen_types.dart";
|
||||||
import "package:flutter_chat/src/screens/creation/widgets/search_field.dart";
|
import "package:flutter_chat/src/screens/creation/widgets/search_field.dart";
|
||||||
import "package:flutter_chat/src/screens/creation/widgets/search_icon.dart";
|
import "package:flutter_chat/src/screens/creation/widgets/search_icon.dart";
|
||||||
|
@ -211,10 +212,17 @@ class _Body extends StatelessWidget {
|
||||||
// ignore: discarded_futures
|
// ignore: discarded_futures
|
||||||
stream: service.getAllUsers(),
|
stream: service.getAllUsers(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
|
var chatScope = ChatScope.of(context);
|
||||||
|
var options = chatScope.options;
|
||||||
|
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
return Text("Error: ${snapshot.error}");
|
return CustomSemantics(
|
||||||
|
identifier: options.semantics.newChatGetUsersError,
|
||||||
|
value: "Error: ${snapshot.error}",
|
||||||
|
child: Text("Error: ${snapshot.error}"),
|
||||||
|
);
|
||||||
} else if (snapshot.hasData) {
|
} else if (snapshot.hasData) {
|
||||||
return UserList(
|
return UserList(
|
||||||
users: snapshot.data!,
|
users: snapshot.data!,
|
||||||
|
|
|
@ -2,6 +2,7 @@ import "dart:typed_data";
|
||||||
|
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
import "package:chat_repository_interface/chat_repository_interface.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/config/screen_types.dart";
|
import "package:flutter_chat/src/config/screen_types.dart";
|
||||||
import "package:flutter_chat/src/screens/creation/widgets/default_image_picker.dart";
|
import "package:flutter_chat/src/screens/creation/widgets/default_image_picker.dart";
|
||||||
import "package:flutter_chat/src/util/scope.dart";
|
import "package:flutter_chat/src/util/scope.dart";
|
||||||
|
@ -301,10 +302,15 @@ class _BodyState extends State<_Body> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
Text(
|
CustomSemantics(
|
||||||
"${translations.selectedMembersHeader}"
|
identifier: options.semantics.newGroupChatMemberAmount,
|
||||||
"${users.length}",
|
value: "${translations.selectedMembersHeader}"
|
||||||
style: theme.textTheme.titleMedium,
|
"${users.length}",
|
||||||
|
child: Text(
|
||||||
|
"${translations.selectedMembersHeader}"
|
||||||
|
"${users.length}",
|
||||||
|
style: theme.textTheme.titleMedium,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 12,
|
height: 12,
|
||||||
|
|
|
@ -196,10 +196,17 @@ class _Body extends StatelessWidget {
|
||||||
// ignore: discarded_futures
|
// ignore: discarded_futures
|
||||||
stream: service.getAllUsers(),
|
stream: service.getAllUsers(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
|
var chatScope = ChatScope.of(context);
|
||||||
|
var options = chatScope.options;
|
||||||
|
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
return Text("Error: ${snapshot.error}");
|
return Semantics(
|
||||||
|
identifier: options.semantics.newGroupChatGetUsersError,
|
||||||
|
value: "Error: ${snapshot.error}",
|
||||||
|
child: Text("Error: ${snapshot.error}"),
|
||||||
|
);
|
||||||
} else if (snapshot.hasData) {
|
} else if (snapshot.hasData) {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
import "package:chat_repository_interface/chat_repository_interface.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/util/scope.dart";
|
import "package:flutter_chat/src/util/scope.dart";
|
||||||
import "package:flutter_profile/flutter_profile.dart";
|
import "package:flutter_profile/flutter_profile.dart";
|
||||||
|
|
||||||
|
@ -106,9 +107,14 @@ class _UserListState extends State<UserList> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 12,
|
width: 12,
|
||||||
),
|
),
|
||||||
Text(
|
CustomSemantics(
|
||||||
user.fullname ?? translations.anonymousUser,
|
identifier: options.semantics
|
||||||
style: theme.textTheme.titleMedium,
|
.newChatUserListUserFullName(index),
|
||||||
|
value: user.fullname ?? translations.anonymousUser,
|
||||||
|
child: Text(
|
||||||
|
user.fullname ?? translations.anonymousUser,
|
||||||
|
style: theme.textTheme.titleMedium,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (widget.creatingGroup) ...[
|
if (widget.creatingGroup) ...[
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
@ -154,9 +160,14 @@ class _UserListState extends State<UserList> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 12,
|
width: 12,
|
||||||
),
|
),
|
||||||
Text(
|
CustomSemantics(
|
||||||
user.fullname ?? translations.anonymousUser,
|
identifier: options.semantics
|
||||||
style: theme.textTheme.titleMedium,
|
.newChatUserListUserFullName(index),
|
||||||
|
value: user.fullname ?? translations.anonymousUser,
|
||||||
|
child: Text(
|
||||||
|
user.fullname ?? translations.anonymousUser,
|
||||||
|
style: theme.textTheme.titleMedium,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (widget.creatingGroup) ...[
|
if (widget.creatingGroup) ...[
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
|
Loading…
Reference in a new issue