feat(chat): Add folder support in new chat screen
This commit is contained in:
@@ -853,6 +853,21 @@ class SelectedModel extends _$SelectedModel {
|
|||||||
void clear() => state = null;
|
void clear() => state = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tracks a pending folder ID for the next new conversation.
|
||||||
|
///
|
||||||
|
/// When a user starts a new chat from within a folder context menu,
|
||||||
|
/// this provider holds the folder ID so that the conversation is
|
||||||
|
/// automatically placed in that folder upon creation.
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class PendingFolderId extends _$PendingFolderId {
|
||||||
|
@override
|
||||||
|
String? build() => null;
|
||||||
|
|
||||||
|
void set(String? folderId) => state = folderId;
|
||||||
|
|
||||||
|
void clear() => state = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Track if the current model selection is manual (user-selected) or automatic (default)
|
// Track if the current model selection is manual (user-selected) or automatic (default)
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
class IsManualModelSelection extends _$IsManualModelSelection {
|
class IsManualModelSelection extends _$IsManualModelSelection {
|
||||||
|
|||||||
@@ -812,6 +812,7 @@ class ApiService {
|
|||||||
required List<ChatMessage> messages,
|
required List<ChatMessage> messages,
|
||||||
String? model,
|
String? model,
|
||||||
String? systemPrompt,
|
String? systemPrompt,
|
||||||
|
String? folderId,
|
||||||
}) async {
|
}) async {
|
||||||
_traceApi('Creating new conversation on OpenWebUI server');
|
_traceApi('Creating new conversation on OpenWebUI server');
|
||||||
_traceApi('Title: $title, Messages: ${messages.length}');
|
_traceApi('Title: $title, Messages: ${messages.length}');
|
||||||
@@ -893,7 +894,7 @@ class ApiService {
|
|||||||
'tags': [],
|
'tags': [],
|
||||||
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
||||||
},
|
},
|
||||||
'folder_id': null,
|
'folder_id': folderId,
|
||||||
};
|
};
|
||||||
|
|
||||||
_traceApi('Sending chat data with proper parent-child structure');
|
_traceApi('Sending chat data with proper parent-child structure');
|
||||||
|
|||||||
@@ -981,6 +981,9 @@ void startNewChat(dynamic ref) {
|
|||||||
|
|
||||||
// Clear context attachments (web pages, YouTube, knowledge base docs)
|
// Clear context attachments (web pages, YouTube, knowledge base docs)
|
||||||
ref.read(contextAttachmentsProvider.notifier).clear();
|
ref.read(contextAttachmentsProvider.notifier).clear();
|
||||||
|
|
||||||
|
// Clear any pending folder selection
|
||||||
|
ref.read(pendingFolderIdProvider.notifier).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Available tools provider
|
// Available tools provider
|
||||||
@@ -1892,6 +1895,9 @@ Future<void> _sendMessageInternal(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (activeConversation == null) {
|
if (activeConversation == null) {
|
||||||
|
// Check if there's a pending folder ID for this new conversation
|
||||||
|
final pendingFolderId = ref.read(pendingFolderIdProvider);
|
||||||
|
|
||||||
// Create new conversation with the first message included
|
// Create new conversation with the first message included
|
||||||
final localConversation = Conversation(
|
final localConversation = Conversation(
|
||||||
id: const Uuid().v4(),
|
id: const Uuid().v4(),
|
||||||
@@ -1900,6 +1906,7 @@ Future<void> _sendMessageInternal(
|
|||||||
updatedAt: DateTime.now(),
|
updatedAt: DateTime.now(),
|
||||||
systemPrompt: userSystemPrompt,
|
systemPrompt: userSystemPrompt,
|
||||||
messages: [userMessage], // Include the user message
|
messages: [userMessage], // Include the user message
|
||||||
|
folderId: pendingFolderId,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set as active conversation locally
|
// Set as active conversation locally
|
||||||
@@ -1914,13 +1921,19 @@ Future<void> _sendMessageInternal(
|
|||||||
messages: [userMessage], // Include the first message in creation
|
messages: [userMessage], // Include the first message in creation
|
||||||
model: selectedModel.id,
|
model: selectedModel.id,
|
||||||
systemPrompt: userSystemPrompt,
|
systemPrompt: userSystemPrompt,
|
||||||
|
folderId: pendingFolderId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Clear the pending folder ID after successful creation
|
||||||
|
ref.read(pendingFolderIdProvider.notifier).clear();
|
||||||
|
|
||||||
final updatedConversation = localConversation.copyWith(
|
final updatedConversation = localConversation.copyWith(
|
||||||
id: serverConversation.id,
|
id: serverConversation.id,
|
||||||
systemPrompt: serverConversation.systemPrompt ?? userSystemPrompt,
|
systemPrompt: serverConversation.systemPrompt ?? userSystemPrompt,
|
||||||
messages: serverConversation.messages.isNotEmpty
|
messages: serverConversation.messages.isNotEmpty
|
||||||
? serverConversation.messages
|
? serverConversation.messages
|
||||||
: [userMessage],
|
: [userMessage],
|
||||||
|
folderId: serverConversation.folderId ?? pendingFolderId,
|
||||||
);
|
);
|
||||||
ref.read(activeConversationProvider.notifier).set(updatedConversation);
|
ref.read(activeConversationProvider.notifier).set(updatedConversation);
|
||||||
activeConversation = updatedConversation;
|
activeConversation = updatedConversation;
|
||||||
@@ -1945,7 +1958,10 @@ Future<void> _sendMessageInternal(
|
|||||||
// handle any disposal gracefully.
|
// handle any disposal gracefully.
|
||||||
final isMounted = ref is Ref ? ref.mounted : true;
|
final isMounted = ref is Ref ? ref.mounted : true;
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
refreshConversationsCache(ref);
|
refreshConversationsCache(
|
||||||
|
ref,
|
||||||
|
includeFolders: pendingFolderId != null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// If ref is disposed or invalid, skip
|
// If ref is disposed or invalid, skip
|
||||||
@@ -1954,10 +1970,16 @@ Future<void> _sendMessageInternal(
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Still add the message locally
|
// Still add the message locally
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage(userMessage);
|
ref.read(chatMessagesProvider.notifier).addMessage(userMessage);
|
||||||
|
|
||||||
|
// Clear the pending folder ID on failure to prevent stale state
|
||||||
|
ref.read(pendingFolderIdProvider.notifier).clear();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Add message for reviewer mode
|
// Add message for reviewer mode
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage(userMessage);
|
ref.read(chatMessagesProvider.notifier).addMessage(userMessage);
|
||||||
|
|
||||||
|
// Clear the pending folder ID even in reviewer mode
|
||||||
|
ref.read(pendingFolderIdProvider.notifier).clear();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Add user message to existing conversation
|
// Add user message to existing conversation
|
||||||
@@ -2490,7 +2512,8 @@ Future<void> _sendMessageInternal(
|
|||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
isStreaming: false,
|
isStreaming: false,
|
||||||
error: const ChatMessageError(
|
error: const ChatMessageError(
|
||||||
content: 'There was an issue with the message format. This might be '
|
content:
|
||||||
|
'There was an issue with the message format. This might be '
|
||||||
'because the image attachment couldn\'t be processed, the request '
|
'because the image attachment couldn\'t be processed, the request '
|
||||||
'format is incompatible with the selected model, or the message '
|
'format is incompatible with the selected model, or the message '
|
||||||
'contains unsupported content. Please try sending the message '
|
'contains unsupported content. Please try sending the message '
|
||||||
@@ -2509,7 +2532,8 @@ Future<void> _sendMessageInternal(
|
|||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
isStreaming: false,
|
isStreaming: false,
|
||||||
error: const ChatMessageError(
|
error: const ChatMessageError(
|
||||||
content: 'Unable to connect to the AI model. The server returned an '
|
content:
|
||||||
|
'Unable to connect to the AI model. The server returned an '
|
||||||
'error (500). This is typically a server-side issue. Please try '
|
'error (500). This is typically a server-side issue. Please try '
|
||||||
'again or contact your administrator.',
|
'again or contact your administrator.',
|
||||||
),
|
),
|
||||||
@@ -2527,7 +2551,8 @@ Future<void> _sendMessageInternal(
|
|||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
isStreaming: false,
|
isStreaming: false,
|
||||||
error: const ChatMessageError(
|
error: const ChatMessageError(
|
||||||
content: 'The selected AI model doesn\'t seem to be available. '
|
content:
|
||||||
|
'The selected AI model doesn\'t seem to be available. '
|
||||||
'Please try selecting a different model or check with your '
|
'Please try selecting a different model or check with your '
|
||||||
'administrator.',
|
'administrator.',
|
||||||
),
|
),
|
||||||
@@ -2542,7 +2567,8 @@ Future<void> _sendMessageInternal(
|
|||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
isStreaming: false,
|
isStreaming: false,
|
||||||
error: const ChatMessageError(
|
error: const ChatMessageError(
|
||||||
content: 'An unexpected error occurred while processing your request. '
|
content:
|
||||||
|
'An unexpected error occurred while processing your request. '
|
||||||
'Please try again or check your connection.',
|
'Please try again or check your connection.',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import 'voice_call_page.dart';
|
|||||||
import '../../../shared/services/tasks/task_queue.dart';
|
import '../../../shared/services/tasks/task_queue.dart';
|
||||||
import '../../tools/providers/tools_providers.dart';
|
import '../../tools/providers/tools_providers.dart';
|
||||||
import '../../../core/models/chat_message.dart';
|
import '../../../core/models/chat_message.dart';
|
||||||
|
import '../../../core/models/folder.dart';
|
||||||
import '../../../core/models/model.dart';
|
import '../../../core/models/model.dart';
|
||||||
import '../providers/context_attachments_provider.dart';
|
import '../providers/context_attachments_provider.dart';
|
||||||
import '../../../shared/widgets/loading_states.dart';
|
import '../../../shared/widgets/loading_states.dart';
|
||||||
@@ -126,6 +127,9 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
// Clear context attachments (web pages, YouTube, knowledge base docs)
|
// Clear context attachments (web pages, YouTube, knowledge base docs)
|
||||||
ref.read(contextAttachmentsProvider.notifier).clear();
|
ref.read(contextAttachmentsProvider.notifier).clear();
|
||||||
|
|
||||||
|
// Clear any pending folder selection
|
||||||
|
ref.read(pendingFolderIdProvider.notifier).clear();
|
||||||
|
|
||||||
// Scroll to top
|
// Scroll to top
|
||||||
if (_scrollController.hasClients) {
|
if (_scrollController.hasClients) {
|
||||||
_scrollController.jumpTo(0);
|
_scrollController.jumpTo(0);
|
||||||
@@ -956,10 +960,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
required Widget child,
|
required Widget child,
|
||||||
bool isCircular = false,
|
bool isCircular = false,
|
||||||
}) {
|
}) {
|
||||||
return FloatingAppBarPill(
|
return FloatingAppBarPill(isCircular: isCircular, child: child);
|
||||||
isCircular: isCircular,
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMessagesList(ThemeData theme) {
|
Widget _buildMessagesList(ThemeData theme) {
|
||||||
@@ -1413,6 +1414,16 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
final greetingText = resolvedGreetingName != null
|
final greetingText = resolvedGreetingName != null
|
||||||
? l10n.onboardStartTitle(resolvedGreetingName)
|
? l10n.onboardStartTitle(resolvedGreetingName)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
// Check if there's a pending folder for the new chat
|
||||||
|
final pendingFolderId = ref.watch(pendingFolderIdProvider);
|
||||||
|
final folders = ref
|
||||||
|
.watch(foldersProvider)
|
||||||
|
.maybeWhen(data: (list) => list, orElse: () => <Folder>[]);
|
||||||
|
final pendingFolder = pendingFolderId != null
|
||||||
|
? folders.where((f) => f.id == pendingFolderId).firstOrNull
|
||||||
|
: null;
|
||||||
|
|
||||||
// Add top padding for floating app bar, bottom padding for floating input.
|
// Add top padding for floating app bar, bottom padding for floating input.
|
||||||
final topPadding =
|
final topPadding =
|
||||||
MediaQuery.of(context).padding.top + kToolbarHeight + Spacing.md;
|
MediaQuery.of(context).padding.top + kToolbarHeight + Spacing.md;
|
||||||
@@ -1439,22 +1450,58 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
if (pendingFolder != null) ...[
|
||||||
height: greetingHeight,
|
Column(
|
||||||
child: AnimatedOpacity(
|
mainAxisSize: MainAxisSize.min,
|
||||||
duration: const Duration(milliseconds: 260),
|
children: [
|
||||||
curve: Curves.easeOutCubic,
|
Text(
|
||||||
opacity: _greetingReady ? 1 : 0,
|
l10n.newChat,
|
||||||
child: Align(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Text(
|
|
||||||
_greetingReady ? greetingDisplay : '',
|
|
||||||
style: greetingStyle,
|
style: greetingStyle,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: Spacing.sm),
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Platform.isIOS
|
||||||
|
? CupertinoIcons.folder_fill
|
||||||
|
: Icons.folder_rounded,
|
||||||
|
size: 14,
|
||||||
|
color: context.conduitTheme.textSecondary,
|
||||||
|
),
|
||||||
|
const SizedBox(width: Spacing.xs),
|
||||||
|
Text(
|
||||||
|
pendingFolder.name,
|
||||||
|
style: AppTypography.small.copyWith(
|
||||||
|
color: context.conduitTheme.textSecondary,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
] else ...[
|
||||||
|
SizedBox(
|
||||||
|
height: greetingHeight,
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
duration: const Duration(milliseconds: 260),
|
||||||
|
curve: Curves.easeOutCubic,
|
||||||
|
opacity: _greetingReady ? 1 : 0,
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
_greetingReady ? greetingDisplay : '',
|
||||||
|
style: greetingStyle,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -1909,8 +1956,9 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
Platform.isIOS
|
Platform.isIOS
|
||||||
? CupertinoIcons.chevron_down
|
? CupertinoIcons.chevron_down
|
||||||
: Icons.keyboard_arrow_down,
|
: Icons.keyboard_arrow_down,
|
||||||
color:
|
color: context
|
||||||
context.conduitTheme.iconSecondary,
|
.conduitTheme
|
||||||
|
.iconSecondary,
|
||||||
size: IconSize.small,
|
size: IconSize.small,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1596,8 +1596,9 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
|||||||
hintStyle: baseChatStyle.copyWith(
|
hintStyle: baseChatStyle.copyWith(
|
||||||
color: animatedPlaceholder,
|
color: animatedPlaceholder,
|
||||||
fontWeight: recordingWeight,
|
fontWeight: recordingWeight,
|
||||||
fontStyle:
|
fontStyle: _isRecording
|
||||||
_isRecording ? FontStyle.italic : FontStyle.normal,
|
? FontStyle.italic
|
||||||
|
: FontStyle.normal,
|
||||||
),
|
),
|
||||||
filled: false,
|
filled: false,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import '../../../core/providers/app_providers.dart';
|
|||||||
import '../../auth/providers/unified_auth_providers.dart';
|
import '../../auth/providers/unified_auth_providers.dart';
|
||||||
import '../../../shared/theme/theme_extensions.dart';
|
import '../../../shared/theme/theme_extensions.dart';
|
||||||
import '../../chat/providers/chat_providers.dart' as chat;
|
import '../../chat/providers/chat_providers.dart' as chat;
|
||||||
|
import '../../chat/providers/context_attachments_provider.dart';
|
||||||
import '../../../core/utils/debug_logger.dart';
|
import '../../../core/utils/debug_logger.dart';
|
||||||
import '../../../core/services/navigation_service.dart';
|
import '../../../core/services/navigation_service.dart';
|
||||||
import '../../../shared/widgets/loading_states.dart';
|
import '../../../shared/widgets/loading_states.dart';
|
||||||
@@ -1114,24 +1115,75 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
|
|||||||
const SizedBox(width: Spacing.sm),
|
const SizedBox(width: Spacing.sm),
|
||||||
Flexible(
|
Flexible(
|
||||||
fit: textFit,
|
fit: textFit,
|
||||||
child: Text(
|
child: Row(
|
||||||
name,
|
mainAxisSize: MainAxisSize.min,
|
||||||
maxLines: 1,
|
children: [
|
||||||
overflow: TextOverflow.ellipsis,
|
Flexible(
|
||||||
style: AppTypography.standard.copyWith(
|
child: Text(
|
||||||
color: theme.textPrimary,
|
name,
|
||||||
fontWeight: FontWeight.w400,
|
maxLines: 1,
|
||||||
),
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: AppTypography.standard.copyWith(
|
||||||
|
color: theme.textPrimary,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: Spacing.xs),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 6,
|
||||||
|
vertical: 2,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: context.sidebarTheme.accent
|
||||||
|
.withValues(alpha: 0.7),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(AppBorderRadius.xs),
|
||||||
|
border: Border.all(
|
||||||
|
color: context.sidebarTheme.border
|
||||||
|
.withValues(alpha: 0.35),
|
||||||
|
width: BorderWidth.micro,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'$count',
|
||||||
|
style: AppTypography.tiny.copyWith(
|
||||||
|
color: context.sidebarTheme.foreground
|
||||||
|
.withValues(alpha: 0.8),
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: Spacing.sm),
|
const SizedBox(width: Spacing.sm),
|
||||||
Text(
|
SizedBox(
|
||||||
'$count',
|
width: 22,
|
||||||
style: AppTypography.standard.copyWith(
|
height: 22,
|
||||||
color: theme.textSecondary,
|
child: IconButton(
|
||||||
|
iconSize: IconSize.xs,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
style: IconButton.styleFrom(
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
),
|
||||||
|
icon: Icon(
|
||||||
|
Platform.isIOS
|
||||||
|
? CupertinoIcons.plus_circle
|
||||||
|
: Icons.add_circle_outline_rounded,
|
||||||
|
color: theme.iconSecondary,
|
||||||
|
size: IconSize.listItem,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
HapticFeedback.selectionClick();
|
||||||
|
_startNewChatInFolder(folderId);
|
||||||
|
},
|
||||||
|
tooltip: AppLocalizations.of(context)!.newChat,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: Spacing.xs),
|
const SizedBox(width: Spacing.sm),
|
||||||
Icon(
|
Icon(
|
||||||
isExpanded
|
isExpanded
|
||||||
? (Platform.isIOS
|
? (Platform.isIOS
|
||||||
@@ -1277,6 +1329,28 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _startNewChatInFolder(String folderId) {
|
||||||
|
// Set the pending folder ID for the new conversation
|
||||||
|
ref.read(pendingFolderIdProvider.notifier).set(folderId);
|
||||||
|
|
||||||
|
// Clear current conversation and start fresh
|
||||||
|
ref.read(chat.chatMessagesProvider.notifier).clearMessages();
|
||||||
|
ref.read(activeConversationProvider.notifier).clear();
|
||||||
|
|
||||||
|
// Clear context attachments (web pages, YouTube, knowledge base docs)
|
||||||
|
ref.read(contextAttachmentsProvider.notifier).clear();
|
||||||
|
|
||||||
|
// Close drawer using the responsive layout (same pattern as _selectConversation)
|
||||||
|
if (mounted) {
|
||||||
|
final mediaQuery = MediaQuery.maybeOf(context);
|
||||||
|
final isTablet =
|
||||||
|
mediaQuery != null && mediaQuery.size.shortestSide >= 600;
|
||||||
|
if (!isTablet) {
|
||||||
|
ResponsiveDrawerLayout.of(context)?.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _renameFolder(
|
Future<void> _renameFolder(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String folderId,
|
String folderId,
|
||||||
@@ -1640,6 +1714,9 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
|
|||||||
container.read(activeConversationProvider.notifier).clear();
|
container.read(activeConversationProvider.notifier).clear();
|
||||||
container.read(chat.chatMessagesProvider.notifier).clearMessages();
|
container.read(chat.chatMessagesProvider.notifier).clearMessages();
|
||||||
|
|
||||||
|
// Clear any pending folder selection when selecting an existing conversation
|
||||||
|
container.read(pendingFolderIdProvider.notifier).clear();
|
||||||
|
|
||||||
// Close the slide drawer for faster perceived performance
|
// Close the slide drawer for faster perceived performance
|
||||||
// (only on mobile; keep tablet drawer unless user toggles it)
|
// (only on mobile; keep tablet drawer unless user toggles it)
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
|||||||
Reference in New Issue
Block a user