feat: add web search availability provider and enhance feature toggles in chat and tools modal
This commit is contained in:
@@ -80,12 +80,10 @@ class ThemeModeNotifier extends StateNotifier<ThemeMode> {
|
||||
}
|
||||
|
||||
// Locale provider
|
||||
final localeProvider = StateNotifierProvider<LocaleNotifier, Locale?>(
|
||||
(ref) {
|
||||
final localeProvider = StateNotifierProvider<LocaleNotifier, Locale?>((ref) {
|
||||
final storage = ref.watch(optimizedStorageServiceProvider);
|
||||
return LocaleNotifier(storage);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
class LocaleNotifier extends StateNotifier<Locale?> {
|
||||
final OptimizedStorageService _storage;
|
||||
@@ -957,6 +955,22 @@ final imageGenerationAvailableProvider = Provider<bool>((ref) {
|
||||
);
|
||||
});
|
||||
|
||||
final webSearchAvailableProvider = Provider<bool>((ref) {
|
||||
final perms = ref.watch(userPermissionsProvider);
|
||||
return perms.maybeWhen(
|
||||
data: (data) {
|
||||
final features = data['features'];
|
||||
if (features is Map<String, dynamic>) {
|
||||
final value = features['web_search'];
|
||||
if (value is bool) return value;
|
||||
if (value is String) return value.toLowerCase() == 'true';
|
||||
}
|
||||
return false;
|
||||
},
|
||||
orElse: () => false,
|
||||
);
|
||||
});
|
||||
|
||||
// Folders provider
|
||||
final foldersProvider = FutureProvider<List<Folder>>((ref) async {
|
||||
final api = ref.watch(apiServiceProvider);
|
||||
|
||||
@@ -657,8 +657,10 @@ Future<void> _sendMessageInternal(
|
||||
}
|
||||
}
|
||||
|
||||
// Check feature toggles for API
|
||||
final webSearchEnabled = ref.read(webSearchEnabledProvider);
|
||||
// Check feature toggles for API (gated by server availability)
|
||||
final webSearchEnabled =
|
||||
ref.read(webSearchEnabledProvider) &&
|
||||
ref.read(webSearchAvailableProvider);
|
||||
final imageGenerationEnabled = ref.read(imageGenerationEnabledProvider);
|
||||
|
||||
// Prepare tools list - pass tool IDs directly
|
||||
|
||||
@@ -65,7 +65,12 @@ class _EnhancedImageAttachmentState
|
||||
parent: _animationController,
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
// Defer loading until after first frame to avoid accessing inherited widgets
|
||||
// (e.g., Localizations) during initState
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
_loadImage();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -382,14 +382,13 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
)!.addAttachment,
|
||||
),
|
||||
const SizedBox(width: Spacing.sm),
|
||||
// Quick pills: wrap in horizontal scroller to prevent overflow
|
||||
// Quick pills: no scroll, clip text within fixed max width
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildPillButton(
|
||||
Flexible(
|
||||
fit: FlexFit.loose,
|
||||
child: _buildPillButton(
|
||||
icon: Platform.isIOS
|
||||
? CupertinoIcons.search
|
||||
: Icons.search,
|
||||
@@ -409,9 +408,12 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
}
|
||||
: null,
|
||||
),
|
||||
),
|
||||
if (imageGenAvailable) ...[
|
||||
const SizedBox(width: Spacing.sm),
|
||||
_buildPillButton(
|
||||
Flexible(
|
||||
fit: FlexFit.loose,
|
||||
child: _buildPillButton(
|
||||
icon: Platform.isIOS
|
||||
? CupertinoIcons.photo
|
||||
: Icons.image,
|
||||
@@ -431,9 +433,9 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
}
|
||||
: null,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: Spacing.sm),
|
||||
@@ -705,25 +707,30 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(horizontal: Spacing.md),
|
||||
decoration: BoxDecoration(
|
||||
color: isActive
|
||||
? context.conduitTheme.buttonPrimary
|
||||
: context.conduitTheme.cardBackground,
|
||||
// Align with unified tools modal: keep subtle card background even when active
|
||||
color: context.conduitTheme.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppBorderRadius.xl),
|
||||
// Reduce perceived height variance: only show shadow when active
|
||||
boxShadow: isActive ? ConduitShadows.button : null,
|
||||
// No elevation to match modal chips
|
||||
boxShadow: null,
|
||||
),
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 140),
|
||||
child: Text(
|
||||
label,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: false,
|
||||
style: AppTypography.labelStyle.copyWith(
|
||||
color: isActive
|
||||
? context.conduitTheme.buttonPrimaryText
|
||||
? context.conduitTheme.buttonPrimary
|
||||
: context.conduitTheme.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
|
||||
final webSearchEnabled = ref.watch(webSearchEnabledProvider);
|
||||
final imageGenEnabled = ref.watch(imageGenerationEnabledProvider);
|
||||
final imageGenAvailable = ref.watch(imageGenerationAvailableProvider);
|
||||
final webSearchAvailable = ref.watch(webSearchAvailableProvider);
|
||||
final selectedToolIds = ref.watch(selectedToolIdsProvider);
|
||||
final toolsAsync = ref.watch(toolsListProvider);
|
||||
|
||||
@@ -59,6 +60,7 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
|
||||
// Full tiles for Web and Image features
|
||||
Column(
|
||||
children: [
|
||||
if (webSearchAvailable)
|
||||
_buildFeatureTile(
|
||||
title: AppLocalizations.of(context)!.webSearch,
|
||||
description: AppLocalizations.of(
|
||||
|
||||
Reference in New Issue
Block a user