mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: improve chat layout
This commit is contained in:
parent
bae67b04a8
commit
5765e604a7
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user