mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-02 11:04:02 +00:00
chore: simplify chat user message bloc and widgets (#6836)
This commit is contained in:
parent
f82dabcc75
commit
e86a9d697c
@ -8,72 +8,19 @@ part 'chat_user_message_bloc.freezed.dart';
|
|||||||
class ChatUserMessageBloc
|
class ChatUserMessageBloc
|
||||||
extends Bloc<ChatUserMessageEvent, ChatUserMessageState> {
|
extends Bloc<ChatUserMessageEvent, ChatUserMessageState> {
|
||||||
ChatUserMessageBloc({
|
ChatUserMessageBloc({
|
||||||
required dynamic message,
|
required this.questionStream,
|
||||||
}) : super(ChatUserMessageState.initial(message)) {
|
required String text,
|
||||||
|
}) : super(ChatUserMessageState.initial(text)) {
|
||||||
|
_dispatch();
|
||||||
|
_startListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
final QuestionStream? questionStream;
|
||||||
|
|
||||||
|
void _dispatch() {
|
||||||
on<ChatUserMessageEvent>(
|
on<ChatUserMessageEvent>(
|
||||||
(event, emit) {
|
(event, emit) {
|
||||||
event.when(
|
event.when(
|
||||||
initial: () {
|
|
||||||
if (state.stream != null) {
|
|
||||||
if (!isClosed) {
|
|
||||||
add(ChatUserMessageEvent.updateText(state.stream!.text));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state.stream?.listen(
|
|
||||||
onData: (text) {
|
|
||||||
if (!isClosed) {
|
|
||||||
add(ChatUserMessageEvent.updateText(text));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onMessageId: (messageId) {
|
|
||||||
if (!isClosed) {
|
|
||||||
add(ChatUserMessageEvent.updateMessageId(messageId));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onError: (error) {
|
|
||||||
if (!isClosed) {
|
|
||||||
add(ChatUserMessageEvent.receiveError(error.toString()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onFileIndexStart: (indexName) {
|
|
||||||
Log.debug("index start: $indexName");
|
|
||||||
},
|
|
||||||
onFileIndexEnd: (indexName) {
|
|
||||||
Log.info("index end: $indexName");
|
|
||||||
},
|
|
||||||
onFileIndexFail: (indexName) {
|
|
||||||
Log.debug("index fail: $indexName");
|
|
||||||
},
|
|
||||||
onIndexStart: () {
|
|
||||||
if (!isClosed) {
|
|
||||||
add(
|
|
||||||
const ChatUserMessageEvent.updateQuestionState(
|
|
||||||
QuestionMessageState.indexStart(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onIndexEnd: () {
|
|
||||||
if (!isClosed) {
|
|
||||||
add(
|
|
||||||
const ChatUserMessageEvent.updateQuestionState(
|
|
||||||
QuestionMessageState.indexEnd(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onDone: () {
|
|
||||||
if (!isClosed) {
|
|
||||||
add(
|
|
||||||
const ChatUserMessageEvent.updateQuestionState(
|
|
||||||
QuestionMessageState.finish(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
updateText: (String text) {
|
updateText: (String text) {
|
||||||
emit(state.copyWith(text: text));
|
emit(state.copyWith(text: text));
|
||||||
},
|
},
|
||||||
@ -88,11 +35,66 @@ class ChatUserMessageBloc
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _startListening() {
|
||||||
|
questionStream?.listen(
|
||||||
|
onData: (text) {
|
||||||
|
if (!isClosed) {
|
||||||
|
add(ChatUserMessageEvent.updateText(text));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMessageId: (messageId) {
|
||||||
|
if (!isClosed) {
|
||||||
|
add(ChatUserMessageEvent.updateMessageId(messageId));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (error) {
|
||||||
|
if (!isClosed) {
|
||||||
|
add(ChatUserMessageEvent.receiveError(error.toString()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onFileIndexStart: (indexName) {
|
||||||
|
Log.debug("index start: $indexName");
|
||||||
|
},
|
||||||
|
onFileIndexEnd: (indexName) {
|
||||||
|
Log.info("index end: $indexName");
|
||||||
|
},
|
||||||
|
onFileIndexFail: (indexName) {
|
||||||
|
Log.debug("index fail: $indexName");
|
||||||
|
},
|
||||||
|
onIndexStart: () {
|
||||||
|
if (!isClosed) {
|
||||||
|
add(
|
||||||
|
const ChatUserMessageEvent.updateQuestionState(
|
||||||
|
QuestionMessageState.indexStart(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onIndexEnd: () {
|
||||||
|
if (!isClosed) {
|
||||||
|
add(
|
||||||
|
const ChatUserMessageEvent.updateQuestionState(
|
||||||
|
QuestionMessageState.indexEnd(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDone: () {
|
||||||
|
if (!isClosed) {
|
||||||
|
add(
|
||||||
|
const ChatUserMessageEvent.updateQuestionState(
|
||||||
|
QuestionMessageState.finish(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class ChatUserMessageEvent with _$ChatUserMessageEvent {
|
class ChatUserMessageEvent with _$ChatUserMessageEvent {
|
||||||
const factory ChatUserMessageEvent.initial() = Initial;
|
|
||||||
const factory ChatUserMessageEvent.updateText(String text) = _UpdateText;
|
const factory ChatUserMessageEvent.updateText(String text) = _UpdateText;
|
||||||
const factory ChatUserMessageEvent.updateQuestionState(
|
const factory ChatUserMessageEvent.updateQuestionState(
|
||||||
QuestionMessageState newState,
|
QuestionMessageState newState,
|
||||||
@ -106,17 +108,14 @@ class ChatUserMessageEvent with _$ChatUserMessageEvent {
|
|||||||
class ChatUserMessageState with _$ChatUserMessageState {
|
class ChatUserMessageState with _$ChatUserMessageState {
|
||||||
const factory ChatUserMessageState({
|
const factory ChatUserMessageState({
|
||||||
required String text,
|
required String text,
|
||||||
QuestionStream? stream,
|
required String? messageId,
|
||||||
String? messageId,
|
required QuestionMessageState messageState,
|
||||||
@Default(QuestionMessageState.finish()) QuestionMessageState messageState,
|
|
||||||
}) = _ChatUserMessageState;
|
}) = _ChatUserMessageState;
|
||||||
|
|
||||||
factory ChatUserMessageState.initial(
|
factory ChatUserMessageState.initial(String message) => ChatUserMessageState(
|
||||||
dynamic message,
|
text: message,
|
||||||
) =>
|
messageId: null,
|
||||||
ChatUserMessageState(
|
messageState: const QuestionMessageState.finish(),
|
||||||
text: message is String ? message : "",
|
|
||||||
stream: message is QuestionStream ? message : null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
import 'package:appflowy/plugins/ai_chat/application/chat_entity.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_chat_core/flutter_chat_core.dart';
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
|
|
||||||
import 'chat_message_service.dart';
|
|
||||||
|
|
||||||
part 'chat_user_message_bubble_bloc.freezed.dart';
|
|
||||||
|
|
||||||
class ChatUserMessageBubbleBloc
|
|
||||||
extends Bloc<ChatUserMessageBubbleEvent, ChatUserMessageBubbleState> {
|
|
||||||
ChatUserMessageBubbleBloc({
|
|
||||||
required Message message,
|
|
||||||
}) : super(
|
|
||||||
ChatUserMessageBubbleState.initial(
|
|
||||||
message,
|
|
||||||
_getFiles(message.metadata),
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
on<ChatUserMessageBubbleEvent>(
|
|
||||||
(event, emit) async {
|
|
||||||
event.when(
|
|
||||||
initial: () {},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ChatFile> _getFiles(Map<String, dynamic>? metadata) {
|
|
||||||
if (metadata == null) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
final refSourceMetadata = metadata[messageRefSourceJsonStringKey] as String?;
|
|
||||||
final files = metadata[messageChatFileListKey] as List<ChatFile>?;
|
|
||||||
|
|
||||||
if (refSourceMetadata != null) {
|
|
||||||
return chatFilesFromMetadataString(refSourceMetadata);
|
|
||||||
}
|
|
||||||
return files ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
class ChatUserMessageBubbleEvent with _$ChatUserMessageBubbleEvent {
|
|
||||||
const factory ChatUserMessageBubbleEvent.initial() = Initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
class ChatUserMessageBubbleState with _$ChatUserMessageBubbleState {
|
|
||||||
const factory ChatUserMessageBubbleState({
|
|
||||||
required Message message,
|
|
||||||
required List<ChatFile> files,
|
|
||||||
}) = _ChatUserMessageBubbleState;
|
|
||||||
|
|
||||||
factory ChatUserMessageBubbleState.initial(
|
|
||||||
Message message,
|
|
||||||
List<ChatFile> files,
|
|
||||||
) =>
|
|
||||||
ChatUserMessageBubbleState(message: message, files: files);
|
|
||||||
}
|
|
||||||
@ -4,7 +4,6 @@ import 'package:appflowy/plugins/ai_chat/application/chat_entity.dart';
|
|||||||
import 'package:appflowy/plugins/ai_chat/application/ai_prompt_input_bloc.dart';
|
import 'package:appflowy/plugins/ai_chat/application/ai_prompt_input_bloc.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/application/chat_message_stream.dart';
|
import 'package:appflowy/plugins/ai_chat/application/chat_message_stream.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/presentation/chat_related_question.dart';
|
import 'package:appflowy/plugins/ai_chat/presentation/chat_related_question.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/presentation/message/user_message_bubble.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||||
import 'package:desktop_drop/desktop_drop.dart';
|
import 'package:desktop_drop/desktop_drop.dart';
|
||||||
@ -233,27 +232,18 @@ class _ChatContentPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (message.author.id == userProfile.id.toString()) {
|
if (message.author.id == userProfile.id.toString()) {
|
||||||
final stream = message.metadata?["$QuestionStream"];
|
return ChatUserMessageWidget(
|
||||||
return ChatUserMessageBubble(
|
user: message.author,
|
||||||
key: ValueKey(message.id),
|
|
||||||
message: message,
|
message: message,
|
||||||
child: ChatUserMessageWidget(
|
isCurrentUser: true,
|
||||||
user: message.author,
|
|
||||||
message: stream is QuestionStream ? stream : message.text,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOtherUserMessage(message)) {
|
if (isOtherUserMessage(message)) {
|
||||||
final stream = message.metadata?["$QuestionStream"];
|
return ChatUserMessageWidget(
|
||||||
return ChatUserMessageBubble(
|
user: message.author,
|
||||||
key: ValueKey(message.id),
|
|
||||||
message: message,
|
message: message,
|
||||||
isCurrentUser: false,
|
isCurrentUser: false,
|
||||||
child: ChatUserMessageWidget(
|
|
||||||
user: message.author,
|
|
||||||
message: stream is QuestionStream ? stream : message.text,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +253,6 @@ class _ChatContentPage extends StatelessWidget {
|
|||||||
message.metadata?[messageRefSourceJsonStringKey] as String?;
|
message.metadata?[messageRefSourceJsonStringKey] as String?;
|
||||||
|
|
||||||
return BlocSelector<ChatBloc, ChatState, bool>(
|
return BlocSelector<ChatBloc, ChatState, bool>(
|
||||||
key: ValueKey(message.id),
|
|
||||||
selector: (state) {
|
selector: (state) {
|
||||||
final chatController = context.read<ChatBloc>().chatController;
|
final chatController = context.read<ChatBloc>().chatController;
|
||||||
final messages = chatController.messages.where((e) {
|
final messages = chatController.messages.where((e) {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||||
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart';
|
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/presentation/chat_avatar.dart';
|
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
|
||||||
import 'package:appflowy/shared/markdown_to_document.dart';
|
import 'package:appflowy/shared/markdown_to_document.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
@ -17,13 +16,13 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_chat_core/flutter_chat_core.dart';
|
import 'package:flutter_chat_core/flutter_chat_core.dart';
|
||||||
import 'package:universal_platform/universal_platform.dart';
|
import 'package:universal_platform/universal_platform.dart';
|
||||||
|
|
||||||
|
import '../chat_avatar.dart';
|
||||||
import '../layout_define.dart';
|
import '../layout_define.dart';
|
||||||
|
|
||||||
/// Wraps an AI response message with the avatar and actions. On desktop,
|
/// Wraps an AI response message with the avatar and actions. On desktop,
|
||||||
/// the actions will be displayed below the response if the response is the
|
/// the actions will be displayed below the response if the response is the
|
||||||
/// last message in the chat. For other AI responses, the actions will be shown
|
/// last message in the chat. For the others, the actions will be shown on hover
|
||||||
/// on hover. On mobile, the actions will be displayed in a bottom sheet on
|
/// On mobile, the actions will be displayed in a bottom sheet on long press.
|
||||||
/// long press.
|
|
||||||
class ChatAIMessageBubble extends StatelessWidget {
|
class ChatAIMessageBubble extends StatelessWidget {
|
||||||
const ChatAIMessageBubble({
|
const ChatAIMessageBubble({
|
||||||
super.key,
|
super.key,
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/application/chat_entity.dart';
|
import 'package:appflowy/plugins/ai_chat/application/chat_entity.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/application/chat_member_bloc.dart';
|
import 'package:appflowy/plugins/ai_chat/application/chat_member_bloc.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/application/chat_user_message_bubble_bloc.dart';
|
|
||||||
import 'package:appflowy/plugins/ai_chat/presentation/chat_avatar.dart';
|
|
||||||
import 'package:appflowy/plugins/ai_chat/presentation/layout_define.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -11,57 +8,50 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:flutter_chat_core/flutter_chat_core.dart';
|
import 'package:flutter_chat_core/flutter_chat_core.dart';
|
||||||
import 'package:universal_platform/universal_platform.dart';
|
import 'package:universal_platform/universal_platform.dart';
|
||||||
|
|
||||||
|
import '../chat_avatar.dart';
|
||||||
|
import '../layout_define.dart';
|
||||||
|
|
||||||
class ChatUserMessageBubble extends StatelessWidget {
|
class ChatUserMessageBubble extends StatelessWidget {
|
||||||
const ChatUserMessageBubble({
|
const ChatUserMessageBubble({
|
||||||
super.key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.child,
|
required this.child,
|
||||||
this.isCurrentUser = true,
|
required this.isCurrentUser,
|
||||||
|
this.files = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
final Message message;
|
final Message message;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final bool isCurrentUser;
|
final bool isCurrentUser;
|
||||||
|
final List<ChatFile> files;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (context.read<ChatMemberBloc>().state.members[message.author.id] ==
|
context
|
||||||
null) {
|
.read<ChatMemberBloc>()
|
||||||
context
|
.add(ChatMemberEvent.getMemberInfo(message.author.id));
|
||||||
.read<ChatMemberBloc>()
|
|
||||||
.add(ChatMemberEvent.getMemberInfo(message.author.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return BlocProvider(
|
return Padding(
|
||||||
create: (context) => ChatUserMessageBubbleBloc(
|
padding: UniversalPlatform.isMobile
|
||||||
message: message,
|
? const EdgeInsets.symmetric(horizontal: 16)
|
||||||
),
|
: EdgeInsets.zero,
|
||||||
child: BlocBuilder<ChatUserMessageBubbleBloc, ChatUserMessageBubbleState>(
|
child: Column(
|
||||||
builder: (context, state) {
|
mainAxisSize: MainAxisSize.min,
|
||||||
return Padding(
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
padding: UniversalPlatform.isMobile
|
children: [
|
||||||
? const EdgeInsets.symmetric(horizontal: 16)
|
if (files.isNotEmpty) ...[
|
||||||
: EdgeInsets.zero,
|
Padding(
|
||||||
child: Column(
|
padding: const EdgeInsets.only(right: 32),
|
||||||
mainAxisSize: MainAxisSize.min,
|
child: _MessageFileList(files: files),
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
if (state.files.isNotEmpty) ...[
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 32),
|
|
||||||
child: _MessageFileList(files: state.files),
|
|
||||||
),
|
|
||||||
const VSpace(6),
|
|
||||||
],
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: getChildren(context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
const VSpace(6),
|
||||||
},
|
],
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: getChildren(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import 'package:appflowy/plugins/ai_chat/application/chat_entity.dart';
|
||||||
|
import 'package:appflowy/plugins/ai_chat/application/chat_message_service.dart';
|
||||||
|
import 'package:appflowy/plugins/ai_chat/application/chat_message_stream.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/application/chat_user_message_bloc.dart';
|
import 'package:appflowy/plugins/ai_chat/application/chat_user_message_bloc.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
@ -5,33 +8,63 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_chat_core/flutter_chat_core.dart';
|
import 'package:flutter_chat_core/flutter_chat_core.dart';
|
||||||
|
|
||||||
|
import 'user_message_bubble.dart';
|
||||||
|
|
||||||
class ChatUserMessageWidget extends StatelessWidget {
|
class ChatUserMessageWidget extends StatelessWidget {
|
||||||
const ChatUserMessageWidget({
|
const ChatUserMessageWidget({
|
||||||
super.key,
|
super.key,
|
||||||
required this.user,
|
required this.user,
|
||||||
required this.message,
|
required this.message,
|
||||||
|
required this.isCurrentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
final User user;
|
final User user;
|
||||||
final dynamic message;
|
final TextMessage message;
|
||||||
|
final bool isCurrentUser;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final stream = message.metadata?["$QuestionStream"];
|
||||||
|
final messageText = stream is QuestionStream ? stream.text : message.text;
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => ChatUserMessageBloc(message: message)
|
create: (context) => ChatUserMessageBloc(
|
||||||
..add(const ChatUserMessageEvent.initial()),
|
text: messageText,
|
||||||
child: BlocBuilder<ChatUserMessageBloc, ChatUserMessageState>(
|
questionStream: stream,
|
||||||
builder: (context, state) {
|
),
|
||||||
return Opacity(
|
child: ChatUserMessageBubble(
|
||||||
opacity: state.messageState.isFinish ? 1.0 : 0.8,
|
message: message,
|
||||||
child: TextMessageText(
|
isCurrentUser: isCurrentUser,
|
||||||
text: state.text,
|
files: _getFiles(),
|
||||||
),
|
child: BlocBuilder<ChatUserMessageBloc, ChatUserMessageState>(
|
||||||
);
|
builder: (context, state) {
|
||||||
},
|
return Opacity(
|
||||||
|
opacity: state.messageState.isFinish ? 1.0 : 0.8,
|
||||||
|
child: TextMessageText(
|
||||||
|
text: state.text,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ChatFile> _getFiles() {
|
||||||
|
if (message.metadata == null) {
|
||||||
|
return const [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final refSourceMetadata =
|
||||||
|
message.metadata?[messageRefSourceJsonStringKey] as String?;
|
||||||
|
if (refSourceMetadata != null) {
|
||||||
|
return chatFilesFromMetadataString(refSourceMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
final chatFileList =
|
||||||
|
message.metadata![messageChatFileListKey] as List<ChatFile>?;
|
||||||
|
return chatFileList ?? [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Widget to reuse the markdown capabilities, e.g., for previews.
|
/// Widget to reuse the markdown capabilities, e.g., for previews.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user