fix: improve chat layout

This commit is contained in:
Mathias Mogensen 2024-06-28 12:39:55 +02:00
parent bae67b04a8
commit 5765e604a7
4 changed files with 90 additions and 91 deletions

View File

@ -118,4 +118,7 @@ class AIChatPagePluginWidgetBuilder extends PluginWidgetBuilder
@override @override
List<NavigationItem> get navigationItems => [this]; List<NavigationItem> get navigationItems => [this];
@override
EdgeInsets get contentPadding => EdgeInsets.zero;
} }

View File

@ -1,3 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart'; import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart';
import 'package:appflowy/plugins/ai_chat/presentation/ai_message_bubble.dart'; import 'package:appflowy/plugins/ai_chat/presentation/ai_message_bubble.dart';
@ -10,12 +13,10 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.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/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_chat_types/flutter_chat_types.dart'; import 'package:flutter_chat_types/flutter_chat_types.dart';
import 'package:flutter_chat_ui/flutter_chat_ui.dart' show Chat;
import 'package:flutter_chat_types/flutter_chat_types.dart' as types; import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
import 'package:flutter_chat_ui/flutter_chat_ui.dart' show Chat;
import 'presentation/chat_input.dart'; import 'presentation/chat_input.dart';
import 'presentation/chat_popmenu.dart'; import 'presentation/chat_popmenu.dart';
@ -27,11 +28,11 @@ import 'presentation/message/user_text_message.dart';
class AIChatUILayout { class AIChatUILayout {
static EdgeInsets get chatPadding => static EdgeInsets get chatPadding =>
isMobile ? EdgeInsets.zero : const EdgeInsets.symmetric(horizontal: 70); isMobile ? EdgeInsets.zero : const EdgeInsets.symmetric(horizontal: 20);
static EdgeInsets get welcomePagePadding => isMobile static EdgeInsets get welcomePagePadding => isMobile
? const EdgeInsets.symmetric(horizontal: 20) ? const EdgeInsets.symmetric(horizontal: 20)
: const EdgeInsets.symmetric(horizontal: 100); : const EdgeInsets.symmetric(horizontal: 50);
static double get messageWidthRatio => 0.85; static double get messageWidthRatio => 0.85;
@ -44,7 +45,8 @@ class AIChatUILayout {
query.padding.right, query.padding.right,
query.viewInsets.bottom + query.padding.bottom, query.viewInsets.bottom + query.padding.bottom,
) )
: const EdgeInsets.symmetric(horizontal: 70); : const EdgeInsets.symmetric(horizontal: 50) +
const EdgeInsets.only(bottom: 20);
} }
} }
@ -77,92 +79,89 @@ class _AIChatPageState extends State<AIChatPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (widget.userProfile.authenticator == AuthenticatorPB.AppFlowyCloud) { if (widget.userProfile.authenticator == AuthenticatorPB.AppFlowyCloud) {
return buildChatWidget(); return buildChatWidget();
} else {
return Center(
child: FlowyText(
LocaleKeys.chat_unsupportedCloudPrompt.tr(),
fontSize: 20,
),
);
} }
return Center(
child: FlowyText(
LocaleKeys.chat_unsupportedCloudPrompt.tr(),
fontSize: 20,
),
);
} }
Widget buildChatWidget() { Widget buildChatWidget() {
return SizedBox.expand( return Row(
child: Padding( mainAxisAlignment: MainAxisAlignment.center,
padding: AIChatUILayout.chatPadding, children: [
child: BlocProvider( Flexible(
create: (context) => ChatBloc( child: ConstrainedBox(
view: widget.view, constraints: const BoxConstraints(maxWidth: 784),
userProfile: widget.userProfile, child: BlocProvider(
)..add(const ChatEvent.initialLoad()), create: (_) => ChatBloc(
child: BlocBuilder<ChatBloc, ChatState>( view: widget.view,
builder: (blocContext, state) { userProfile: widget.userProfile,
return Chat( )..add(const ChatEvent.initialLoad()),
messages: state.messages, child: BlocBuilder<ChatBloc, ChatState>(
onAttachmentPressed: () {}, builder: (blocContext, state) => Chat(
onSendPressed: (types.PartialText message) { messages: state.messages,
// We use custom bottom widget for chat input, so onSendPressed: (_) {
// do not need to handle this event. // We use custom bottom widget for chat input, so
}, // do not need to handle this event.
customBottomWidget: buildChatInput(blocContext), },
user: _user, customBottomWidget: buildChatInput(blocContext),
theme: buildTheme(context), user: _user,
onEndReached: () async { theme: buildTheme(context),
if (state.hasMorePrevMessage && onEndReached: () async {
state.loadingPreviousStatus != if (state.hasMorePrevMessage &&
const LoadingState.loading()) { state.loadingPreviousStatus !=
blocContext const LoadingState.loading()) {
.read<ChatBloc>() blocContext
.add(const ChatEvent.startLoadingPrevMessage()); .read<ChatBloc>()
} .add(const ChatEvent.startLoadingPrevMessage());
}, }
emptyState: BlocBuilder<ChatBloc, ChatState>( },
builder: (context, state) { emptyState: BlocBuilder<ChatBloc, ChatState>(
return state.initialLoadingStatus == builder: (_, state) => state.initialLoadingStatus ==
const LoadingState.finish() const LoadingState.finish()
? Padding( ? Padding(
padding: AIChatUILayout.welcomePagePadding, padding: AIChatUILayout.welcomePagePadding,
child: ChatWelcomePage( child: ChatWelcomePage(
onSelectedQuestion: (question) { onSelectedQuestion: (question) => blocContext
blocContext .read<ChatBloc>()
.read<ChatBloc>() .add(ChatEvent.sendMessage(question)),
.add(ChatEvent.sendMessage(question));
},
), ),
) )
: const Center( : const Center(
child: CircularProgressIndicator.adaptive(), child: CircularProgressIndicator.adaptive(),
); ),
),
messageWidthRatio: AIChatUILayout.messageWidthRatio,
textMessageBuilder: (
textMessage, {
required messageWidth,
required showName,
}) =>
_buildAITextMessage(blocContext, textMessage),
bubbleBuilder: (
child, {
required message,
required nextMessageInGroup,
}) {
if (message.author.id == _user.id) {
return ChatUserMessageBubble(
message: message,
child: child,
);
}
return _buildAIBubble(message, blocContext, state, child);
}, },
), ),
messageWidthRatio: AIChatUILayout.messageWidthRatio, ),
textMessageBuilder: ( ),
textMessage, {
required messageWidth,
required showName,
}) {
return _buildAITextMessage(blocContext, textMessage);
},
bubbleBuilder: (
child, {
required message,
required nextMessageInGroup,
}) {
if (message.author.id == _user.id) {
return ChatUserMessageBubble(
message: message,
child: child,
);
} else {
return _buildAIBubble(message, blocContext, state, child);
}
},
);
},
), ),
), ),
), ],
); );
} }

View File

@ -1,9 +1,10 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; 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:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'chat_input.dart'; import 'chat_input.dart';
@ -31,19 +32,15 @@ class ChatWelcomePage extends StatelessWidget {
size: Size.square(44), size: Size.square(44),
), ),
const SizedBox(height: 40), const SizedBox(height: 40),
GridView.builder( Wrap(
shrinkWrap: true, children: items
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( .map(
crossAxisCount: isMobile ? 2 : 4, (i) => WelcomeQuestion(
crossAxisSpacing: 6, question: i,
mainAxisSpacing: 6, onSelected: onSelectedQuestion,
childAspectRatio: 16.0 / 9.0, ),
), )
itemCount: items.length, .toList(),
itemBuilder: (context, index) => WelcomeQuestion(
question: items[index],
onSelected: onSelectedQuestion,
),
), ),
], ],
), ),

View File

@ -144,7 +144,7 @@ class _AISearchToggle extends StatelessWidget {
child: SizedBox( child: SizedBox(
height: 26, height: 26,
width: 26, width: 26,
child: CircularProgressIndicator.adaptive(strokeWidth: 4), child: CircularProgressIndicator.adaptive(),
), ),
); );
} else { } else {