background fetch running
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
@@ -25,8 +23,8 @@ class SelectedTab extends _$SelectedTab {
|
||||
state = tabId;
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(selectedTabSub.cancel());
|
||||
ref.onDispose(() async {
|
||||
await selectedTabSub.cancel();
|
||||
});
|
||||
|
||||
return null;
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'selected_tab.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$selectedTabHash() => r'250f54fe9a56d14876e0979e5370eb76879da11c';
|
||||
String _$selectedTabHash() => r'12b670dd76c3416e8d62bafd63bf69a83a603e3a';
|
||||
|
||||
/// See also [SelectedTab].
|
||||
@ProviderFor(SelectedTab)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fast_equatable/fast_equatable.dart';
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||
@@ -30,8 +28,8 @@ class TabList extends _$TabList {
|
||||
}
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(tabListSub.cancel());
|
||||
ref.onDispose(() async {
|
||||
await tabListSub.cancel();
|
||||
});
|
||||
|
||||
return EquatableValue([]);
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'tab_list.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$tabListHash() => r'2b98ccdf62c15670e0a12e38064e8186e6555cf8';
|
||||
String _$tabListHash() => r'9507bcc75dc69a55aba14334cdef0128a5fcf252';
|
||||
|
||||
/// See also [TabList].
|
||||
@ProviderFor(TabList)
|
||||
|
||||
@@ -165,9 +165,9 @@ class TabStates extends _$TabStates {
|
||||
}
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
ref.onDispose(() async {
|
||||
for (final sub in subscriptions) {
|
||||
unawaited(sub.cancel());
|
||||
await sub.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ final selectedTabStateProvider = AutoDisposeProvider<TabState?>.internal(
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef SelectedTabStateRef = AutoDisposeProviderRef<TabState?>;
|
||||
String _$tabStatesHash() => r'b136dbf6d68b67f0fe0db302a4147b67789db853';
|
||||
String _$tabStatesHash() => r'3a906aec8c4e650de8d5d2461ff45a99b8a0a3b9';
|
||||
|
||||
/// See also [TabStates].
|
||||
@ProviderFor(TabStates)
|
||||
|
||||
@@ -86,9 +86,9 @@ class WebExtensionsState extends _$WebExtensionsState {
|
||||
],
|
||||
};
|
||||
|
||||
ref.onDispose(() {
|
||||
ref.onDispose(() async {
|
||||
for (final sub in subscriptions) {
|
||||
unawaited(sub.cancel());
|
||||
await sub.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ part of 'web_extensions_state.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$webExtensionsStateHash() =>
|
||||
r'eab924e9c17e805a3c29065289be5d1c8ffe3bc9';
|
||||
r'6fb44ab543250f2b2554e410ee749fdd035cd4e7';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
||||
@@ -167,10 +167,10 @@ class TabRepository extends _$TabRepository {
|
||||
});
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
ref.onDispose(() async {
|
||||
tabStateDebouncer.dispose();
|
||||
unawaited(tabAddedSub.cancel());
|
||||
unawaited(tabContentSub.cancel());
|
||||
await tabAddedSub.cancel();
|
||||
await tabContentSub.cancel();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'tab.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$tabRepositoryHash() => r'69e283b820d86388f4d80e71e08761e2b6890507';
|
||||
String _$tabRepositoryHash() => r'35c078a841d815aa2452c07b52c4cf0cbcec7e68';
|
||||
|
||||
/// See also [TabRepository].
|
||||
@ProviderFor(TabRepository)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fast_equatable/fast_equatable.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/domain/repositories/data.dart';
|
||||
@@ -48,8 +46,8 @@ class SelectedBangData extends _$SelectedBangData {
|
||||
state = value;
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(subscription.cancel());
|
||||
ref.onDispose(() async {
|
||||
await subscription.cancel();
|
||||
});
|
||||
|
||||
return null;
|
||||
|
||||
@@ -719,7 +719,7 @@ class _SelectedBangTriggerProviderElement
|
||||
String? get domain => (origin as SelectedBangTriggerProvider).domain;
|
||||
}
|
||||
|
||||
String _$selectedBangDataHash() => r'28c394e5989e108870ca5733e916b80b3cf8972c';
|
||||
String _$selectedBangDataHash() => r'666858556efe59d2de38a04fda30e8ec227c6675';
|
||||
|
||||
abstract class _$SelectedBangData
|
||||
extends BuildlessAutoDisposeNotifier<BangData?> {
|
||||
|
||||
+2
-2
@@ -4,10 +4,10 @@ import 'package:lensai/features/geckoview/features/tabs/domain/providers.dart';
|
||||
import 'package:lensai/features/tor/domain/services/tor_proxy.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'proxy_settings_replucation.g.dart';
|
||||
part 'proxy_settings_replication.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class ProxySettingsReplucation extends _$ProxySettingsReplucation {
|
||||
class ProxySettingsReplication extends _$ProxySettingsReplication {
|
||||
final _service = GeckoContainerProxyService();
|
||||
|
||||
@override
|
||||
+11
-11
@@ -1,28 +1,28 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'proxy_settings_replucation.dart';
|
||||
part of 'proxy_settings_replication.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$proxySettingsReplucationHash() =>
|
||||
r'b00fc9a9c8b385a0f8a5830e9ba1c329d340c0ae';
|
||||
String _$proxySettingsReplicationHash() =>
|
||||
r'1982923eeb0bcd6d606683fde70835ec7aff601b';
|
||||
|
||||
/// See also [ProxySettingsReplucation].
|
||||
@ProviderFor(ProxySettingsReplucation)
|
||||
final proxySettingsReplucationProvider =
|
||||
NotifierProvider<ProxySettingsReplucation, void>.internal(
|
||||
ProxySettingsReplucation.new,
|
||||
name: r'proxySettingsReplucationProvider',
|
||||
/// See also [ProxySettingsReplication].
|
||||
@ProviderFor(ProxySettingsReplication)
|
||||
final proxySettingsReplicationProvider =
|
||||
NotifierProvider<ProxySettingsReplication, void>.internal(
|
||||
ProxySettingsReplication.new,
|
||||
name: r'proxySettingsReplicationProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$proxySettingsReplucationHash,
|
||||
: _$proxySettingsReplicationHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$ProxySettingsReplucation = Notifier<void>;
|
||||
typedef _$ProxySettingsReplication = Notifier<void>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
+8
-2
@@ -15,11 +15,12 @@ import 'package:lensai/features/geckoview/domain/providers/web_extensions_state.
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/domain/services/browser_data.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/domain/services/engine_settings_replication.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/domain/services/proxy_settings_replucation.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/domain/services/proxy_settings_replication.dart';
|
||||
import 'package:lensai/features/geckoview/features/tabs/features/vector_store/domain/repositories/document.dart';
|
||||
import 'package:lensai/features/user/domain/repositories/cache.dart';
|
||||
import 'package:lensai/features/user/domain/repositories/general_settings.dart';
|
||||
import 'package:lensai/features/user/domain/services/local_authentication.dart';
|
||||
import 'package:lensai/features/web_feed/domain/services/article_content_processor.dart';
|
||||
|
||||
class BrowserView extends StatefulHookConsumerWidget {
|
||||
final Duration screenshotPeriod;
|
||||
@@ -151,7 +152,12 @@ class _BrowserViewState extends ConsumerState<BrowserView>
|
||||
(previous, next) {},
|
||||
);
|
||||
|
||||
ref.listenManual(proxySettingsReplucationProvider, (previous, next) {});
|
||||
ref.listenManual(proxySettingsReplicationProvider, (previous, next) {});
|
||||
|
||||
ref.listenManual(
|
||||
articleContentProcessorServiceProvider,
|
||||
(previous, next) {},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
+2
-2
@@ -68,8 +68,8 @@ class _PreferenceRepository extends _$PreferenceRepository {
|
||||
Raw<Stream<Map<String, Object>>> build() {
|
||||
_prefSubject = BehaviorSubject<Map<String, Object>>();
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(_prefSubject.close());
|
||||
ref.onDispose(() async {
|
||||
await _prefSubject.close();
|
||||
});
|
||||
|
||||
ref.onAddListener(() async {
|
||||
|
||||
+1
-1
@@ -330,7 +330,7 @@ class _PreferenceSettingGroupProviderElement
|
||||
}
|
||||
|
||||
String _$preferenceRepositoryHash() =>
|
||||
r'53c0cbbf60e44c3834fe3e3255836f7e27f09c7f';
|
||||
r'b2b7f75b3d30842b3006bb18af89f7ff90ba4ce7';
|
||||
|
||||
/// See also [_PreferenceRepository].
|
||||
@ProviderFor(_PreferenceRepository)
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:lensai/features/geckoview/domain/controllers/bottom_sheet.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
|
||||
import 'package:lensai/features/geckoview/features/search/presentation/widgets/search_field.dart';
|
||||
import 'package:lensai/features/geckoview/features/search/presentation/widgets/search_modules/feed_search.dart';
|
||||
import 'package:lensai/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart';
|
||||
import 'package:lensai/features/geckoview/features/search/presentation/widgets/search_modules/search_suggestions.dart';
|
||||
import 'package:lensai/features/geckoview/features/search/presentation/widgets/search_modules/tab_search.dart';
|
||||
@@ -116,6 +117,7 @@ class SearchScreen extends HookConsumerWidget {
|
||||
),
|
||||
const SliverToBoxAdapter(child: Divider()),
|
||||
TabSearch(searchTextController: searchTextController),
|
||||
FeedSearch(searchTextController: searchTextController),
|
||||
HistorySuggestions(searchTextController: searchTextController),
|
||||
],
|
||||
),
|
||||
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/core/routing/routes.dart';
|
||||
import 'package:lensai/extensions/nullable.dart';
|
||||
import 'package:lensai/extensions/uri.dart';
|
||||
import 'package:lensai/features/web_feed/data/models/feed_article_query_result.dart';
|
||||
import 'package:lensai/features/web_feed/data/models/feed_link.dart';
|
||||
import 'package:lensai/features/web_feed/domain/providers.dart';
|
||||
import 'package:lensai/features/web_feed/extensions/atom.dart';
|
||||
import 'package:lensai/features/web_feed/extensions/feed_article.dart';
|
||||
import 'package:lensai/presentation/hooks/listenable_callback.dart';
|
||||
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
||||
import 'package:lensai/presentation/widgets/url_icon.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:sliver_tools/sliver_tools.dart';
|
||||
|
||||
class FeedSearch extends HookConsumerWidget {
|
||||
static const _matchPrefix = '***';
|
||||
static const _matchSuffix = '***';
|
||||
|
||||
final TextEditingController searchTextController;
|
||||
|
||||
const FeedSearch({required this.searchTextController});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
final articlesAsync = ref.watch(articleSearchProvider(null));
|
||||
|
||||
useListenableCallback(searchTextController, () async {
|
||||
await ref
|
||||
.read(articleSearchProvider(null).notifier)
|
||||
.search(
|
||||
searchTextController.text,
|
||||
// ignore: avoid_redundant_argument_values dont break things
|
||||
matchPrefix: _matchPrefix,
|
||||
// ignore: avoid_redundant_argument_values dont break things
|
||||
matchSuffix: _matchSuffix,
|
||||
);
|
||||
});
|
||||
|
||||
if (articlesAsync.hasValue && (articlesAsync.valueOrNull.isEmpty)) {
|
||||
return const SliverToBoxAdapter(child: SizedBox.shrink());
|
||||
}
|
||||
|
||||
return MultiSliver(
|
||||
children: [
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Articles', style: Theme.of(context).textTheme.labelSmall),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverSkeletonizer(
|
||||
enabled: articlesAsync.isLoading,
|
||||
child: articlesAsync.when(
|
||||
data:
|
||||
(articles) => SliverList.builder(
|
||||
itemCount: articles.length,
|
||||
itemBuilder: (context, index) {
|
||||
final article = articles[index];
|
||||
|
||||
final titleHighlight = switch (article) {
|
||||
final FeedArticleQueryResult result =>
|
||||
result.titleHighlight.whenNotEmpty,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
final searchSnippet = switch (article) {
|
||||
final FeedArticleQueryResult result =>
|
||||
result.summarySnippet.whenNotEmpty ??
|
||||
result.contentSnippet.whenNotEmpty,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
return ListTile(
|
||||
leading: RepaintBoundary(
|
||||
child: UrlIcon([
|
||||
article.icon ??
|
||||
article.links
|
||||
?.getRelation(FeedLinkRelation.alternate)
|
||||
?.uri ??
|
||||
article.siteLink ??
|
||||
article.feedId.base,
|
||||
], iconSize: 24.0),
|
||||
),
|
||||
title:
|
||||
(titleHighlight.isNotEmpty)
|
||||
? MarkdownBody(
|
||||
data: titleHighlight!,
|
||||
styleSheet: MarkdownStyleSheet(
|
||||
p: Theme.of(
|
||||
context,
|
||||
).textTheme.titleMedium?.copyWith(
|
||||
color:
|
||||
Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
article.displayTitle,
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
subtitle:
|
||||
(searchSnippet.isNotEmpty)
|
||||
? MarkdownBody(
|
||||
data: searchSnippet!,
|
||||
styleSheet: MarkdownStyleSheet(
|
||||
p: Theme.of(
|
||||
context,
|
||||
).textTheme.bodyMedium?.copyWith(
|
||||
color:
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
a: Theme.of(
|
||||
context,
|
||||
).textTheme.bodyMedium?.copyWith(
|
||||
color:
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurfaceVariant,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
)
|
||||
: ((article.summaryPlain != null)
|
||||
? Text(
|
||||
article.summaryPlain!,
|
||||
style: theme.textTheme.bodySmall,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
)
|
||||
: null),
|
||||
onTap: () {
|
||||
FeedArticleRoute(
|
||||
articleId: article.id,
|
||||
).pushReplacement(context);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
error: (error, stackTrace) {
|
||||
return SliverToBoxAdapter(
|
||||
child: FailureWidget(
|
||||
title: 'Failed searching Articles',
|
||||
exception: error,
|
||||
),
|
||||
);
|
||||
},
|
||||
loading:
|
||||
() => SliverList.builder(
|
||||
itemCount: articlesAsync.valueOrNull?.length ?? 3,
|
||||
itemBuilder: (context, index) {
|
||||
return const ListTile(title: Bone.text());
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
+11
-9
@@ -20,7 +20,7 @@ class HistorySuggestions extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final historySuggestions = ref.watch(engineHistorySuggestionsProvider);
|
||||
final historySuggestionsAsync = ref.watch(engineHistorySuggestionsProvider);
|
||||
|
||||
useListenableCallback(searchTextController, () async {
|
||||
await ref
|
||||
@@ -28,8 +28,8 @@ class HistorySuggestions extends HookConsumerWidget {
|
||||
.addQuery(searchTextController.text);
|
||||
});
|
||||
|
||||
if (historySuggestions.hasValue &&
|
||||
(historySuggestions.valueOrNull.isEmpty)) {
|
||||
if (historySuggestionsAsync.hasValue &&
|
||||
(historySuggestionsAsync.valueOrNull.isEmpty)) {
|
||||
return const SliverToBoxAdapter(child: SizedBox.shrink());
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ class HistorySuggestions extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
SliverSkeletonizer(
|
||||
enabled: historySuggestions.isLoading,
|
||||
child: historySuggestions.when(
|
||||
enabled: historySuggestionsAsync.isLoading,
|
||||
child: historySuggestionsAsync.when(
|
||||
skipLoadingOnReload: true,
|
||||
data: (historySuggestions) {
|
||||
return SliverList.builder(
|
||||
@@ -109,14 +109,16 @@ class HistorySuggestions extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
error: (error, stackTrace) {
|
||||
return FailureWidget(
|
||||
title: 'Could not load history',
|
||||
exception: error,
|
||||
return SliverToBoxAdapter(
|
||||
child: FailureWidget(
|
||||
title: 'Could not load history',
|
||||
exception: error,
|
||||
),
|
||||
);
|
||||
},
|
||||
loading:
|
||||
() => SliverList.builder(
|
||||
itemCount: historySuggestions.valueOrNull?.length ?? 3,
|
||||
itemCount: historySuggestionsAsync.valueOrNull?.length ?? 3,
|
||||
itemBuilder: (context, index) {
|
||||
return const ListTile(title: Bone.text());
|
||||
},
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:lensai/core/providers/models.dart';
|
||||
@@ -51,8 +49,8 @@ TabDatabase tabDatabase(Ref ref) {
|
||||
embeddingDimensions: dimensions,
|
||||
);
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(db.close());
|
||||
ref.onDispose(() async {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
return db;
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'providers.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$tabDatabaseHash() => r'940dd2a1f1df6f2a0b77a1a3e9b8318550b832d2';
|
||||
String _$tabDatabaseHash() => r'db190f01d7e70e65b9f44403effa82ec503144a0';
|
||||
|
||||
/// See also [tabDatabase].
|
||||
@ProviderFor(tabDatabase)
|
||||
|
||||
+2
-2
@@ -108,8 +108,8 @@ class DocumentRepository extends _$DocumentRepository {
|
||||
}
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(tabContentSub.cancel());
|
||||
ref.onDispose(() async {
|
||||
await tabContentSub.cancel();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ part of 'document.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$documentRepositoryHash() =>
|
||||
r'60e5a0c889d9659c8e0e254c59225c2041a0cb56';
|
||||
r'fd78b5eaf96951724e905b068144dcf2a254dcbb';
|
||||
|
||||
/// See also [DocumentRepository].
|
||||
@ProviderFor(DocumentRepository)
|
||||
|
||||
Reference in New Issue
Block a user