refactor: ux
This commit is contained in:
@@ -50,6 +50,8 @@ PODS:
|
|||||||
- SDWebImage (5.21.1):
|
- SDWebImage (5.21.1):
|
||||||
- SDWebImage/Core (= 5.21.1)
|
- SDWebImage/Core (= 5.21.1)
|
||||||
- SDWebImage/Core (5.21.1)
|
- SDWebImage/Core (5.21.1)
|
||||||
|
- share_plus (0.0.1):
|
||||||
|
- Flutter
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
@@ -71,6 +73,7 @@ DEPENDENCIES:
|
|||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- record_ios (from `.symlinks/plugins/record_ios/ios`)
|
- record_ios (from `.symlinks/plugins/record_ios/ios`)
|
||||||
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
@@ -100,6 +103,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
record_ios:
|
record_ios:
|
||||||
:path: ".symlinks/plugins/record_ios/ios"
|
:path: ".symlinks/plugins/record_ios/ios"
|
||||||
|
share_plus:
|
||||||
|
:path: ".symlinks/plugins/share_plus/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||||
sqflite_darwin:
|
sqflite_darwin:
|
||||||
@@ -121,6 +126,7 @@ SPEC CHECKSUMS:
|
|||||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||||
record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b
|
record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b
|
||||||
SDWebImage: f29024626962457f3470184232766516dee8dfea
|
SDWebImage: f29024626962457f3470184232766516dee8dfea
|
||||||
|
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
import 'dart:io' show Platform, File;
|
import 'dart:io' show Platform, File;
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:path/path.dart' as path;
|
|
||||||
import '../../../core/providers/app_providers.dart';
|
import '../../../core/providers/app_providers.dart';
|
||||||
import '../providers/chat_providers.dart';
|
import '../providers/chat_providers.dart';
|
||||||
import '../../../core/utils/debug_logger.dart';
|
import '../../../core/utils/debug_logger.dart';
|
||||||
@@ -247,11 +246,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
|
|
||||||
if (selectedModel == null) {
|
if (selectedModel == null) {
|
||||||
debugPrint('DEBUG: No model selected');
|
debugPrint('DEBUG: No model selected');
|
||||||
if (mounted) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text('Please select a model first')),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,16 +256,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
);
|
);
|
||||||
if (!isOnline && !isReviewerMode) {
|
if (!isOnline && !isReviewerMode) {
|
||||||
debugPrint('DEBUG: Offline - cannot send message');
|
debugPrint('DEBUG: Offline - cannot send message');
|
||||||
if (mounted) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: const Text(
|
|
||||||
'You\'re offline. Message will be sent when connection is restored.',
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.warning,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,22 +312,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('DEBUG: Message send error: $e');
|
debugPrint('DEBUG: Message send error: $e');
|
||||||
if (mounted) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: const Text(
|
|
||||||
'Message failed to send. Check your connection and try again.',
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
action: SnackBarAction(
|
|
||||||
label: 'Retry',
|
|
||||||
textColor: Colors.white,
|
|
||||||
onPressed: () => _handleMessageSend(text, selectedModel),
|
|
||||||
),
|
|
||||||
duration: const Duration(seconds: 6),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,12 +321,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
|
|
||||||
if (!isAvailable) {
|
if (!isAvailable) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: const Text('Voice input unavailable. Check permissions.'),
|
|
||||||
backgroundColor: context.conduitTheme.warning,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,20 +348,11 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
final fileUploadCapableModels = ref.read(fileUploadCapableModelsProvider);
|
final fileUploadCapableModels = ref.read(fileUploadCapableModelsProvider);
|
||||||
if (fileUploadCapableModels.isEmpty) {
|
if (fileUploadCapableModels.isEmpty) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: const Text('Selected model does not support file upload'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final fileService = ref.read(fileAttachmentServiceProvider);
|
final fileService = ref.read(fileAttachmentServiceProvider);
|
||||||
if (fileService == null) {
|
if (fileService == null) {
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(const SnackBar(content: Text('File service unavailable')));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,12 +364,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
final currentFiles = ref.read(attachedFilesProvider);
|
final currentFiles = ref.read(attachedFilesProvider);
|
||||||
if (!validateFileCount(currentFiles.length, files.length, 10)) {
|
if (!validateFileCount(currentFiles.length, files.length, 10)) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: const Text('Maximum 10 files allowed'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,14 +372,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
final fileSize = await file.length();
|
final fileSize = await file.length();
|
||||||
if (!validateFileSize(fileSize, 20)) {
|
if (!validateFileSize(fileSize, 20)) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'File ${path.basename(file.path)} exceeds 20MB limit',
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -451,23 +390,13 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
},
|
},
|
||||||
onError: (error) {
|
onError: (error) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
debugPrint('Upload failed: $error');
|
||||||
SnackBar(
|
|
||||||
content: Text('Upload failed: $error'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
debugPrint('File selection failed: $e');
|
||||||
SnackBar(
|
|
||||||
content: Text('File selection failed: $e'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,21 +409,12 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
final visionCapableModels = ref.read(visionCapableModelsProvider);
|
final visionCapableModels = ref.read(visionCapableModelsProvider);
|
||||||
if (visionCapableModels.isEmpty) {
|
if (visionCapableModels.isEmpty) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: const Text('Selected model does not support image inputs'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final fileService = ref.read(fileAttachmentServiceProvider);
|
final fileService = ref.read(fileAttachmentServiceProvider);
|
||||||
if (fileService == null) {
|
if (fileService == null) {
|
||||||
debugPrint('DEBUG: File service is null - cannot proceed');
|
debugPrint('DEBUG: File service is null - cannot proceed');
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(const SnackBar(content: Text('File service unavailable')));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,12 +435,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
// Validate file size (default 20MB limit like OpenWebUI)
|
// Validate file size (default 20MB limit like OpenWebUI)
|
||||||
if (!validateFileSize(imageSize, 20)) {
|
if (!validateFileSize(imageSize, 20)) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: const Text('Image size exceeds 20MB limit'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,12 +442,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
final currentFiles = ref.read(attachedFilesProvider);
|
final currentFiles = ref.read(attachedFilesProvider);
|
||||||
if (!validateFileCount(currentFiles.length, 1, 10)) {
|
if (!validateFileCount(currentFiles.length, 1, 10)) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: const Text('Maximum 10 files allowed'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,23 +464,11 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
onError: (error) {
|
onError: (error) {
|
||||||
debugPrint('DEBUG: Image upload error: $error');
|
debugPrint('DEBUG: Image upload error: $error');
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Image upload failed: $error'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('DEBUG: Image attachment error: $e');
|
debugPrint('DEBUG: Image attachment error: $e');
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Image attachment failed: $e'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,14 +482,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
_showScrollToBottom = false;
|
_showScrollToBottom = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show success message
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('New chat started'),
|
|
||||||
duration: Duration(seconds: 2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showChatsListOverlay() {
|
void _showChatsListOverlay() {
|
||||||
@@ -1029,20 +917,11 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
|
|
||||||
void _copyMessage(String content) {
|
void _copyMessage(String content) {
|
||||||
Clipboard.setData(ClipboardData(text: content));
|
Clipboard.setData(ClipboardData(text: content));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('Copied to clipboard'),
|
|
||||||
duration: Duration(seconds: 2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _regenerateMessage(dynamic message) async {
|
void _regenerateMessage(dynamic message) async {
|
||||||
final selectedModel = ref.read(selectedModelProvider);
|
final selectedModel = ref.read(selectedModelProvider);
|
||||||
if (selectedModel == null) {
|
if (selectedModel == null) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text('Please select a model first')),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1051,9 +930,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
final messageIndex = messages.indexOf(message);
|
final messageIndex = messages.indexOf(message);
|
||||||
|
|
||||||
if (messageIndex <= 0 || messages[messageIndex - 1].role != 'user') {
|
if (messageIndex <= 0 || messages[messageIndex - 1].role != 'user') {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text('Cannot regenerate this message')),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1068,40 +944,13 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
userMessage.content,
|
userMessage.content,
|
||||||
userMessage.attachmentIds,
|
userMessage.attachmentIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('Regenerating...'),
|
|
||||||
duration: Duration(seconds: 2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
debugPrint('Regenerate failed: $e');
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Failed to regenerate message. Try again or check your connection.',
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
action: SnackBarAction(
|
|
||||||
label: 'Retry',
|
|
||||||
textColor: Colors.white,
|
|
||||||
onPressed: () => _regenerateMessage(message),
|
|
||||||
),
|
|
||||||
duration: const Duration(seconds: 6),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _editMessage(dynamic message) async {
|
void _editMessage(dynamic message) async {
|
||||||
if (message.role != 'user') {
|
if (message.role != 'user') {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text('Only user messages can be edited')),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1170,25 +1019,11 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
if (selectedModel != null) {
|
if (selectedModel != null) {
|
||||||
await sendMessage(ref, result, null);
|
await sendMessage(ref, result, null);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('Message updated'),
|
|
||||||
duration: Duration(seconds: 2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Failed to edit message: $e'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1197,16 +1032,10 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
|
|
||||||
void _likeMessage(dynamic message) {
|
void _likeMessage(dynamic message) {
|
||||||
// TODO: Implement message liking
|
// TODO: Implement message liking
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(const SnackBar(content: Text('Message liked!')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _dislikeMessage(dynamic message) {
|
void _dislikeMessage(dynamic message) {
|
||||||
// TODO: Implement message disliking
|
// TODO: Implement message disliking
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(const SnackBar(content: Text('Message disliked!')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEmptyState(ThemeData theme) {
|
Widget _buildEmptyState(ThemeData theme) {
|
||||||
@@ -1755,14 +1584,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
// ref.read(chatMessagesProvider.notifier).removeMessage(selectedMessage.id);
|
// ref.read(chatMessagesProvider.notifier).removeMessage(selectedMessage.id);
|
||||||
// }
|
// }
|
||||||
_clearSelection();
|
_clearSelection();
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('Messages removed'),
|
|
||||||
duration: Duration(seconds: 2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2249,28 +2071,14 @@ class _VoiceInputSheetState extends ConsumerState<_VoiceInputSheet> {
|
|||||||
_isListening = false;
|
_isListening = false;
|
||||||
});
|
});
|
||||||
_elapsedTimer?.cancel();
|
_elapsedTimer?.cancel();
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Voice input error: $error'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isListening = false;
|
_isListening = false;
|
||||||
});
|
});
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Failed to start voice input: $e'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2304,12 +2112,6 @@ class _VoiceInputSheetState extends ConsumerState<_VoiceInputSheet> {
|
|||||||
setState(() => _isListening = false);
|
setState(() => _isListening = false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Transcription failed: $e'),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
setState(() => _isListening = false);
|
setState(() => _isListening = false);
|
||||||
} finally {
|
} finally {
|
||||||
if (mounted) setState(() => _isTranscribing = false);
|
if (mounted) setState(() => _isTranscribing = false);
|
||||||
|
|||||||
@@ -313,9 +313,11 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Action buttons below the message content (always visible)
|
// Action buttons below the message content (only after streaming completes)
|
||||||
const SizedBox(height: Spacing.sm),
|
if (!widget.isStreaming) ...[
|
||||||
_buildActionButtons(),
|
const SizedBox(height: Spacing.sm),
|
||||||
|
_buildActionButtons(),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -387,15 +389,23 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
|
|||||||
child: EnhancedImageAttachment(
|
child: EnhancedImageAttachment(
|
||||||
attachmentId: widget.message.attachmentIds![0],
|
attachmentId: widget.message.attachmentIds![0],
|
||||||
isMarkdownFormat: true,
|
isMarkdownFormat: true,
|
||||||
constraints: const BoxConstraints(maxWidth: 500, maxHeight: 400),
|
constraints: const BoxConstraints(
|
||||||
disableAnimation: widget.isStreaming, // Disable animation during streaming
|
maxWidth: 500,
|
||||||
|
maxHeight: 400,
|
||||||
|
),
|
||||||
|
disableAnimation:
|
||||||
|
widget.isStreaming, // Disable animation during streaming
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Wrap(
|
: Wrap(
|
||||||
key: ValueKey('multi_images_${widget.message.attachmentIds!.join('_')}'),
|
key: ValueKey(
|
||||||
|
'multi_images_${widget.message.attachmentIds!.join('_')}',
|
||||||
|
),
|
||||||
spacing: Spacing.sm,
|
spacing: Spacing.sm,
|
||||||
runSpacing: Spacing.sm,
|
runSpacing: Spacing.sm,
|
||||||
children: widget.message.attachmentIds!.map<Widget>((attachmentId) {
|
children: widget.message.attachmentIds!.map<Widget>((
|
||||||
|
attachmentId,
|
||||||
|
) {
|
||||||
return EnhancedImageAttachment(
|
return EnhancedImageAttachment(
|
||||||
key: ValueKey('attachment_$attachmentId'),
|
key: ValueKey('attachment_$attachmentId'),
|
||||||
attachmentId: attachmentId,
|
attachmentId: attachmentId,
|
||||||
@@ -404,7 +414,8 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
|
|||||||
maxWidth: imageCount == 2 ? 245 : 160,
|
maxWidth: imageCount == 2 ? 245 : 160,
|
||||||
maxHeight: imageCount == 2 ? 245 : 160,
|
maxHeight: imageCount == 2 ? 245 : 160,
|
||||||
),
|
),
|
||||||
disableAnimation: widget.isStreaming, // Disable animation during streaming
|
disableAnimation:
|
||||||
|
widget.isStreaming, // Disable animation during streaming
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
@@ -415,7 +426,7 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
|
|||||||
if (widget.message.files == null || widget.message.files!.isEmpty) {
|
if (widget.message.files == null || widget.message.files!.isEmpty) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter for image files
|
// Filter for image files
|
||||||
final imageFiles = widget.message.files!
|
final imageFiles = widget.message.files!
|
||||||
.where((file) => file['type'] == 'image')
|
.where((file) => file['type'] == 'image')
|
||||||
@@ -439,24 +450,31 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
|
|||||||
builder: (context) {
|
builder: (context) {
|
||||||
final imageUrl = imageFiles[0]['url'] as String?;
|
final imageUrl = imageFiles[0]['url'] as String?;
|
||||||
if (imageUrl == null) return const SizedBox.shrink();
|
if (imageUrl == null) return const SizedBox.shrink();
|
||||||
|
|
||||||
return EnhancedImageAttachment(
|
return EnhancedImageAttachment(
|
||||||
attachmentId: imageUrl, // Pass URL directly as it handles URLs
|
attachmentId:
|
||||||
|
imageUrl, // Pass URL directly as it handles URLs
|
||||||
isMarkdownFormat: true,
|
isMarkdownFormat: true,
|
||||||
constraints: const BoxConstraints(maxWidth: 500, maxHeight: 400),
|
constraints: const BoxConstraints(
|
||||||
disableAnimation: widget.isStreaming, // Disable animation during streaming
|
maxWidth: 500,
|
||||||
|
maxHeight: 400,
|
||||||
|
),
|
||||||
|
disableAnimation: widget
|
||||||
|
.isStreaming, // Disable animation during streaming
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Wrap(
|
: Wrap(
|
||||||
key: ValueKey('gen_multi_${imageFiles.map((f) => f['url']).join('_')}'),
|
key: ValueKey(
|
||||||
|
'gen_multi_${imageFiles.map((f) => f['url']).join('_')}',
|
||||||
|
),
|
||||||
spacing: Spacing.sm,
|
spacing: Spacing.sm,
|
||||||
runSpacing: Spacing.sm,
|
runSpacing: Spacing.sm,
|
||||||
children: imageFiles.map<Widget>((file) {
|
children: imageFiles.map<Widget>((file) {
|
||||||
final imageUrl = file['url'] as String?;
|
final imageUrl = file['url'] as String?;
|
||||||
if (imageUrl == null) return const SizedBox.shrink();
|
if (imageUrl == null) return const SizedBox.shrink();
|
||||||
|
|
||||||
return EnhancedImageAttachment(
|
return EnhancedImageAttachment(
|
||||||
key: ValueKey('gen_attachment_$imageUrl'),
|
key: ValueKey('gen_attachment_$imageUrl'),
|
||||||
attachmentId: imageUrl, // Pass URL directly
|
attachmentId: imageUrl, // Pass URL directly
|
||||||
@@ -465,7 +483,8 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
|
|||||||
maxWidth: imageCount == 2 ? 245 : 160,
|
maxWidth: imageCount == 2 ? 245 : 160,
|
||||||
maxHeight: imageCount == 2 ? 245 : 160,
|
maxHeight: imageCount == 2 ? 245 : 160,
|
||||||
),
|
),
|
||||||
disableAnimation: widget.isStreaming, // Disable animation during streaming
|
disableAnimation:
|
||||||
|
widget.isStreaming, // Disable animation during streaming
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -725,9 +725,8 @@ class FullScreenImageViewer extends ConsumerWidget {
|
|||||||
|
|
||||||
await SharePlus.instance.share(ShareParams(files: [XFile(file.path)]));
|
await SharePlus.instance.share(ShareParams(files: [XFile(file.path)]));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ScaffoldMessenger.of(
|
// Swallowing UI feedback per requirements; keep a log for debugging
|
||||||
context,
|
debugPrint('Failed to share image: $e');
|
||||||
).showSnackBar(const SnackBar(content: Text('Failed to share image')));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,36 +307,13 @@ class CopyOptionsSheet extends ConsumerWidget {
|
|||||||
if (content != null) {
|
if (content != null) {
|
||||||
await Clipboard.setData(ClipboardData(text: content));
|
await Clipboard.setData(ClipboardData(text: content));
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'${messages.length} messages copied to clipboard',
|
|
||||||
),
|
|
||||||
backgroundColor: AppTheme.success,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Failed to copy messages: ${result.error}'),
|
|
||||||
backgroundColor: AppTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Error copying messages: $e'),
|
|
||||||
backgroundColor: AppTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -652,21 +629,10 @@ class MoreOptionsSheet extends ConsumerWidget {
|
|||||||
controller.clear();
|
controller.clear();
|
||||||
setState(() {}); // Refresh the dialog
|
setState(() {}); // Refresh the dialog
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text('Tag "$tag" added')),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Failed to add tag: $e'),
|
|
||||||
backgroundColor: AppTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -730,28 +696,10 @@ class MoreOptionsSheet extends ConsumerWidget {
|
|||||||
);
|
);
|
||||||
setState(() {}); // Refresh the dialog
|
setState(() {}); // Refresh the dialog
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Tag "$tag" removed'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Failed to remove tag: $e',
|
|
||||||
),
|
|
||||||
backgroundColor:
|
|
||||||
context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -818,23 +766,12 @@ class MoreOptionsSheet extends ConsumerWidget {
|
|||||||
ref.invalidate(archivedConversationsProvider);
|
ref.invalidate(archivedConversationsProvider);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text('Conversation archived')),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Navigate back or clear current conversation
|
// Navigate back or clear current conversation
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Failed to archive conversation: $e'),
|
|
||||||
backgroundColor: AppTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -848,7 +785,7 @@ class MoreOptionsSheet extends ConsumerWidget {
|
|||||||
confirmText: 'Delete',
|
confirmText: 'Delete',
|
||||||
isDestructive: true,
|
isDestructive: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (confirmed == true && context.mounted) {
|
if (confirmed == true && context.mounted) {
|
||||||
_deleteMessages(context, ref);
|
_deleteMessages(context, ref);
|
||||||
}
|
}
|
||||||
@@ -880,23 +817,12 @@ class MoreOptionsSheet extends ConsumerWidget {
|
|||||||
ref.read(chatMessagesProvider.notifier).clearMessages();
|
ref.read(chatMessagesProvider.notifier).clearMessages();
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text('Conversation deleted')),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Navigate back to conversation list
|
// Navigate back to conversation list
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Failed to delete conversation: $e'),
|
|
||||||
backgroundColor: AppTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -280,6 +280,8 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
|||||||
autofocus: false,
|
autofocus: false,
|
||||||
maxLines: _isExpanded ? null : 1,
|
maxLines: _isExpanded ? null : 1,
|
||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
|
textCapitalization:
|
||||||
|
TextCapitalization.sentences,
|
||||||
textInputAction: TextInputAction.newline,
|
textInputAction: TextInputAction.newline,
|
||||||
showCursor: true,
|
showCursor: true,
|
||||||
cursorColor: context.conduitTheme.inputText,
|
cursorColor: context.conduitTheme.inputText,
|
||||||
|
|||||||
@@ -213,20 +213,9 @@ class _TagManagementDialogState extends ConsumerState<TagManagementDialog> {
|
|||||||
ref.invalidate(conversationsProvider);
|
ref.invalidate(conversationsProvider);
|
||||||
_tagController.clear();
|
_tagController.clear();
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(SnackBar(content: Text('Tag "$tag" added')));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Error adding tag: $e'),
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
setState(() => _isAdding = false);
|
setState(() => _isAdding = false);
|
||||||
}
|
}
|
||||||
@@ -240,20 +229,9 @@ class _TagManagementDialogState extends ConsumerState<TagManagementDialog> {
|
|||||||
await api.removeTagFromConversation(widget.conversation.id, tag);
|
await api.removeTagFromConversation(widget.conversation.id, tag);
|
||||||
ref.invalidate(conversationsProvider);
|
ref.invalidate(conversationsProvider);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(SnackBar(content: Text('Tag "$tag" removed')));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Error removing tag: $e'),
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1295,12 +1295,7 @@ class _ChatsListPageState extends ConsumerState<ChatsListPage>
|
|||||||
String name,
|
String name,
|
||||||
BuildContext dialogContext,
|
BuildContext dialogContext,
|
||||||
) async {
|
) async {
|
||||||
// Store theme values and messenger before async operation
|
// Begin async operation
|
||||||
final theme = context.conduitTheme;
|
|
||||||
final textInverseColor = theme.textInverse;
|
|
||||||
final successColor = theme.success;
|
|
||||||
final errorColor = theme.error;
|
|
||||||
final messenger = ScaffoldMessenger.of(context);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final api = ref.read(apiServiceProvider);
|
final api = ref.read(apiServiceProvider);
|
||||||
@@ -1312,33 +1307,9 @@ class _ChatsListPageState extends ConsumerState<ChatsListPage>
|
|||||||
if (mounted && dialogContext.mounted) {
|
if (mounted && dialogContext.mounted) {
|
||||||
Navigator.pop(dialogContext);
|
Navigator.pop(dialogContext);
|
||||||
}
|
}
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
messenger.showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Folder "$name" created',
|
|
||||||
style: AppTypography.bodyMediumStyle.copyWith(
|
|
||||||
color: textInverseColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: successColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {}
|
||||||
messenger.showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Failed to create folder: $e',
|
|
||||||
style: AppTypography.bodyMediumStyle.copyWith(
|
|
||||||
color: textInverseColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: errorColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1352,35 +1323,11 @@ class _ChatsListPageState extends ConsumerState<ChatsListPage>
|
|||||||
// Refresh conversations list
|
// Refresh conversations list
|
||||||
ref.invalidate(conversationsProvider);
|
ref.invalidate(conversationsProvider);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
newPinnedState ? 'Chat pinned' : 'Chat unpinned',
|
|
||||||
style: AppTypography.bodyMediumStyle.copyWith(
|
|
||||||
color: context.conduitTheme.textInverse,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.success,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
DebugLogger.error('Error toggling pin', e);
|
DebugLogger.error('Error toggling pin', e);
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Failed to ${conversation.pinned == true ? 'unpin' : 'pin'} chat',
|
|
||||||
style: AppTypography.bodyMediumStyle.copyWith(
|
|
||||||
color: context.conduitTheme.textInverse,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1393,35 +1340,11 @@ class _ChatsListPageState extends ConsumerState<ChatsListPage>
|
|||||||
// Refresh conversations list
|
// Refresh conversations list
|
||||||
ref.invalidate(conversationsProvider);
|
ref.invalidate(conversationsProvider);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Chat archived',
|
|
||||||
style: AppTypography.bodyMediumStyle.copyWith(
|
|
||||||
color: context.conduitTheme.textInverse,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.success,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
DebugLogger.error('Error archiving conversation', e);
|
DebugLogger.error('Error archiving conversation', e);
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Failed to archive chat',
|
|
||||||
style: AppTypography.bodyMediumStyle.copyWith(
|
|
||||||
color: context.conduitTheme.textInverse,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1446,35 +1369,11 @@ class _ChatsListPageState extends ConsumerState<ChatsListPage>
|
|||||||
// Refresh conversations list
|
// Refresh conversations list
|
||||||
ref.invalidate(conversationsProvider);
|
ref.invalidate(conversationsProvider);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Chat deleted',
|
|
||||||
style: AppTypography.bodyMediumStyle.copyWith(
|
|
||||||
color: context.conduitTheme.textInverse,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.success,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
DebugLogger.error('Error deleting conversation', e);
|
DebugLogger.error('Error deleting conversation', e);
|
||||||
if (mounted) {
|
if (mounted) {}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Failed to delete chat',
|
|
||||||
style: AppTypography.bodyMediumStyle.copyWith(
|
|
||||||
color: context.conduitTheme.textInverse,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: context.conduitTheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user