feat: image generation
This commit is contained in:
@@ -6,6 +6,7 @@ import 'dart:io' show Platform;
|
||||
import '../../../core/models/tool.dart';
|
||||
import '../../../shared/theme/theme_extensions.dart';
|
||||
import '../../chat/providers/chat_providers.dart';
|
||||
import '../../../core/providers/app_providers.dart';
|
||||
import '../providers/tools_providers.dart';
|
||||
|
||||
class UnifiedToolsModal extends ConsumerStatefulWidget {
|
||||
@@ -19,6 +20,8 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final webSearchEnabled = ref.watch(webSearchEnabledProvider);
|
||||
final imageGenEnabled = ref.watch(imageGenerationEnabledProvider);
|
||||
final imageGenAvailable = ref.watch(imageGenerationAvailableProvider);
|
||||
final selectedToolIds = ref.watch(selectedToolIdsProvider);
|
||||
final toolsAsync = ref.watch(toolsListProvider);
|
||||
|
||||
@@ -60,6 +63,12 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
|
||||
_buildWebSearchToggle(webSearchEnabled),
|
||||
const SizedBox(height: Spacing.md),
|
||||
|
||||
// Image Generation Toggle (conditionally shown)
|
||||
if (imageGenAvailable) ...[
|
||||
_buildImageGenerationToggle(imageGenEnabled),
|
||||
const SizedBox(height: Spacing.md),
|
||||
],
|
||||
|
||||
// Tools Section
|
||||
toolsAsync.when(
|
||||
data: (tools) {
|
||||
@@ -95,10 +104,15 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: Spacing.sm),
|
||||
...tools.map((tool) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: Spacing.sm),
|
||||
child: _buildToolCard(tool, selectedToolIds.contains(tool.id)),
|
||||
)),
|
||||
...tools.map(
|
||||
(tool) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: Spacing.sm),
|
||||
child: _buildToolCard(
|
||||
tool,
|
||||
selectedToolIds.contains(tool.id),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -221,17 +235,95 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildImageGenerationToggle(bool imageGenEnabled) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
HapticFeedback.lightImpact();
|
||||
ref.read(imageGenerationEnabledProvider.notifier).state =
|
||||
!imageGenEnabled;
|
||||
},
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(Spacing.md),
|
||||
decoration: BoxDecoration(
|
||||
color: imageGenEnabled
|
||||
? context.conduitTheme.buttonPrimary
|
||||
: context.conduitTheme.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppBorderRadius.md),
|
||||
border: Border.all(
|
||||
color: imageGenEnabled
|
||||
? context.conduitTheme.buttonPrimary
|
||||
: context.conduitTheme.cardBorder,
|
||||
width: BorderWidth.regular,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Platform.isIOS ? CupertinoIcons.photo : Icons.image,
|
||||
size: IconSize.medium,
|
||||
color: imageGenEnabled
|
||||
? context.conduitTheme.buttonPrimaryText
|
||||
: context.conduitTheme.textPrimary.withValues(
|
||||
alpha: Alpha.strong,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: Spacing.sm),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Image Generation',
|
||||
style: AppTypography.labelStyle.copyWith(
|
||||
color: imageGenEnabled
|
||||
? context.conduitTheme.buttonPrimaryText
|
||||
: context.conduitTheme.textPrimary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
imageGenEnabled
|
||||
? 'I can generate images from your prompt'
|
||||
: 'Enable to generate images with your request',
|
||||
style: AppTypography.captionStyle.copyWith(
|
||||
color: imageGenEnabled
|
||||
? context.conduitTheme.buttonPrimaryText.withValues(
|
||||
alpha: Alpha.strong,
|
||||
)
|
||||
: context.conduitTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
imageGenEnabled ? Icons.toggle_on : Icons.toggle_off,
|
||||
size: IconSize.large,
|
||||
color: imageGenEnabled
|
||||
? context.conduitTheme.buttonPrimaryText
|
||||
: context.conduitTheme.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildToolCard(Tool tool, bool isSelected) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
HapticFeedback.lightImpact();
|
||||
final currentIds = ref.read(selectedToolIdsProvider);
|
||||
if (isSelected) {
|
||||
ref.read(selectedToolIdsProvider.notifier).state =
|
||||
currentIds.where((id) => id != tool.id).toList();
|
||||
ref.read(selectedToolIdsProvider.notifier).state = currentIds
|
||||
.where((id) => id != tool.id)
|
||||
.toList();
|
||||
} else {
|
||||
ref.read(selectedToolIdsProvider.notifier).state =
|
||||
[...currentIds, tool.id];
|
||||
ref.read(selectedToolIdsProvider.notifier).state = [
|
||||
...currentIds,
|
||||
tool.id,
|
||||
];
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
@@ -274,7 +366,7 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
if (tool.meta?['description'] != null &&
|
||||
if (tool.meta?['description'] != null &&
|
||||
tool.meta!['description'].toString().isNotEmpty)
|
||||
Text(
|
||||
tool.meta!['description'].toString(),
|
||||
@@ -306,11 +398,13 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
|
||||
|
||||
IconData _getToolIcon(Tool tool) {
|
||||
final toolName = tool.name.toLowerCase();
|
||||
|
||||
|
||||
if (toolName.contains('image') || toolName.contains('vision')) {
|
||||
return Platform.isIOS ? CupertinoIcons.photo : Icons.image;
|
||||
} else if (toolName.contains('code') || toolName.contains('python')) {
|
||||
return Platform.isIOS ? CupertinoIcons.chevron_left_slash_chevron_right : Icons.code;
|
||||
return Platform.isIOS
|
||||
? CupertinoIcons.chevron_left_slash_chevron_right
|
||||
: Icons.code;
|
||||
} else if (toolName.contains('calculator') || toolName.contains('math')) {
|
||||
return Icons.calculate;
|
||||
} else if (toolName.contains('file') || toolName.contains('document')) {
|
||||
|
||||
Reference in New Issue
Block a user