fix lints

This commit is contained in:
Fabian Freund
2026-02-16 19:59:32 +01:00
parent cfa7e3ac89
commit 645bbb9b53
78 changed files with 244 additions and 210 deletions
+13 -6
View File
@@ -37,7 +37,6 @@ import 'package:weblibre/extensions/http_encoding.dart';
import 'package:weblibre/features/geckoview/domain/entities/browser_icon.dart'; import 'package:weblibre/features/geckoview/domain/entities/browser_icon.dart';
import 'package:weblibre/features/user/domain/repositories/cache.dart'; import 'package:weblibre/features/user/domain/repositories/cache.dart';
import 'package:weblibre/features/web_feed/utils/feed_finder.dart'; import 'package:weblibre/features/web_feed/utils/feed_finder.dart';
import 'package:weblibre/presentation/controllers/website_title.dart';
import 'package:weblibre/utils/lru_cache.dart'; import 'package:weblibre/utils/lru_cache.dart';
part 'generic_website.g.dart'; part 'generic_website.g.dart';
@@ -87,6 +86,8 @@ class GenericWebsiteService extends _$GenericWebsiteService {
late CacheRepository _cacheRepository; late CacheRepository _cacheRepository;
//Local decoded icon cache //Local decoded icon cache
late final LRUCache<String, BrowserIcon> _browserIconCache; late final LRUCache<String, BrowserIcon> _browserIconCache;
//In-flight fetch deduplication
final _inFlightFetches = <Uri, Future<Result<WebPageInfo>>>{};
GenericWebsiteService() GenericWebsiteService()
: _iconsService = GeckoIconService(), : _iconsService = GeckoIconService(),
@@ -344,6 +345,13 @@ class GenericWebsiteService extends _$GenericWebsiteService {
); );
} }
Future<Result<WebPageInfo>> _deduplicatedFetchPageInfo(Uri url) {
return _inFlightFetches.putIfAbsent(url, () {
return fetchPageInfo(url: url, isImageRequest: true, proxyPort: null)
.whenComplete(() => _inFlightFetches.remove(url));
});
}
Future<BrowserIcon?> getUrlIcon(List<Uri> urlList) async { Future<BrowserIcon?> getUrlIcon(List<Uri> urlList) async {
for (final url in urlList) { for (final url in urlList) {
final cachedIcon = await getCachedIcon(url); final cachedIcon = await getCachedIcon(url);
@@ -353,12 +361,10 @@ class GenericWebsiteService extends _$GenericWebsiteService {
} }
if (ref.mounted) { if (ref.mounted) {
// ignore: only_use_keep_alive_inside_keep_alive final result = await _deduplicatedFetchPageInfo(url);
final result = await ref.read(
pageInfoProvider(url, isImageRequest: true).future,
);
if (result.favicon case final BrowserIcon favicon) { if (result.isSuccess) {
if (result.value.favicon case final BrowserIcon favicon) {
//If it was a `isImageRequest` hit, we need to cache it at this point //If it was a `isImageRequest` hit, we need to cache it at this point
if (!_browserIconCache.contains(url.origin)) { if (!_browserIconCache.contains(url.origin)) {
_browserIconCache.set(url.origin, favicon); _browserIconCache.set(url.origin, favicon);
@@ -368,6 +374,7 @@ class GenericWebsiteService extends _$GenericWebsiteService {
} }
} }
} }
}
return null; return null;
} }
@@ -42,7 +42,7 @@ final class GenericWebsiteServiceProvider
} }
String _$genericWebsiteServiceHash() => String _$genericWebsiteServiceHash() =>
r'80b0f7113368bdd6fbe43fc27d2ab7332fe4b692'; r'437e1b11b6e63d38151354522deda755d9333c47';
abstract class _$GenericWebsiteService extends $Notifier<void> { abstract class _$GenericWebsiteService extends $Notifier<void> {
void build(); void build();
@@ -26,7 +26,7 @@ import 'package:weblibre/features/about/domain/providers.dart';
import 'package:weblibre/features/geckoview/domain/repositories/tab.dart'; import 'package:weblibre/features/geckoview/domain/repositories/tab.dart';
class AboutDialogScreen extends HookConsumerWidget { class AboutDialogScreen extends HookConsumerWidget {
const AboutDialogScreen(); const AboutDialogScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -31,7 +31,6 @@ Future<bool> widgetPinnable(Ref ref) async {
@Riverpod() @Riverpod()
Raw<Stream<ReceivedIntentParameter>> appWidgetLaunchStream(Ref ref) { Raw<Stream<ReceivedIntentParameter>> appWidgetLaunchStream(Ref ref) {
// ignore: discarded_futures is used as stream
final initialStream = HomeWidget.initiallyLaunchedFromHomeWidget().asStream(); final initialStream = HomeWidget.initiallyLaunchedFromHomeWidget().asStream();
return ConcatStream([ return ConcatStream([
@@ -23,7 +23,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:weblibre/core/routing/routes.dart'; import 'package:weblibre/core/routing/routes.dart';
class BangMenuScreen extends HookConsumerWidget { class BangMenuScreen extends HookConsumerWidget {
const BangMenuScreen(); const BangMenuScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -33,7 +33,7 @@ import 'package:weblibre/presentation/widgets/failure_widget.dart';
class UserBangs extends HookConsumerWidget { class UserBangs extends HookConsumerWidget {
static const _userGroupFilter = [BangGroup.user]; static const _userGroupFilter = [BangGroup.user];
const UserBangs(); const UserBangs({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -20,6 +20,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
import 'package:nullability/nullability.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@@ -30,7 +31,7 @@ import 'package:weblibre/features/bangs/domain/providers/bangs.dart';
import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart'; import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart';
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
import 'package:weblibre/features/geckoview/domain/repositories/tab.dart'; import 'package:weblibre/features/geckoview/domain/repositories/tab.dart';
import 'package:weblibre/features/geckoview/features/find_in_page/presentation/controllers/find_in_page.dart'; import 'package:weblibre/features/geckoview/features/find_in_page/domain/repositories/find_in_page.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
part 'providers.g.dart'; part 'providers.g.dart';
@@ -46,11 +47,17 @@ GeckoSelectionActionService selectionActionService(Ref ref) {
final router = await ref.read(routerProvider.future); final router = await ref.read(routerProvider.future);
if (ref.mounted) { if (ref.mounted) {
final settings = ref.read(generalSettingsWithDefaultsProvider); final settings = ref.read(generalSettingsWithDefaultsProvider);
final selectedTabState = ref.read(
tabStatesProvider,
)[ref.read(selectedTabProvider)];
final isPrivate = selectedTabState?.isPrivate.mapNotNull(
(isCurrentPrivate) =>
isCurrentPrivate ? TabType.private : TabType.regular,
);
final route = SearchRoute( final route = SearchRoute(
tabType: tabType: isPrivate ?? settings.defaultCreateTabType,
// ignore: only_use_keep_alive_inside_keep_alive
ref.read(selectedTabTypeProvider) ??
settings.defaultCreateTabType,
searchText: text, searchText: text,
); );
@@ -65,8 +72,10 @@ GeckoSelectionActionService selectionActionService(Ref ref) {
); );
if (ref.mounted && defaultSearchBang != null) { if (ref.mounted && defaultSearchBang != null) {
// ignore: only_use_keep_alive_inside_keep_alive final currentTab = ref.read(
final currentTab = ref.read(selectedTabStateProvider); tabStatesProvider,
)[ref.read(selectedTabProvider)];
final isPrivate = final isPrivate =
currentTab?.isPrivate ?? currentTab?.isPrivate ??
ref ref
@@ -91,10 +100,9 @@ GeckoSelectionActionService selectionActionService(Ref ref) {
if (ref.mounted) { if (ref.mounted) {
final tabId = ref.read(selectedTabProvider); final tabId = ref.read(selectedTabProvider);
if (tabId != null) { if (tabId != null) {
// ignore: only_use_keep_alive_inside_keep_alive
await ref await ref
.read(findInPageControllerProvider(tabId).notifier) .read(findInPageRepositoryProvider(tabId).notifier)
.findAll(text: text); .findAll(text);
} }
} }
}), }),
@@ -55,7 +55,7 @@ final class SelectionActionServiceProvider
} }
String _$selectionActionServiceHash() => String _$selectionActionServiceHash() =>
r'6250d2121375b2a41c2f0450512fc836c996f461'; r'75fa0fa770e74e49554d4098102fde9f9e531c4f';
@ProviderFor(eventService) @ProviderFor(eventService)
final eventServiceProvider = EventServiceProvider._(); final eventServiceProvider = EventServiceProvider._();
@@ -95,7 +95,6 @@ class TabRepository extends _$TabRepository {
final assingedContainer = final assingedContainer =
container ?? container ??
Value<ContainerData?>( Value<ContainerData?>(
// ignore: only_use_keep_alive_inside_keep_alive
await ref.read(selectedContainerProvider.notifier).fetchData(), await ref.read(selectedContainerProvider.notifier).fetchData(),
); );
@@ -295,8 +294,7 @@ class TabRepository extends _$TabRepository {
} }
Future<void> _selectNextTab(String tabId) async { Future<void> _selectNextTab(String tabId) async {
// ignore: only_use_keep_alive_inside_keep_alive final tabState = ref.read(tabStatesProvider)[tabId];
final tabState = ref.read(tabStateProvider(tabId));
final currentContainerId = await ref final currentContainerId = await ref
.read(tabDataRepositoryProvider.notifier) .read(tabDataRepositoryProvider.notifier)
@@ -382,8 +380,7 @@ class TabRepository extends _$TabRepository {
if (!ref.mounted) return; if (!ref.mounted) return;
final nextContainerTabs = await nextAvailableContainer final nextContainerTabs = await nextAvailableContainer.mapNotNull(
.mapNotNull(
(container) => ref (container) => ref
.read(containerRepositoryProvider.notifier) .read(containerRepositoryProvider.notifier)
.getContainerTabIds(container.id) .getContainerTabIds(container.id)
@@ -446,8 +443,7 @@ class TabRepository extends _$TabRepository {
final containerSiteAssignementSub = eventSerivce.siteAssignementEvent.listen( final containerSiteAssignementSub = eventSerivce.siteAssignementEvent.listen(
(event) async { (event) async {
if (event.tabId != null) { if (event.tabId != null) {
// ignore: only_use_keep_alive_inside_keep_alive final tabState = ref.read(tabStatesProvider)[event.tabId];
final tabState = ref.read(tabStateProvider(event.tabId));
if (tabState != null) { if (tabState != null) {
final uri = Uri.parse(event.url); final uri = Uri.parse(event.url);
final originUri = event.originUrl.mapNotNull(Uri.parse); final originUri = event.originUrl.mapNotNull(Uri.parse);
@@ -41,7 +41,7 @@ final class TabRepositoryProvider
} }
} }
String _$tabRepositoryHash() => r'b300b88bc7817b533be46d8d0d933786b10212fb'; String _$tabRepositoryHash() => r'0a676c0513917e8853677ebd592954bde0f15f57';
abstract class _$TabRepository extends $Notifier<void> { abstract class _$TabRepository extends $Notifier<void> {
void build(); void build();
@@ -35,6 +35,7 @@ class BookmarkEntryEditScreen extends HookConsumerWidget {
final BookmarkEntry? exisitingEntry; final BookmarkEntry? exisitingEntry;
const BookmarkEntryEditScreen({ const BookmarkEntryEditScreen({
super.key,
required this.exisitingEntry, required this.exisitingEntry,
required this.initialInfo, required this.initialInfo,
}); });
@@ -32,7 +32,11 @@ class BookmarkFolderEditScreen extends HookConsumerWidget {
final String? parentGuid; final String? parentGuid;
final BookmarkFolder? folder; final BookmarkFolder? folder;
const BookmarkFolderEditScreen({required this.folder, this.parentGuid}); const BookmarkFolderEditScreen({
super.key,
required this.folder,
this.parentGuid,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -175,7 +175,7 @@ EquatableValue<List<TabStateWirthContainer>> fifoTabStates(Ref ref) {
]); ]);
} }
@Riverpod(keepAlive: true) @Riverpod()
EquatableValue<List<TabStateWirthContainer>> EquatableValue<List<TabStateWirthContainer>>
selectedContainerTabStatesWithContainer(Ref ref) { selectedContainerTabStatesWithContainer(Ref ref) {
final filter = ref.watch( final filter = ref.watch(
@@ -452,7 +452,7 @@ final class SelectedContainerTabStatesWithContainerProvider
argument: null, argument: null,
retry: null, retry: null,
name: r'selectedContainerTabStatesWithContainerProvider', name: r'selectedContainerTabStatesWithContainerProvider',
isAutoDispose: false, isAutoDispose: true,
dependencies: null, dependencies: null,
$allTransitiveDependencies: null, $allTransitiveDependencies: null,
); );
@@ -487,7 +487,7 @@ final class SelectedContainerTabStatesWithContainerProvider
} }
String _$selectedContainerTabStatesWithContainerHash() => String _$selectedContainerTabStatesWithContainerHash() =>
r'd22d16eba89040fbcf7932e5334155f00312957f'; r'2fd5e12595b3aced1e235c9626073c34655d57fa';
@ProviderFor(suggestedTabEntities) @ProviderFor(suggestedTabEntities)
final suggestedTabEntitiesProvider = SuggestedTabEntitiesFamily._(); final suggestedTabEntitiesProvider = SuggestedTabEntitiesFamily._();
@@ -221,7 +221,6 @@ class EngineSettingsReplicationService
); );
} }
if (previous.value?.enablePdfJs != settings.enablePdfJs) { if (previous.value?.enablePdfJs != settings.enablePdfJs) {
// ignore: only_use_keep_alive_inside_keep_alive
await ref await ref
.read(preferenceFixatorProvider.notifier) .read(preferenceFixatorProvider.notifier)
.register('pdfjs.disabled', !settings.enablePdfJs); .register('pdfjs.disabled', !settings.enablePdfJs);
@@ -230,7 +229,6 @@ class EngineSettingsReplicationService
previous.value?.locales, previous.value?.locales,
settings.locales, settings.locales,
)) { )) {
// ignore: only_use_keep_alive_inside_keep_alive
await ref await ref
.read(preferenceFixatorProvider.notifier) .read(preferenceFixatorProvider.notifier)
.register( .register(
@@ -240,13 +238,9 @@ class EngineSettingsReplicationService
} }
} else { } else {
await _service.setDefaultSettings(settings); await _service.setDefaultSettings(settings);
// ignore: only_use_keep_alive_inside_keep_alive
await ref await ref
.read(preferenceFixatorProvider.notifier) .read(preferenceFixatorProvider.notifier)
.register('pdfjs.disabled', !settings.enablePdfJs); .register('pdfjs.disabled', !settings.enablePdfJs);
// ignore: only_use_keep_alive_inside_keep_alive
await ref await ref
.read(preferenceFixatorProvider.notifier) .read(preferenceFixatorProvider.notifier)
.register('intl.accept_languages', settings.locales.join(',')); .register('intl.accept_languages', settings.locales.join(','));
@@ -135,7 +135,6 @@ class ProxySettingsReplication extends _$ProxySettingsReplication {
}, },
); );
// ignore: only_use_keep_alive_inside_keep_alive
ref.listen(watchAllAssignedSitesProvider, (previous, next) async { ref.listen(watchAllAssignedSitesProvider, (previous, next) async {
if (next.hasValue) { if (next.hasValue) {
await ref await ref
@@ -32,7 +32,7 @@ import 'package:weblibre/utils/form_validators.dart';
class OpenSharedContent extends HookConsumerWidget { class OpenSharedContent extends HookConsumerWidget {
final Uri sharedUrl; final Uri sharedUrl;
const OpenSharedContent({required this.sharedUrl}); const OpenSharedContent({super.key, required this.sharedUrl});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -30,7 +30,7 @@ import 'package:weblibre/features/user/domain/repositories/general_settings.dart
import 'package:weblibre/presentation/hooks/scroll_visibility.dart'; import 'package:weblibre/presentation/hooks/scroll_visibility.dart';
class TabViewScreen extends HookConsumerWidget { class TabViewScreen extends HookConsumerWidget {
const TabViewScreen(); const TabViewScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -68,7 +68,7 @@ class BrowserTopAppBar extends HookConsumerWidget {
late final BrowserTabBar _tabBar; late final BrowserTabBar _tabBar;
late final _size = Size.fromHeight(_tabBar.getToolbarHeight()); late final _size = Size.fromHeight(_tabBar.getToolbarHeight());
BrowserTopAppBar({ BrowserTopAppBar({super.key,
required this.showMainToolbar, required this.showMainToolbar,
required this.showContextualToolbar, required this.showContextualToolbar,
required this.showQuickTabSwitcherBar, required this.showQuickTabSwitcherBar,
@@ -103,7 +103,7 @@ class BrowserBottomAppBar extends HookConsumerWidget {
late final BrowserTabBar _tabBar; late final BrowserTabBar _tabBar;
late final _size = Size.fromHeight(_tabBar.getToolbarHeight()); late final _size = Size.fromHeight(_tabBar.getToolbarHeight());
BrowserBottomAppBar({ BrowserBottomAppBar({super.key,
required this.showMainToolbar, required this.showMainToolbar,
required this.displayedSheet, required this.displayedSheet,
required this.showContextualToolbar, required this.showContextualToolbar,
@@ -148,7 +148,7 @@ class BrowserTabBar extends HookConsumerWidget {
final bool showMainToolbarNavigationButton; final bool showMainToolbarNavigationButton;
final bool showMainToolbarTabActionButton; final bool showMainToolbarTabActionButton;
const BrowserTabBar({ const BrowserTabBar({super.key,
required this.showMainToolbar, required this.showMainToolbar,
required this.displayedSheet, required this.displayedSheet,
required this.showContextualToolbar, required this.showContextualToolbar,
@@ -476,7 +476,7 @@ class ContextualToolbar extends HookConsumerWidget {
class QuickTabSwitcher extends HookConsumerWidget { class QuickTabSwitcher extends HookConsumerWidget {
final QuickTabSwitcherMode quickTabSwitcherMode; final QuickTabSwitcherMode quickTabSwitcherMode;
const QuickTabSwitcher({required this.quickTabSwitcherMode}); const QuickTabSwitcher({super.key, required this.quickTabSwitcherMode});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -685,7 +685,7 @@ class NavigationMenuButton extends StatelessWidget {
} }
class AddTabButton extends HookConsumerWidget { class AddTabButton extends HookConsumerWidget {
const AddTabButton(); const AddTabButton({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -68,7 +68,7 @@ class BrowserView extends StatefulHookConsumerWidget {
final Future<void> Function()? postInitializationStep; final Future<void> Function()? postInitializationStep;
final StreamSink<Offset>? pointerMoveEventSink; final StreamSink<Offset>? pointerMoveEventSink;
const BrowserView({ const BrowserView({super.key,
this.screenshotPeriod = const Duration(seconds: 10), this.screenshotPeriod = const Duration(seconds: 10),
this.suggestionTimeout = const Duration(seconds: 30), this.suggestionTimeout = const Duration(seconds: 30),
this.postInitializationStep, this.postInitializationStep,
@@ -25,7 +25,7 @@ import 'package:skeletonizer/skeletonizer.dart';
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
class CertificateTile extends HookConsumerWidget { class CertificateTile extends HookConsumerWidget {
const CertificateTile(); const CertificateTile({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -22,7 +22,7 @@ import 'package:flutter/material.dart';
class ErrorContainer extends StatelessWidget { class ErrorContainer extends StatelessWidget {
final Widget content; final Widget content;
const ErrorContainer({required this.content}); const ErrorContainer({super.key, required this.content});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -25,7 +25,7 @@ import 'package:weblibre/presentation/widgets/safe_raw_image.dart';
class ExtensionBadgeIcon extends StatelessWidget { class ExtensionBadgeIcon extends StatelessWidget {
final WebExtensionState state; final WebExtensionState state;
const ExtensionBadgeIcon(this.state); const ExtensionBadgeIcon(this.state, {super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -52,7 +52,7 @@ class ViewTabSheetWidget extends HookConsumerWidget {
final double bottomAppBarHeight; final double bottomAppBarHeight;
final ValueChanged<bool>? onClearSiteDataExpandedChanged; final ValueChanged<bool>? onClearSiteDataExpandedChanged;
const ViewTabSheetWidget({ const ViewTabSheetWidget({super.key,
required this.initialTabState, required this.initialTabState,
required this.sheetScrollController, required this.sheetScrollController,
required this.draggableScrollableController, required this.draggableScrollableController,
@@ -44,6 +44,7 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/ta
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_chips.dart'; import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_chips.dart';
import 'package:weblibre/features/tor/presentation/controllers/start_tor_proxy.dart'; import 'package:weblibre/features/tor/presentation/controllers/start_tor_proxy.dart';
import 'package:weblibre/features/tor/presentation/widgets/tor_dialog.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
import 'package:weblibre/presentation/hooks/menu_controller.dart'; import 'package:weblibre/presentation/hooks/menu_controller.dart';
import 'package:weblibre/presentation/widgets/speech_to_text_button.dart'; import 'package:weblibre/presentation/widgets/speech_to_text_button.dart';
@@ -55,7 +56,11 @@ class TabViewHeader extends HookConsumerWidget {
final TabsViewMode tabsViewMode; final TabsViewMode tabsViewMode;
final VoidCallback onClose; final VoidCallback onClose;
const TabViewHeader({required this.onClose, required this.tabsViewMode}); const TabViewHeader({
super.key,
required this.onClose,
required this.tabsViewMode,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -601,9 +606,24 @@ class TabViewHeader extends HookConsumerWidget {
if (context.mounted && if (context.mounted &&
result == SetContainerResult.successHasProxy) { result == SetContainerResult.successHasProxy) {
final shouldStartProxy = await ref
.read(startProxyControllerProvider.notifier)
.shouldPromptProxyStart();
if (!context.mounted || !shouldStartProxy) return;
final dialogResult = await showDialog<bool>(
context: context,
builder: (context) {
return const TorDialog();
},
);
if (dialogResult == true) {
await ref await ref
.read(startProxyControllerProvider.notifier) .read(startProxyControllerProvider.notifier)
.maybeStartProxy(context); .startProxy();
}
} }
} else { } else {
ref ref
@@ -25,7 +25,7 @@ import 'package:weblibre/features/geckoview/domain/providers.dart';
part 'preference_observer.g.dart'; part 'preference_observer.g.dart';
@Riverpod() @Riverpod(keepAlive: true)
class PreferenceChangeListener extends _$PreferenceChangeListener { class PreferenceChangeListener extends _$PreferenceChangeListener {
@override @override
Stream<GeckoPref> build() async* { Stream<GeckoPref> build() async* {
@@ -41,7 +41,7 @@ class PreferenceChangeListener extends _$PreferenceChangeListener {
} }
} }
@Riverpod() @Riverpod(keepAlive: true)
class PreferenceFixator extends _$PreferenceFixator { class PreferenceFixator extends _$PreferenceFixator {
Future<void> register(String name, Object value) async { Future<void> register(String name, Object value) async {
state = {...state} state = {...state}
@@ -20,7 +20,7 @@ final class PreferenceChangeListenerProvider
argument: null, argument: null,
retry: null, retry: null,
name: r'preferenceChangeListenerProvider', name: r'preferenceChangeListenerProvider',
isAutoDispose: true, isAutoDispose: false,
dependencies: null, dependencies: null,
$allTransitiveDependencies: null, $allTransitiveDependencies: null,
); );
@@ -34,7 +34,7 @@ final class PreferenceChangeListenerProvider
} }
String _$preferenceChangeListenerHash() => String _$preferenceChangeListenerHash() =>
r'668c1bcd0636ec515a5e92ee5ba4ea7a67fa7a6d'; r'de9759b32a6a6b9bab5656137a365da78633f866';
abstract class _$PreferenceChangeListener extends $StreamNotifier<GeckoPref> { abstract class _$PreferenceChangeListener extends $StreamNotifier<GeckoPref> {
Stream<GeckoPref> build(); Stream<GeckoPref> build();
@@ -65,7 +65,7 @@ final class PreferenceFixatorProvider
argument: null, argument: null,
retry: null, retry: null,
name: r'preferenceFixatorProvider', name: r'preferenceFixatorProvider',
isAutoDispose: true, isAutoDispose: false,
dependencies: null, dependencies: null,
$allTransitiveDependencies: null, $allTransitiveDependencies: null,
); );
@@ -86,7 +86,7 @@ final class PreferenceFixatorProvider
} }
} }
String _$preferenceFixatorHash() => r'c76245d5c420e2e3f6c026f23c017c939b69ef59'; String _$preferenceFixatorHash() => r'c8d71966faf6b2feb9ac4e770297cd298edf5211';
abstract class _$PreferenceFixator extends $Notifier<Map<String, Object>> { abstract class _$PreferenceFixator extends $Notifier<Map<String, Object>> {
Map<String, Object> build(); Map<String, Object> build();
@@ -59,7 +59,7 @@ class SearchScreen extends HookConsumerWidget {
/// When null, a new tab will be created. /// When null, a new tab will be created.
final String? tabId; final String? tabId;
const SearchScreen({ const SearchScreen({super.key,
required this.initialSearchText, required this.initialSearchText,
required this.tabType, required this.tabType,
this.launchedFromIntent = false, this.launchedFromIntent = false,
@@ -42,7 +42,7 @@ class FeedSearch extends HookConsumerWidget {
final ValueListenable<TextEditingValue> searchTextNotifier; final ValueListenable<TextEditingValue> searchTextNotifier;
const FeedSearch({required this.searchTextNotifier}); const FeedSearch({super.key, required this.searchTextNotifier});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -50,7 +50,7 @@ class TabSearch extends HookConsumerWidget {
final ValueListenable<TextEditingValue> searchTextListenable; final ValueListenable<TextEditingValue> searchTextListenable;
const TabSearch({required this.searchTextListenable}); const TabSearch({super.key, required this.searchTextListenable});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -76,7 +76,7 @@ class TabSearch extends HookConsumerWidget {
.fold( .fold(
<String?, int>{}, <String?, int>{},
(map, id) => (map, id) =>
map..update(id, (value) => ++value, ifAbsent: () => 1), map..update(id, (value) => value + 1, ifAbsent: () => 1),
), ),
), ),
[tabSearchResults], [tabSearchResults],
@@ -149,7 +149,7 @@ Stream<Map<String, String?>> watchTabsContainerId(
.map(Map.fromEntries); .map(Map.fromEntries);
} }
@Riverpod() @Riverpod(keepAlive: true)
Stream<List<SiteAssignment>> watchAllAssignedSites(Ref ref) { Stream<List<SiteAssignment>> watchAllAssignedSites(Ref ref) {
final db = ref.watch(tabDatabaseProvider); final db = ref.watch(tabDatabaseProvider);
return db.containerDao.allAssignedSites().watch(); return db.containerDao.allAssignedSites().watch();
@@ -848,7 +848,7 @@ final class WatchAllAssignedSitesProvider
argument: null, argument: null,
retry: null, retry: null,
name: r'watchAllAssignedSitesProvider', name: r'watchAllAssignedSitesProvider',
isAutoDispose: true, isAutoDispose: false,
dependencies: null, dependencies: null,
$allTransitiveDependencies: null, $allTransitiveDependencies: null,
); );
@@ -869,7 +869,7 @@ final class WatchAllAssignedSitesProvider
} }
String _$watchAllAssignedSitesHash() => String _$watchAllAssignedSitesHash() =>
r'0e06caeb4a53b5cf976b3f47d328ea238243438b'; r'5f658b5733ee20192eb86d3aeb79aa9678dafba8';
@ProviderFor(watchIsCurrentSiteAssignedToContainer) @ProviderFor(watchIsCurrentSiteAssignedToContainer)
final watchIsCurrentSiteAssignedToContainerProvider = final watchIsCurrentSiteAssignedToContainerProvider =
@@ -46,7 +46,7 @@ class TabDataRepository extends _$TabDataRepository {
.tabDao .tabDao
.assignContainer(tabId, containerId: targetContainer.id); .assignContainer(tabId, containerId: targetContainer.id);
} else { } else {
final tabState = ref.read(tabStateProvider(tabId)); final tabState = ref.read(tabStatesProvider)[tabId];
if (tabState != null) { if (tabState != null) {
if (closeOldTab) { if (closeOldTab) {
await ref.read(tabRepositoryProvider.notifier).closeTab(tabId); await ref.read(tabRepositoryProvider.notifier).closeTab(tabId);
@@ -76,7 +76,7 @@ class TabDataRepository extends _$TabDataRepository {
.tabDao .tabDao
.assignContainer(tabId, containerId: null); .assignContainer(tabId, containerId: null);
} else { } else {
final tabState = ref.read(tabStateProvider(tabId)); final tabState = ref.read(tabStatesProvider)[tabId];
if (tabState != null) { if (tabState != null) {
await ref.read(tabRepositoryProvider.notifier).closeTab(tabId); await ref.read(tabRepositoryProvider.notifier).closeTab(tabId);
@@ -41,7 +41,7 @@ final class TabDataRepositoryProvider
} }
} }
String _$tabDataRepositoryHash() => r'c3632e0a2d91811103b329659cb0c6d778b14cea'; String _$tabDataRepositoryHash() => r'c872509a70e4c0c029b468457e15c5e5bff10c65';
abstract class _$TabDataRepository extends $Notifier<void> { abstract class _$TabDataRepository extends $Notifier<void> {
void build(); void build();
@@ -37,7 +37,7 @@ class ContainerTopicController extends _$ContainerTopicController {
return _predictFromTitles(titles); return _predictFromTitles(titles);
} }
Future<String?> predictTopicFromTabIds(Set<String> tabIds) async { Future<String?> predictTopicFromTabIds(Set<String> tabIds) {
final tabStates = ref.read(tabStatesProvider); final tabStates = ref.read(tabStatesProvider);
final titles = tabIds final titles = tabIds
.map((tabId) => tabStates[tabId]?.title) .map((tabId) => tabStates[tabId]?.title)
@@ -42,7 +42,7 @@ final class ContainerTopicControllerProvider
} }
String _$containerTopicControllerHash() => String _$containerTopicControllerHash() =>
r'0b54e0be899e2abb4defbd5614ba231917ad74e5'; r'41ee4b2a259eba17af49b3c877a9b10ea51281c8';
abstract class _$ContainerTopicController extends $Notifier<AsyncValue<void>> { abstract class _$ContainerTopicController extends $Notifier<AsyncValue<void>> {
AsyncValue<void> build(); AsyncValue<void> build();
@@ -31,10 +31,11 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selec
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart';
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_list_tile.dart'; import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_list_tile.dart';
import 'package:weblibre/features/tor/presentation/controllers/start_tor_proxy.dart'; import 'package:weblibre/features/tor/presentation/controllers/start_tor_proxy.dart';
import 'package:weblibre/features/tor/presentation/widgets/tor_dialog.dart';
import 'package:weblibre/presentation/widgets/failure_widget.dart'; import 'package:weblibre/presentation/widgets/failure_widget.dart';
class ContainerListScreen extends HookConsumerWidget { class ContainerListScreen extends HookConsumerWidget {
const ContainerListScreen(); const ContainerListScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -70,9 +71,28 @@ class ContainerListScreen extends HookConsumerWidget {
if (context.mounted && if (context.mounted &&
result == result ==
SetContainerResult.successHasProxy) { SetContainerResult.successHasProxy) {
await ref final shouldStartProxy = await ref
.read(startProxyControllerProvider.notifier) .read(startProxyControllerProvider.notifier)
.maybeStartProxy(context); .shouldPromptProxyStart();
if (!context.mounted || !shouldStartProxy) {
return;
}
final dialogResult = await showDialog<bool>(
context: context,
builder: (context) {
return const TorDialog();
},
);
if (dialogResult == true) {
await ref
.read(
startProxyControllerProvider.notifier,
)
.startProxy();
}
} }
}, },
foregroundColor: Theme.of( foregroundColor: Theme.of(
@@ -33,7 +33,7 @@ import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/c
import 'package:weblibre/presentation/widgets/failure_widget.dart'; import 'package:weblibre/presentation/widgets/failure_widget.dart';
class ContainerSelectionScreen extends HookConsumerWidget { class ContainerSelectionScreen extends HookConsumerWidget {
const ContainerSelectionScreen(); const ContainerSelectionScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -25,7 +25,7 @@ import 'package:weblibre/features/geckoview/features/tabs/utils/container_colors
class ColorPickerDialog extends HookWidget { class ColorPickerDialog extends HookWidget {
final Color initialColor; final Color initialColor;
const ColorPickerDialog(this.initialColor); const ColorPickerDialog(this.initialColor, {super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -145,7 +145,7 @@ class ContainerChips extends HookConsumerWidget {
final ValueListenable<TextEditingValue>? searchTextListenable; final ValueListenable<TextEditingValue>? searchTextListenable;
const ContainerChips({ const ContainerChips({super.key,
required this.selectedContainer, required this.selectedContainer,
required this.onSelected, required this.onSelected,
required this.onDeleted, required this.onDeleted,
@@ -25,6 +25,8 @@ import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart';
import 'package:weblibre/utils/ui_helper.dart' as ui_helper; import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
class QrScannerDialog extends HookWidget { class QrScannerDialog extends HookWidget {
const QrScannerDialog({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final qrKey = useMemoized(() => GlobalKey(debugLabel: 'qr_scanner')); final qrKey = useMemoized(() => GlobalKey(debugLabel: 'qr_scanner'));
@@ -28,7 +28,7 @@ import 'package:weblibre/features/user/domain/repositories/engine_settings.dart'
import 'package:weblibre/utils/form_validators.dart'; import 'package:weblibre/utils/form_validators.dart';
class DohSettingsScreen extends HookConsumerWidget { class DohSettingsScreen extends HookConsumerWidget {
const DohSettingsScreen(); const DohSettingsScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -29,7 +29,7 @@ import 'package:weblibre/features/user/domain/services/fingerprinting.dart';
import 'package:weblibre/presentation/widgets/failure_widget.dart'; import 'package:weblibre/presentation/widgets/failure_widget.dart';
class FingerprintSettingsScreen extends HookConsumerWidget { class FingerprintSettingsScreen extends HookConsumerWidget {
const FingerprintSettingsScreen(); const FingerprintSettingsScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -31,7 +31,7 @@ import 'package:weblibre/features/user/data/models/engine_settings.dart';
import 'package:weblibre/features/user/domain/repositories/engine_settings.dart'; import 'package:weblibre/features/user/domain/repositories/engine_settings.dart';
class LocaleSettingsScreen extends HookConsumerWidget { class LocaleSettingsScreen extends HookConsumerWidget {
const LocaleSettingsScreen(); const LocaleSettingsScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -29,7 +29,7 @@ import 'package:weblibre/features/settings/presentation/widgets/hardening_group_
import 'package:weblibre/presentation/widgets/failure_widget.dart'; import 'package:weblibre/presentation/widgets/failure_widget.dart';
class WebEngineHardeningScreen extends HookConsumerWidget { class WebEngineHardeningScreen extends HookConsumerWidget {
const WebEngineHardeningScreen(); const WebEngineHardeningScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -28,7 +28,7 @@ import 'package:weblibre/presentation/widgets/selectable_chips.dart';
import 'package:weblibre/presentation/widgets/url_icon.dart'; import 'package:weblibre/presentation/widgets/url_icon.dart';
class DefaultSearchSelector extends HookConsumerWidget { class DefaultSearchSelector extends HookConsumerWidget {
const DefaultSearchSelector(); const DefaultSearchSelector({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -22,7 +22,7 @@ import 'package:flutter/material.dart';
class SettingSection extends StatelessWidget { class SettingSection extends StatelessWidget {
final String name; final String name;
const SettingSection({required this.name}); const SettingSection({super.key, required this.name});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -43,7 +43,7 @@ class SettingSection extends StatelessWidget {
class SettingSubSection extends StatelessWidget { class SettingSubSection extends StatelessWidget {
final String name; final String name;
const SettingSubSection({required this.name}); const SettingSubSection({super.key, required this.name});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -25,7 +25,7 @@ class SyncDetailsTable extends StatelessWidget {
final int? count; final int? count;
final DateTime? lastSync; final DateTime? lastSync;
const SyncDetailsTable(this.count, this.lastSync); const SyncDetailsTable(this.count, this.lastSync, {super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -65,7 +65,6 @@ class TorProxyService extends _$TorProxyService {
if (config == null && torSettings.requireBridge) { if (config == null && torSettings.requireBridge) {
config = MoatService.convertBuiltinToSettings( config = MoatService.convertBuiltinToSettings(
// ignore: only_use_keep_alive_inside_keep_alive
await ref await ref
.read(builtinBridgesRepositoryProvider(moat).notifier) .read(builtinBridgesRepositoryProvider(moat).notifier)
.getBridges(), .getBridges(),
@@ -99,7 +98,6 @@ class TorProxyService extends _$TorProxyService {
if (config == null && if (config == null &&
(torSettings.requireBridge || !torSettings.fetchRemoteBridges)) { (torSettings.requireBridge || !torSettings.fetchRemoteBridges)) {
config = MoatService.convertBuiltinToSettings( config = MoatService.convertBuiltinToSettings(
// ignore: only_use_keep_alive_inside_keep_alive
await ref await ref
.read(builtinBridgesRepositoryProvider(moat).notifier) .read(builtinBridgesRepositoryProvider(moat).notifier)
.getBridges(tryUpdate: torSettings.fetchRemoteBridges), .getBridges(tryUpdate: torSettings.fetchRemoteBridges),
@@ -17,34 +17,30 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:weblibre/features/geckoview/domain/controllers/overlay.dart'; import 'package:weblibre/features/geckoview/domain/controllers/overlay.dart';
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart'; import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
import 'package:weblibre/features/tor/presentation/widgets/tor_dialog.dart';
import 'package:weblibre/features/tor/presentation/widgets/tor_notification.dart'; import 'package:weblibre/features/tor/presentation/widgets/tor_notification.dart';
part 'start_tor_proxy.g.dart'; part 'start_tor_proxy.g.dart';
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
class StartProxyController extends _$StartProxyController { class StartProxyController extends _$StartProxyController {
// ignore: document_ignores is used for dialog Future<bool> shouldPromptProxyStart() async {
// ignore: avoid_build_context_in_providers
Future<void> maybeStartProxy(BuildContext context) async {
final currentStatus = await ref final currentStatus = await ref
.read(torProxyServiceProvider.notifier) .read(torProxyServiceProvider.notifier)
.requestSync(); .requestSync();
if (!currentStatus.isRunning) { return !currentStatus.isRunning;
if (context.mounted) { }
final result = await showDialog<bool>(
context: context,
builder: (context) {
return const TorDialog();
},
);
if (result == true) { Future<void> startProxy() async {
if (state) return;
state = true;
try {
final connection = ref final connection = ref
.read(torProxyServiceProvider.notifier) .read(torProxyServiceProvider.notifier)
.startOrReconfigure(reconfigureIfRunning: false); .startOrReconfigure(reconfigureIfRunning: false);
@@ -53,15 +49,17 @@ class StartProxyController extends _$StartProxyController {
.read(overlayControllerProvider.notifier) .read(overlayControllerProvider.notifier)
.show( .show(
(context) => (context) =>
Positioned(top: 0, left: 0, child: TorNotification()), const Positioned(top: 0, left: 0, child: TorNotification()),
); );
await connection; await connection;
} } finally {
} state = false;
} }
} }
@override @override
void build() {} bool build() {
return false;
}
} }
@@ -13,7 +13,7 @@ part of 'start_tor_proxy.dart';
final startProxyControllerProvider = StartProxyControllerProvider._(); final startProxyControllerProvider = StartProxyControllerProvider._();
final class StartProxyControllerProvider final class StartProxyControllerProvider
extends $NotifierProvider<StartProxyController, void> { extends $NotifierProvider<StartProxyController, bool> {
StartProxyControllerProvider._() StartProxyControllerProvider._()
: super( : super(
from: null, from: null,
@@ -33,28 +33,28 @@ final class StartProxyControllerProvider
StartProxyController create() => StartProxyController(); StartProxyController create() => StartProxyController();
/// {@macro riverpod.override_with_value} /// {@macro riverpod.override_with_value}
Override overrideWithValue(void value) { Override overrideWithValue(bool value) {
return $ProviderOverride( return $ProviderOverride(
origin: this, origin: this,
providerOverride: $SyncValueProvider<void>(value), providerOverride: $SyncValueProvider<bool>(value),
); );
} }
} }
String _$startProxyControllerHash() => String _$startProxyControllerHash() =>
r'13c6ad9611a2f9525689d370a0511274aa9c0f03'; r'899b585bf7f220251ac92f11c79537cc07723241';
abstract class _$StartProxyController extends $Notifier<void> { abstract class _$StartProxyController extends $Notifier<bool> {
void build(); bool build();
@$mustCallSuper @$mustCallSuper
@override @override
void runBuild() { void runBuild() {
final ref = this.ref as $Ref<void, void>; final ref = this.ref as $Ref<bool, bool>;
final element = final element =
ref.element ref.element
as $ClassProviderElement< as $ClassProviderElement<
AnyNotifier<void, void>, AnyNotifier<bool, bool>,
void, bool,
Object?, Object?,
Object? Object?
>; >;
@@ -30,6 +30,7 @@ const automaticCountry = '';
class CountryPickerScreen extends HookWidget { class CountryPickerScreen extends HookWidget {
const CountryPickerScreen({ const CountryPickerScreen({
super.key,
required this.title, required this.title,
this.selectedCountryCode, this.selectedCountryCode,
}); });
@@ -51,20 +52,16 @@ class CountryPickerScreen extends HookWidget {
country.countryCode ?? country.countryCode ??
'Unnamed Country'; 'Unnamed Country';
return (alpha2Code: country.alpha2Code, label: label); return (alpha2Code: country.alpha2Code, label: label);
}).toList() }).toList()..sort((a, b) => a.label.compareTo(b.label));
..sort((a, b) => a.label.compareTo(b.label));
}); });
final filteredCountries = useMemoized( final filteredCountries = useMemoized(() {
() {
if (searchQuery.value.isEmpty) return countries; if (searchQuery.value.isEmpty) return countries;
final query = searchQuery.value.toLowerCase(); final query = searchQuery.value.toLowerCase();
return countries return countries
.where((c) => c.label.toLowerCase().contains(query)) .where((c) => c.label.toLowerCase().contains(query))
.toList(); .toList();
}, }, [searchQuery.value, countries]);
[searchQuery.value, countries],
);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
@@ -95,7 +92,7 @@ class CountryPickerScreen extends HookWidget {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
borderSide: BorderSide.none, borderSide: BorderSide.none,
), ),
contentPadding: const EdgeInsets.symmetric(vertical: 0), contentPadding: EdgeInsets.zero,
), ),
onChanged: (value) => searchQuery.value = value, onChanged: (value) => searchQuery.value = value,
), ),
@@ -24,9 +24,9 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:nullability/nullability.dart'; import 'package:nullability/nullability.dart';
import 'package:weblibre/core/design/app_colors.dart'; import 'package:weblibre/core/design/app_colors.dart';
import 'package:weblibre/core/routing/routes.dart';
import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart'; import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart';
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart'; import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
import 'package:weblibre/core/routing/routes.dart';
import 'package:weblibre/features/tor/presentation/screens/country_picker.dart'; import 'package:weblibre/features/tor/presentation/screens/country_picker.dart';
import 'package:weblibre/features/user/data/models/tor_settings.dart'; import 'package:weblibre/features/user/data/models/tor_settings.dart';
import 'package:weblibre/features/user/domain/repositories/tor_settings.dart'; import 'package:weblibre/features/user/domain/repositories/tor_settings.dart';
@@ -34,7 +34,7 @@ import 'package:weblibre/presentation/hooks/on_initialization.dart';
import 'package:weblibre/utils/ui_helper.dart'; import 'package:weblibre/utils/ui_helper.dart';
class TorProxyScreen extends HookConsumerWidget { class TorProxyScreen extends HookConsumerWidget {
const TorProxyScreen(); const TorProxyScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -465,7 +465,8 @@ class TorProxyScreen extends HookConsumerWidget {
), ),
ListTile( ListTile(
enabled: !torIsBusy, enabled: !torIsBusy,
leading: torSettings.entryNodeCountry.mapNotNull( leading:
torSettings.entryNodeCountry.mapNotNull(
(code) => CountryFlag.fromCountryCode( (code) => CountryFlag.fromCountryCode(
code, code,
theme: const EmojiTheme(size: 28), theme: const EmojiTheme(size: 28),
@@ -486,8 +487,9 @@ class TorProxyScreen extends HookConsumerWidget {
$extra: torSettings.entryNodeCountry, $extra: torSettings.entryNodeCountry,
).push<String>(context); ).push<String>(context);
if (result == null) return; if (result == null) return;
final value = final value = result == automaticCountry
result == automaticCountry ? null : result; ? null
: result;
await ref await ref
.read(saveTorSettingsControllerProvider.notifier) .read(saveTorSettingsControllerProvider.notifier)
.save( .save(
@@ -498,7 +500,8 @@ class TorProxyScreen extends HookConsumerWidget {
), ),
ListTile( ListTile(
enabled: !torIsBusy, enabled: !torIsBusy,
leading: torSettings.exitNodeCountry.mapNotNull( leading:
torSettings.exitNodeCountry.mapNotNull(
(code) => CountryFlag.fromCountryCode( (code) => CountryFlag.fromCountryCode(
code, code,
theme: const EmojiTheme(size: 28), theme: const EmojiTheme(size: 28),
@@ -519,8 +522,9 @@ class TorProxyScreen extends HookConsumerWidget {
$extra: torSettings.exitNodeCountry, $extra: torSettings.exitNodeCountry,
).push<String>(context); ).push<String>(context);
if (result == null) return; if (result == null) return;
final value = final value = result == automaticCountry
result == automaticCountry ? null : result; ? null
: result;
await ref await ref
.read(saveTorSettingsControllerProvider.notifier) .read(saveTorSettingsControllerProvider.notifier)
.save( .save(
@@ -23,7 +23,7 @@ import 'package:weblibre/core/design/app_colors.dart';
import 'package:weblibre/presentation/icons/tor_icons.dart'; import 'package:weblibre/presentation/icons/tor_icons.dart';
class TorDialog extends StatelessWidget { class TorDialog extends StatelessWidget {
const TorDialog(); const TorDialog({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -26,6 +26,8 @@ import 'package:weblibre/presentation/icons/tor_icons.dart';
import 'package:weblibre/presentation/widgets/animate_gradient_shader.dart'; import 'package:weblibre/presentation/widgets/animate_gradient_shader.dart';
class TorNotification extends HookConsumerWidget { class TorNotification extends HookConsumerWidget {
const TorNotification({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final appColors = AppColors.of(context); final appColors = AppColors.of(context);
@@ -31,7 +31,7 @@ import 'package:weblibre/presentation/widgets/failure_widget.dart';
/// Bottom sheet widget to select a user profile. /// Bottom sheet widget to select a user profile.
class SelectProfileDialog extends HookConsumerWidget { class SelectProfileDialog extends HookConsumerWidget {
const SelectProfileDialog(); const SelectProfileDialog({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -31,7 +31,7 @@ import 'package:weblibre/utils/ui_helper.dart';
class ProfileBackupScreen extends HookConsumerWidget { class ProfileBackupScreen extends HookConsumerWidget {
final Profile profile; final Profile profile;
const ProfileBackupScreen({required this.profile}); const ProfileBackupScreen({super.key, required this.profile});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -31,7 +31,7 @@ final _filenamePattern = RegExp(
); );
class ProfileBackupListScreen extends HookConsumerWidget { class ProfileBackupListScreen extends HookConsumerWidget {
const ProfileBackupListScreen(); const ProfileBackupListScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -46,7 +46,7 @@ const _timeoutOptions = <DropdownMenuItem<Duration?>>[
class ProfileEditScreen extends HookConsumerWidget { class ProfileEditScreen extends HookConsumerWidget {
final Profile? profile; final Profile? profile;
const ProfileEditScreen({required this.profile}); const ProfileEditScreen({super.key, required this.profile});
Future<void> _handleSave( Future<void> _handleSave(
BuildContext context, BuildContext context,
@@ -28,7 +28,7 @@ import 'package:weblibre/features/user/domain/repositories/profile.dart';
import 'package:weblibre/presentation/widgets/failure_widget.dart'; import 'package:weblibre/presentation/widgets/failure_widget.dart';
class ProfileListScreen extends HookConsumerWidget { class ProfileListScreen extends HookConsumerWidget {
const ProfileListScreen(); const ProfileListScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -27,7 +27,7 @@ import 'package:weblibre/features/user/domain/providers/profile_auth.dart';
import 'package:weblibre/presentation/hooks/on_initialization.dart'; import 'package:weblibre/presentation/hooks/on_initialization.dart';
class LockScreen extends HookConsumerWidget { class LockScreen extends HookConsumerWidget {
const LockScreen(); const LockScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -32,7 +32,7 @@ import 'package:weblibre/presentation/widgets/speech_to_text_button.dart';
class FeedArticleListScreen extends HookConsumerWidget { class FeedArticleListScreen extends HookConsumerWidget {
final Uri? feedId; final Uri? feedId;
const FeedArticleListScreen({required this.feedId}); const FeedArticleListScreen({super.key, required this.feedId});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -28,7 +28,7 @@ import 'package:weblibre/features/web_feed/presentation/widgets/feed_card.dart';
import 'package:weblibre/presentation/widgets/failure_widget.dart'; import 'package:weblibre/presentation/widgets/failure_widget.dart';
class FeedListScreen extends HookConsumerWidget { class FeedListScreen extends HookConsumerWidget {
const FeedListScreen(); const FeedListScreen({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -29,7 +29,7 @@ import 'package:weblibre/presentation/widgets/failure_widget.dart';
class SelectFeedDialog extends HookConsumerWidget { class SelectFeedDialog extends HookConsumerWidget {
final Set<Uri> feedUris; final Set<Uri> feedUris;
const SelectFeedDialog({required this.feedUris}); const SelectFeedDialog({super.key, required this.feedUris});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -25,7 +25,7 @@ import 'package:weblibre/features/web_feed/data/models/feed_author.dart';
class AuthorsHorizontalList extends StatelessWidget { class AuthorsHorizontalList extends StatelessWidget {
late final List<Widget> _authors; late final List<Widget> _authors;
AuthorsHorizontalList({ AuthorsHorizontalList({super.key,
required List<FeedAuthor> authors, required List<FeedAuthor> authors,
Set<String> selectedTags = const {}, Set<String> selectedTags = const {},
void Function(String tagId, bool value)? onTagSelected, void Function(String tagId, bool value)? onTagSelected,
@@ -25,7 +25,7 @@ import 'package:weblibre/features/web_feed/data/models/feed_category.dart';
class TagsHorizontalList extends StatelessWidget { class TagsHorizontalList extends StatelessWidget {
late final List<Widget> _tags; late final List<Widget> _tags;
TagsHorizontalList({ TagsHorizontalList({super.key,
required List<FeedCategory> tags, required List<FeedCategory> tags,
Set<String> selectedTags = const {}, Set<String> selectedTags = const {},
void Function(String tagId, bool value)? onTagSelected, void Function(String tagId, bool value)? onTagSelected,
@@ -26,7 +26,7 @@ import 'package:weblibre/features/qr_scanner/presentation/dialogs/qr_scanner_dia
class QrScannerButton extends HookConsumerWidget { class QrScannerButton extends HookConsumerWidget {
final void Function(Barcode? scanResult) onScanResult; final void Function(Barcode? scanResult) onScanResult;
const QrScannerButton({required this.onScanResult}); const QrScannerButton({super.key, required this.onScanResult});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -35,7 +35,7 @@ class QrScannerButton extends HookConsumerWidget {
final result = await showDialog<Barcode>( final result = await showDialog<Barcode>(
context: context, context: context,
builder: (context) { builder: (context) {
return QrScannerDialog(); return const QrScannerDialog();
}, },
); );
@@ -16,10 +16,10 @@ dependencies:
path: ../ path: ../
dev_dependencies: dev_dependencies:
integration_test:
sdk: flutter
flutter_test: flutter_test:
sdk: flutter sdk: flutter
integration_test:
sdk: flutter
lint: ^2.8.0 lint: ^2.8.0
flutter: flutter:
@@ -6,9 +6,8 @@
// tree, read text, and verify that the values of widget properties are correct. // tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_mozilla_components_example/main.dart'; import 'package:flutter_mozilla_components_example/main.dart';
import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('Verify Platform version', (WidgetTester tester) async { testWidgets('Verify Platform version', (WidgetTester tester) async {
+1 -1
View File
@@ -27,11 +27,11 @@ dependencies:
socks5_proxy: ^2.1.1 socks5_proxy: ^2.1.1
dev_dependencies: dev_dependencies:
lint: ^2.8.0
flutter_test: flutter_test:
sdk: flutter sdk: flutter
integration_test: integration_test:
sdk: flutter sdk: flutter
lint: ^2.8.0
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec
+4 -5
View File
@@ -1,9 +1,8 @@
export 'src/flutter_tor.dart';
export 'src/tor_api.g.dart' export 'src/tor_api.g.dart'
show show
TransportType, IPtProxyController,
TorConfiguration, TorConfiguration,
TorStatus,
TorLogMessage, TorLogMessage,
IPtProxyController; TorStatus,
TransportType;
export 'src/flutter_tor.dart';
@@ -57,9 +57,9 @@ class FlutterTor {
// Unregister the Flutter API handler // Unregister the Flutter API handler
TorLogApi.setUp(null); TorLogApi.setUp(null);
_logController.close(); unawaited(_logController.close());
_statusController.close(); unawaited(_statusController.close());
_bootstrapController.close(); unawaited(_bootstrapController.close());
} }
} }
@@ -26,15 +26,11 @@ dependencies:
# the parent directory to use the current plugin's version. # the parent directory to use the current plugin's version.
path: ../ path: ../
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
dev_dependencies: dev_dependencies:
integration_test:
sdk: flutter
flutter_test: flutter_test:
sdk: flutter sdk: flutter
integration_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to # The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is # encourage good coding practices. The lint set provided by the package is
@@ -42,6 +42,6 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp(); return const MaterialApp();
} }
} }
@@ -17,7 +17,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
logger: ^2.6.2
simple_intent_receiver: simple_intent_receiver:
# When depending on this package from a real application you should use: # When depending on this package from a real application you should use:
# simple_intent_receiver: ^x.y.z # simple_intent_receiver: ^x.y.z
@@ -26,16 +26,11 @@ dependencies:
# the parent directory to use the current plugin's version. # the parent directory to use the current plugin's version.
path: ../ path: ../
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
logger: ^2.6.2
dev_dependencies: dev_dependencies:
integration_test:
sdk: flutter
flutter_test: flutter_test:
sdk: flutter sdk: flutter
integration_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to # The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is # encourage good coding practices. The lint set provided by the package is
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart';
import 'package:speech_to_text_dialog/speech_to_text_dialog.dart'; import 'package:speech_to_text_dialog/speech_to_text_dialog.dart';
void main() { void main() {
@@ -50,7 +50,7 @@ class _MyAppState extends State<MyApp> {
@override @override
void dispose() { void dispose() {
_textSubscription?.cancel(); unawaited(_textSubscription?.cancel());
_speechToTextDialog.dispose(); _speechToTextDialog.dispose();
super.dispose(); super.dispose();
} }
@@ -26,15 +26,11 @@ dependencies:
# the parent directory to use the current plugin's version. # the parent directory to use the current plugin's version.
path: ../ path: ../
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
dev_dependencies: dev_dependencies:
integration_test:
sdk: flutter
flutter_test: flutter_test:
sdk: flutter sdk: flutter
integration_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to # The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is # encourage good coding practices. The lint set provided by the package is
@@ -20,7 +20,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/services.dart' show BinaryMessenger; import 'package:flutter/services.dart' show BinaryMessenger;
import 'src/pigeons/speech_to_text.g.dart'; import 'package:speech_to_text_dialog/src/pigeons/speech_to_text.g.dart';
/// Speech recognition dialog using Android's RecognizerIntent. /// Speech recognition dialog using Android's RecognizerIntent.
/// ///
@@ -82,7 +82,7 @@ class SpeechToTextDialog implements SpeechToTextEvents {
/// print('Speech recognition not available'); /// print('Speech recognition not available');
/// } /// }
/// ``` /// ```
Future<bool> showDialog({String? locale}) async { Future<bool> showDialog({String? locale}) {
return _api.showDialog(locale: locale); return _api.showDialog(locale: locale);
} }
@@ -101,7 +101,7 @@ class SpeechToTextDialog implements SpeechToTextEvents {
if (!_disposed) { if (!_disposed) {
_disposed = true; _disposed = true;
SpeechToTextEvents.setUp(null, binaryMessenger: _binaryMessenger); SpeechToTextEvents.setUp(null, binaryMessenger: _binaryMessenger);
_textStreamController.close(); unawaited(_textStreamController.close());
} }
} }
} }