refactor: improve chat page scrolling behavior and reset logic
- Introduced a new boolean flag `_pendingConversationScrollReset` to manage scrolling behavior when switching conversations. - Added a method `_resetScrollToTop` to handle scrolling to the top of the chat when necessary, enhancing user experience. - Updated the logic in the chat page to ensure proper scrolling behavior based on conversation state, improving usability during conversation transitions. - Refactored the chat input widget to simplify the layout and enhance responsiveness, ensuring better integration with the overall chat interface.
This commit is contained in:
@@ -68,6 +68,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
String? _lastConversationId;
|
String? _lastConversationId;
|
||||||
bool _shouldAutoScrollToBottom = true;
|
bool _shouldAutoScrollToBottom = true;
|
||||||
bool _autoScrollCallbackScheduled = false;
|
bool _autoScrollCallbackScheduled = false;
|
||||||
|
bool _pendingConversationScrollReset = false;
|
||||||
|
|
||||||
String _formatModelDisplayName(String name, {required bool omitProvider}) {
|
String _formatModelDisplayName(String name, {required bool omitProvider}) {
|
||||||
var display = name.trim();
|
var display = name.trim();
|
||||||
@@ -104,6 +105,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_shouldAutoScrollToBottom = true;
|
_shouldAutoScrollToBottom = true;
|
||||||
|
_pendingConversationScrollReset = false;
|
||||||
_scheduleAutoScrollToBottom();
|
_scheduleAutoScrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,6 +601,22 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _resetScrollToTop() {
|
||||||
|
if (!_scrollController.hasClients) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (!mounted || !_scrollController.hasClients) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_scrollController.jumpTo(0);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_scrollController.position.pixels != 0) {
|
||||||
|
_scrollController.jumpTo(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _scrollToBottom({bool smooth = true}) {
|
void _scrollToBottom({bool smooth = true}) {
|
||||||
if (!_scrollController.hasClients) return;
|
if (!_scrollController.hasClients) return;
|
||||||
final position = _scrollController.position;
|
final position = _scrollController.position;
|
||||||
@@ -763,6 +781,17 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
|
|
||||||
final apiService = ref.watch(apiServiceProvider);
|
final apiService = ref.watch(apiServiceProvider);
|
||||||
|
|
||||||
|
if (_pendingConversationScrollReset) {
|
||||||
|
_pendingConversationScrollReset = false;
|
||||||
|
if (messages.length <= 1) {
|
||||||
|
_shouldAutoScrollToBottom = true;
|
||||||
|
} else {
|
||||||
|
// When opening an existing conversation, start reading from the top
|
||||||
|
_shouldAutoScrollToBottom = false;
|
||||||
|
_resetScrollToTop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_shouldAutoScrollToBottom) {
|
if (_shouldAutoScrollToBottom) {
|
||||||
_scheduleAutoScrollToBottom();
|
_scheduleAutoScrollToBottom();
|
||||||
} else {
|
} else {
|
||||||
@@ -1031,8 +1060,14 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
);
|
);
|
||||||
if (conversationId != _lastConversationId) {
|
if (conversationId != _lastConversationId) {
|
||||||
_lastConversationId = conversationId;
|
_lastConversationId = conversationId;
|
||||||
_shouldAutoScrollToBottom = true;
|
if (conversationId == null) {
|
||||||
_scheduleAutoScrollToBottom();
|
_shouldAutoScrollToBottom = true;
|
||||||
|
_pendingConversationScrollReset = false;
|
||||||
|
_scheduleAutoScrollToBottom();
|
||||||
|
} else {
|
||||||
|
_pendingConversationScrollReset = true;
|
||||||
|
_shouldAutoScrollToBottom = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
final conversationTitle = ref.watch(
|
final conversationTitle = ref.watch(
|
||||||
activeConversationProvider.select((conv) => conv?.title),
|
activeConversationProvider.select((conv) => conv?.title),
|
||||||
|
|||||||
@@ -1276,25 +1276,12 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
|||||||
borderRadius: BorderRadius.circular(radius),
|
borderRadius: BorderRadius.circular(radius),
|
||||||
boxShadow: ConduitShadows.button,
|
boxShadow: ConduitShadows.button,
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Center(
|
||||||
alignment: Alignment.center,
|
child: Icon(
|
||||||
children: [
|
Platform.isIOS ? CupertinoIcons.stop_fill : Icons.stop,
|
||||||
SizedBox(
|
size: IconSize.large,
|
||||||
width: buttonSize - 18,
|
color: context.conduitTheme.error,
|
||||||
height: buttonSize - 18,
|
),
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: BorderWidth.medium,
|
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(
|
|
||||||
context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Icon(
|
|
||||||
Platform.isIOS ? CupertinoIcons.stop_fill : Icons.stop,
|
|
||||||
size: IconSize.medium,
|
|
||||||
color: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user