add setting to disable automatic clipboard access (#159)
This commit is contained in:
+18
-14
@@ -541,23 +541,27 @@ class _BrowserViewState extends ConsumerState<BrowserView>
|
|||||||
if (_suggestionCountTime != null &&
|
if (_suggestionCountTime != null &&
|
||||||
DateTime.now().difference(_suggestionCountTime!) >
|
DateTime.now().difference(_suggestionCountTime!) >
|
||||||
widget.suggestionTimeout) {
|
widget.suggestionTimeout) {
|
||||||
|
final topRoute = ref.read(currentTopRouteProvider);
|
||||||
|
|
||||||
//Don't do anything if a child route is active
|
//Don't do anything if a child route is active
|
||||||
if (GoRouterState.of(context).topRoute?.name == BrowserRoute.name) {
|
if (topRoute is GoRoute && topRoute.name == BrowserRoute.name) {
|
||||||
final settings = ref.read(generalSettingsWithDefaultsProvider);
|
final settings = ref.read(generalSettingsWithDefaultsProvider);
|
||||||
|
|
||||||
unawaited(
|
if (settings.allowClipboardAccess) {
|
||||||
showSuggestNewTabMessage(
|
unawaited(
|
||||||
context,
|
showSuggestNewTabMessage(
|
||||||
onAdd: (searchText) async {
|
context,
|
||||||
await SearchRoute(
|
onAdd: (searchText) async {
|
||||||
tabType:
|
await SearchRoute(
|
||||||
ref.read(selectedTabTypeProvider) ??
|
tabType:
|
||||||
settings.defaultCreateTabType,
|
ref.read(selectedTabTypeProvider) ??
|
||||||
searchText: searchText ?? SearchRoute.emptySearchText,
|
settings.defaultCreateTabType,
|
||||||
).push(context);
|
searchText: searchText ?? SearchRoute.emptySearchText,
|
||||||
},
|
).push(context);
|
||||||
),
|
},
|
||||||
);
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -23,6 +23,7 @@ import 'package:riverpod/riverpod.dart';
|
|||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:weblibre/features/geckoview/domain/providers.dart';
|
import 'package:weblibre/features/geckoview/domain/providers.dart';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
|
|
||||||
part 'engine_suggestions.g.dart';
|
part 'engine_suggestions.g.dart';
|
||||||
|
|
||||||
@@ -39,9 +40,17 @@ class EngineSuggestions extends _$EngineSuggestions {
|
|||||||
String query, {
|
String query, {
|
||||||
List<GeckoSuggestionType> providers = const [GeckoSuggestionType.history],
|
List<GeckoSuggestionType> providers = const [GeckoSuggestionType.history],
|
||||||
}) {
|
}) {
|
||||||
|
final allowClipboard = ref.read(
|
||||||
|
generalSettingsWithDefaultsProvider.select((s) => s.allowClipboardAccess),
|
||||||
|
);
|
||||||
|
|
||||||
return ref
|
return ref
|
||||||
.read(engineSuggestionsServiceProvider)
|
.read(engineSuggestionsServiceProvider)
|
||||||
.querySuggestions(query, providers: providers);
|
.querySuggestions(
|
||||||
|
query,
|
||||||
|
providers: providers,
|
||||||
|
allowClipboard: allowClipboard,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ final class EngineSuggestionsProvider
|
|||||||
EngineSuggestions create() => EngineSuggestions();
|
EngineSuggestions create() => EngineSuggestions();
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$engineSuggestionsHash() => r'ba2c2d7f0a5e99fd9e639acd020b8cf3016c6126';
|
String _$engineSuggestionsHash() => r'10d4a8a53d184b6c1d107d8634a2f662dfd297f1';
|
||||||
|
|
||||||
abstract class _$EngineSuggestions
|
abstract class _$EngineSuggestions
|
||||||
extends $StreamNotifier<List<GeckoSuggestion>> {
|
extends $StreamNotifier<List<GeckoSuggestion>> {
|
||||||
|
|||||||
+12
-2
@@ -20,16 +20,26 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/hooks/cached_future.dart';
|
import 'package:weblibre/presentation/hooks/cached_future.dart';
|
||||||
import 'package:weblibre/utils/clipboard.dart';
|
import 'package:weblibre/utils/clipboard.dart';
|
||||||
|
|
||||||
class ClipboardFillLink extends HookWidget {
|
class ClipboardFillLink extends HookConsumerWidget {
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
|
||||||
const ClipboardFillLink({super.key, required this.controller});
|
const ClipboardFillLink({super.key, required this.controller});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final allowClipboardAccess = ref.watch(
|
||||||
|
generalSettingsWithDefaultsProvider.select((s) => s.allowClipboardAccess),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowClipboardAccess) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
final clipboardUrl = useCachedFuture(() => tryGetUriFromClipboard());
|
final clipboardUrl = useCachedFuture(() => tryGetUriFromClipboard());
|
||||||
final currentText = useValueListenable(controller);
|
final currentText = useValueListenable(controller);
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class _SearchSection extends StatelessWidget {
|
|||||||
_BangsTile(),
|
_BangsTile(),
|
||||||
_AutocompleteProviderSection(),
|
_AutocompleteProviderSection(),
|
||||||
_MaxSearchHistoryEntriesSection(),
|
_MaxSearchHistoryEntriesSection(),
|
||||||
|
_AllowClipboardAccessTile(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -470,3 +471,29 @@ class _AddonCollectionTile extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _AllowClipboardAccessTile extends HookConsumerWidget {
|
||||||
|
const _AllowClipboardAccessTile();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final allowClipboardAccess = ref.watch(
|
||||||
|
generalSettingsWithDefaultsProvider.select((s) => s.allowClipboardAccess),
|
||||||
|
);
|
||||||
|
|
||||||
|
return SwitchListTile.adaptive(
|
||||||
|
title: const Text('Allow clipboard access for suggestions'),
|
||||||
|
subtitle: const Text('Browser can read clipboard to suggest URLs'),
|
||||||
|
secondary: const Icon(MdiIcons.clipboardTextOutline),
|
||||||
|
value: allowClipboardAccess,
|
||||||
|
onChanged: (value) async {
|
||||||
|
await ref
|
||||||
|
.read(saveGeneralSettingsControllerProvider.notifier)
|
||||||
|
.save(
|
||||||
|
(currentSettings) =>
|
||||||
|
currentSettings.copyWith.allowClipboardAccess(value),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
final bool doubleBackCloseTab;
|
final bool doubleBackCloseTab;
|
||||||
final Duration unassignedTabsAutoCleanInterval;
|
final Duration unassignedTabsAutoCleanInterval;
|
||||||
final int maxSearchHistoryEntries;
|
final int maxSearchHistoryEntries;
|
||||||
|
final bool allowClipboardAccess;
|
||||||
|
|
||||||
GeneralSettings({
|
GeneralSettings({
|
||||||
required this.themeMode,
|
required this.themeMode,
|
||||||
@@ -112,6 +113,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
required this.doubleBackCloseTab,
|
required this.doubleBackCloseTab,
|
||||||
required this.unassignedTabsAutoCleanInterval,
|
required this.unassignedTabsAutoCleanInterval,
|
||||||
required this.maxSearchHistoryEntries,
|
required this.maxSearchHistoryEntries,
|
||||||
|
required this.allowClipboardAccess,
|
||||||
});
|
});
|
||||||
|
|
||||||
GeneralSettings.withDefaults({
|
GeneralSettings.withDefaults({
|
||||||
@@ -140,6 +142,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
bool? doubleBackCloseTab,
|
bool? doubleBackCloseTab,
|
||||||
Duration? unassignedTabsAutoCleanInterval,
|
Duration? unassignedTabsAutoCleanInterval,
|
||||||
int? maxSearchHistoryEntries,
|
int? maxSearchHistoryEntries,
|
||||||
|
bool? allowClipboardAccess,
|
||||||
}) : themeMode = themeMode ?? ThemeMode.dark,
|
}) : themeMode = themeMode ?? ThemeMode.dark,
|
||||||
enableReadability = enableReadability ?? true,
|
enableReadability = enableReadability ?? true,
|
||||||
enforceReadability = enforceReadability ?? false,
|
enforceReadability = enforceReadability ?? false,
|
||||||
@@ -168,7 +171,8 @@ class GeneralSettings with FastEquatable {
|
|||||||
doubleBackCloseTab = doubleBackCloseTab ?? true,
|
doubleBackCloseTab = doubleBackCloseTab ?? true,
|
||||||
unassignedTabsAutoCleanInterval =
|
unassignedTabsAutoCleanInterval =
|
||||||
unassignedTabsAutoCleanInterval ?? Duration.zero,
|
unassignedTabsAutoCleanInterval ?? Duration.zero,
|
||||||
maxSearchHistoryEntries = maxSearchHistoryEntries ?? 5;
|
maxSearchHistoryEntries = maxSearchHistoryEntries ?? 5,
|
||||||
|
allowClipboardAccess = allowClipboardAccess ?? true;
|
||||||
|
|
||||||
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
||||||
_$GeneralSettingsFromJson(json);
|
_$GeneralSettingsFromJson(json);
|
||||||
@@ -202,5 +206,6 @@ class GeneralSettings with FastEquatable {
|
|||||||
doubleBackCloseTab,
|
doubleBackCloseTab,
|
||||||
unassignedTabsAutoCleanInterval,
|
unassignedTabsAutoCleanInterval,
|
||||||
maxSearchHistoryEntries,
|
maxSearchHistoryEntries,
|
||||||
|
allowClipboardAccess,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
|
|
||||||
GeneralSettings maxSearchHistoryEntries(int maxSearchHistoryEntries);
|
GeneralSettings maxSearchHistoryEntries(int maxSearchHistoryEntries);
|
||||||
|
|
||||||
|
GeneralSettings allowClipboardAccess(bool allowClipboardAccess);
|
||||||
|
|
||||||
/// Creates a new instance with the provided field values.
|
/// Creates a new instance with the provided field values.
|
||||||
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
|
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
|
||||||
///
|
///
|
||||||
@@ -102,6 +104,7 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
bool doubleBackCloseTab,
|
bool doubleBackCloseTab,
|
||||||
Duration unassignedTabsAutoCleanInterval,
|
Duration unassignedTabsAutoCleanInterval,
|
||||||
int maxSearchHistoryEntries,
|
int maxSearchHistoryEntries,
|
||||||
|
bool allowClipboardAccess,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +220,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
GeneralSettings maxSearchHistoryEntries(int maxSearchHistoryEntries) =>
|
GeneralSettings maxSearchHistoryEntries(int maxSearchHistoryEntries) =>
|
||||||
call(maxSearchHistoryEntries: maxSearchHistoryEntries);
|
call(maxSearchHistoryEntries: maxSearchHistoryEntries);
|
||||||
|
|
||||||
|
@override
|
||||||
|
GeneralSettings allowClipboardAccess(bool allowClipboardAccess) =>
|
||||||
|
call(allowClipboardAccess: allowClipboardAccess);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
/// Creates a new instance with the provided field values.
|
/// Creates a new instance with the provided field values.
|
||||||
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
|
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
|
||||||
@@ -251,6 +258,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
Object? doubleBackCloseTab = const $CopyWithPlaceholder(),
|
Object? doubleBackCloseTab = const $CopyWithPlaceholder(),
|
||||||
Object? unassignedTabsAutoCleanInterval = const $CopyWithPlaceholder(),
|
Object? unassignedTabsAutoCleanInterval = const $CopyWithPlaceholder(),
|
||||||
Object? maxSearchHistoryEntries = const $CopyWithPlaceholder(),
|
Object? maxSearchHistoryEntries = const $CopyWithPlaceholder(),
|
||||||
|
Object? allowClipboardAccess = const $CopyWithPlaceholder(),
|
||||||
}) {
|
}) {
|
||||||
return GeneralSettings(
|
return GeneralSettings(
|
||||||
themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null
|
themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null
|
||||||
@@ -399,6 +407,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
? _value.maxSearchHistoryEntries
|
? _value.maxSearchHistoryEntries
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
: maxSearchHistoryEntries as int,
|
: maxSearchHistoryEntries as int,
|
||||||
|
allowClipboardAccess:
|
||||||
|
allowClipboardAccess == const $CopyWithPlaceholder() ||
|
||||||
|
allowClipboardAccess == null
|
||||||
|
? _value.allowClipboardAccess
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: allowClipboardAccess as bool,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -474,6 +488,7 @@ GeneralSettings _$GeneralSettingsFromJson(
|
|||||||
.toInt(),
|
.toInt(),
|
||||||
),
|
),
|
||||||
maxSearchHistoryEntries: (json['maxSearchHistoryEntries'] as num?)?.toInt(),
|
maxSearchHistoryEntries: (json['maxSearchHistoryEntries'] as num?)?.toInt(),
|
||||||
|
allowClipboardAccess: json['allowClipboardAccess'] as bool?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$GeneralSettingsToJson(
|
Map<String, dynamic> _$GeneralSettingsToJson(
|
||||||
@@ -513,6 +528,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
|
|||||||
'unassignedTabsAutoCleanInterval':
|
'unassignedTabsAutoCleanInterval':
|
||||||
instance.unassignedTabsAutoCleanInterval.inMicroseconds,
|
instance.unassignedTabsAutoCleanInterval.inMicroseconds,
|
||||||
'maxSearchHistoryEntries': instance.maxSearchHistoryEntries,
|
'maxSearchHistoryEntries': instance.maxSearchHistoryEntries,
|
||||||
|
'allowClipboardAccess': instance.allowClipboardAccess,
|
||||||
};
|
};
|
||||||
|
|
||||||
const _$ThemeModeEnumMap = {
|
const _$ThemeModeEnumMap = {
|
||||||
|
|||||||
@@ -141,6 +141,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
|||||||
DriftSqlType.int,
|
DriftSqlType.int,
|
||||||
db.typeMapping,
|
db.typeMapping,
|
||||||
),
|
),
|
||||||
|
'allowClipboardAccess': settings['allowClipboardAccess']?.readAs(
|
||||||
|
DriftSqlType.bool,
|
||||||
|
db.typeMapping,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$generalSettingsRepositoryHash() =>
|
String _$generalSettingsRepositoryHash() =>
|
||||||
r'7cea68308e2e7847e9bb030e9c9c04860c760edd';
|
r'302d33b57212a8f3affcf13a8ef5227d68e56ecb';
|
||||||
|
|
||||||
abstract class _$GeneralSettingsRepository
|
abstract class _$GeneralSettingsRepository
|
||||||
extends $StreamNotifier<GeneralSettings> {
|
extends $StreamNotifier<GeneralSettings> {
|
||||||
|
|||||||
@@ -39,8 +39,13 @@ class GeckoSuggestionsService extends GeckoSuggestionEvents {
|
|||||||
GeckoSuggestionType.clipboard,
|
GeckoSuggestionType.clipboard,
|
||||||
GeckoSuggestionType.history,
|
GeckoSuggestionType.history,
|
||||||
],
|
],
|
||||||
|
bool allowClipboard = true,
|
||||||
}) {
|
}) {
|
||||||
return _api.querySuggestions(text, providers);
|
final effectiveProviders = allowClipboard
|
||||||
|
? providers
|
||||||
|
: providers.where((p) => p != GeckoSuggestionType.clipboard).toList();
|
||||||
|
|
||||||
|
return _api.querySuggestions(text, effectiveProviders);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<AutocompleteResult?> getAutocompleteSuggestion(String query) {
|
Future<AutocompleteResult?> getAutocompleteSuggestion(String query) {
|
||||||
|
|||||||
Reference in New Issue
Block a user