feat: add web search availability provider and enhance feature toggles in chat and tools modal

This commit is contained in:
cogwheel0
2025-08-24 20:55:51 +05:30
parent cc46799e20
commit 4cd00e9193
5 changed files with 77 additions and 47 deletions

View File

@@ -80,12 +80,10 @@ class ThemeModeNotifier extends StateNotifier<ThemeMode> {
} }
// Locale provider // Locale provider
final localeProvider = StateNotifierProvider<LocaleNotifier, Locale?>( final localeProvider = StateNotifierProvider<LocaleNotifier, Locale?>((ref) {
(ref) {
final storage = ref.watch(optimizedStorageServiceProvider); final storage = ref.watch(optimizedStorageServiceProvider);
return LocaleNotifier(storage); return LocaleNotifier(storage);
}, });
);
class LocaleNotifier extends StateNotifier<Locale?> { class LocaleNotifier extends StateNotifier<Locale?> {
final OptimizedStorageService _storage; 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 // Folders provider
final foldersProvider = FutureProvider<List<Folder>>((ref) async { final foldersProvider = FutureProvider<List<Folder>>((ref) async {
final api = ref.watch(apiServiceProvider); final api = ref.watch(apiServiceProvider);

View File

@@ -657,8 +657,10 @@ Future<void> _sendMessageInternal(
} }
} }
// Check feature toggles for API // Check feature toggles for API (gated by server availability)
final webSearchEnabled = ref.read(webSearchEnabledProvider); final webSearchEnabled =
ref.read(webSearchEnabledProvider) &&
ref.read(webSearchAvailableProvider);
final imageGenerationEnabled = ref.read(imageGenerationEnabledProvider); final imageGenerationEnabled = ref.read(imageGenerationEnabledProvider);
// Prepare tools list - pass tool IDs directly // Prepare tools list - pass tool IDs directly

View File

@@ -65,7 +65,12 @@ class _EnhancedImageAttachmentState
parent: _animationController, parent: _animationController,
curve: Curves.easeInOut, 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(); _loadImage();
});
} }
@override @override

View File

@@ -382,14 +382,13 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
)!.addAttachment, )!.addAttachment,
), ),
const SizedBox(width: Spacing.sm), 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( Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
child: Row( child: Row(
children: [ children: [
_buildPillButton( Flexible(
fit: FlexFit.loose,
child: _buildPillButton(
icon: Platform.isIOS icon: Platform.isIOS
? CupertinoIcons.search ? CupertinoIcons.search
: Icons.search, : Icons.search,
@@ -409,9 +408,12 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
} }
: null, : null,
), ),
),
if (imageGenAvailable) ...[ if (imageGenAvailable) ...[
const SizedBox(width: Spacing.sm), const SizedBox(width: Spacing.sm),
_buildPillButton( Flexible(
fit: FlexFit.loose,
child: _buildPillButton(
icon: Platform.isIOS icon: Platform.isIOS
? CupertinoIcons.photo ? CupertinoIcons.photo
: Icons.image, : Icons.image,
@@ -431,9 +433,9 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
} }
: null, : null,
), ),
],
],
), ),
],
],
), ),
), ),
const SizedBox(width: Spacing.sm), const SizedBox(width: Spacing.sm),
@@ -705,25 +707,30 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
alignment: Alignment.center, alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: Spacing.md), padding: const EdgeInsets.symmetric(horizontal: Spacing.md),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isActive // Align with unified tools modal: keep subtle card background even when active
? context.conduitTheme.buttonPrimary color: context.conduitTheme.cardBackground,
: context.conduitTheme.cardBackground,
borderRadius: BorderRadius.circular(AppBorderRadius.xl), borderRadius: BorderRadius.circular(AppBorderRadius.xl),
// Reduce perceived height variance: only show shadow when active // No elevation to match modal chips
boxShadow: isActive ? ConduitShadows.button : null, boxShadow: null,
), ),
child: Center( child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 140),
child: Text( child: Text(
label, label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
softWrap: false,
style: AppTypography.labelStyle.copyWith( style: AppTypography.labelStyle.copyWith(
color: isActive color: isActive
? context.conduitTheme.buttonPrimaryText ? context.conduitTheme.buttonPrimary
: context.conduitTheme.textPrimary, : context.conduitTheme.textPrimary,
), ),
), ),
), ),
), ),
), ),
),
); );
} }

View File

@@ -25,6 +25,7 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
final webSearchEnabled = ref.watch(webSearchEnabledProvider); final webSearchEnabled = ref.watch(webSearchEnabledProvider);
final imageGenEnabled = ref.watch(imageGenerationEnabledProvider); final imageGenEnabled = ref.watch(imageGenerationEnabledProvider);
final imageGenAvailable = ref.watch(imageGenerationAvailableProvider); final imageGenAvailable = ref.watch(imageGenerationAvailableProvider);
final webSearchAvailable = ref.watch(webSearchAvailableProvider);
final selectedToolIds = ref.watch(selectedToolIdsProvider); final selectedToolIds = ref.watch(selectedToolIdsProvider);
final toolsAsync = ref.watch(toolsListProvider); final toolsAsync = ref.watch(toolsListProvider);
@@ -59,6 +60,7 @@ class _UnifiedToolsModalState extends ConsumerState<UnifiedToolsModal> {
// Full tiles for Web and Image features // Full tiles for Web and Image features
Column( Column(
children: [ children: [
if (webSearchAvailable)
_buildFeatureTile( _buildFeatureTile(
title: AppLocalizations.of(context)!.webSearch, title: AppLocalizations.of(context)!.webSearch,
description: AppLocalizations.of( description: AppLocalizations.of(