intermediate

This commit is contained in:
Fabian Freund
2025-01-07 00:06:31 +01:00
parent ea0880b97a
commit 4a2191b01d
84 changed files with 2655 additions and 1383 deletions
@@ -1,5 +1,6 @@
import 'package:lensai/features/bangs/data/models/bang.dart';
import 'package:lensai/features/bangs/data/models/bang_data.dart';
import 'package:lensai/features/bangs/data/models/search_history_entry.dart';
import 'package:lensai/features/bangs/domain/repositories/data.dart';
import 'package:lensai/features/bangs/domain/repositories/sync.dart';
import 'package:riverpod/riverpod.dart';
@@ -50,6 +51,12 @@ Stream<List<BangData>> frequentBangDataList(Ref ref) {
return repository.watchFrequentBangs();
}
@Riverpod()
Stream<List<SearchHistoryEntry>> searchHistory(Ref ref) {
final repository = ref.watch(bangDataRepositoryProvider.notifier);
return repository.watchSearchHistory(limit: 3); //TODO: make count dynamic
}
@Riverpod()
Future<BangData> bangDataEnsureIcon(
Ref ref,
@@ -78,9 +85,3 @@ Stream<int> bangCountOfGroup(
final repository = ref.watch(bangDataRepositoryProvider.notifier);
return repository.watchBangCount(group);
}
@Riverpod()
Stream<double> bangIconCacheSizeMegabytes(Ref ref) {
final repository = ref.watch(bangDataRepositoryProvider.notifier);
return repository.watchIconCacheSize();
}
@@ -368,6 +368,25 @@ final frequentBangDataListProvider =
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef FrequentBangDataListRef = AutoDisposeStreamProviderRef<List<BangData>>;
String _$searchHistoryHash() => r'7b97798729643de8e44fd8024cdc02f35124b08b';
/// See also [searchHistory].
@ProviderFor(searchHistory)
final searchHistoryProvider =
AutoDisposeStreamProvider<List<SearchHistoryEntry>>.internal(
searchHistory,
name: r'searchHistoryProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$searchHistoryHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef SearchHistoryRef
= AutoDisposeStreamProviderRef<List<SearchHistoryEntry>>;
String _$bangDataEnsureIconHash() =>
r'423b8e92fd89ec328c2fcc8f9e55365c30633fd2';
@@ -760,25 +779,5 @@ class _BangCountOfGroupProviderElement
@override
BangGroup get group => (origin as BangCountOfGroupProvider).group;
}
String _$bangIconCacheSizeMegabytesHash() =>
r'e08bfdc7bb47a56c079464478f0b8b5516b2effe';
/// See also [bangIconCacheSizeMegabytes].
@ProviderFor(bangIconCacheSizeMegabytes)
final bangIconCacheSizeMegabytesProvider =
AutoDisposeStreamProvider<double>.internal(
bangIconCacheSizeMegabytes,
name: r'bangIconCacheSizeMegabytesProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$bangIconCacheSizeMegabytesHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef BangIconCacheSizeMegabytesRef = AutoDisposeStreamProviderRef<double>;
// 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
@@ -0,0 +1,24 @@
import 'package:lensai/features/bangs/data/models/bang_data.dart';
import 'package:lensai/features/bangs/domain/repositories/data.dart';
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'search.g.dart';
@Riverpod()
Future<Uri> triggerBangSearch(
Ref ref,
BangData bang,
String searchQuery,
) async {
final bangDataNotifier = ref.watch(bangDataRepositoryProvider.notifier);
await bangDataNotifier.increaseFrequency(bang.trigger);
await bangDataNotifier.addSearchEntry(
bang.trigger,
searchQuery,
maxEntryCount: 3,
); //TODO: make count dynamic
return bang.getUrl(searchQuery);
}
@@ -0,0 +1,177 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'search.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$triggerBangSearchHash() => r'a5cff116ae09b26d4fa476ce6a2e6052fa6fa177';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [triggerBangSearch].
@ProviderFor(triggerBangSearch)
const triggerBangSearchProvider = TriggerBangSearchFamily();
/// See also [triggerBangSearch].
class TriggerBangSearchFamily extends Family<AsyncValue<Uri>> {
/// See also [triggerBangSearch].
const TriggerBangSearchFamily();
/// See also [triggerBangSearch].
TriggerBangSearchProvider call(
BangData bang,
String searchQuery,
) {
return TriggerBangSearchProvider(
bang,
searchQuery,
);
}
@override
TriggerBangSearchProvider getProviderOverride(
covariant TriggerBangSearchProvider provider,
) {
return call(
provider.bang,
provider.searchQuery,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'triggerBangSearchProvider';
}
/// See also [triggerBangSearch].
class TriggerBangSearchProvider extends AutoDisposeFutureProvider<Uri> {
/// See also [triggerBangSearch].
TriggerBangSearchProvider(
BangData bang,
String searchQuery,
) : this._internal(
(ref) => triggerBangSearch(
ref as TriggerBangSearchRef,
bang,
searchQuery,
),
from: triggerBangSearchProvider,
name: r'triggerBangSearchProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$triggerBangSearchHash,
dependencies: TriggerBangSearchFamily._dependencies,
allTransitiveDependencies:
TriggerBangSearchFamily._allTransitiveDependencies,
bang: bang,
searchQuery: searchQuery,
);
TriggerBangSearchProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.bang,
required this.searchQuery,
}) : super.internal();
final BangData bang;
final String searchQuery;
@override
Override overrideWith(
FutureOr<Uri> Function(TriggerBangSearchRef provider) create,
) {
return ProviderOverride(
origin: this,
override: TriggerBangSearchProvider._internal(
(ref) => create(ref as TriggerBangSearchRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
bang: bang,
searchQuery: searchQuery,
),
);
}
@override
AutoDisposeFutureProviderElement<Uri> createElement() {
return _TriggerBangSearchProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is TriggerBangSearchProvider &&
other.bang == bang &&
other.searchQuery == searchQuery;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, bang.hashCode);
hash = _SystemHash.combine(hash, searchQuery.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin TriggerBangSearchRef on AutoDisposeFutureProviderRef<Uri> {
/// The parameter `bang` of this provider.
BangData get bang;
/// The parameter `searchQuery` of this provider.
String get searchQuery;
}
class _TriggerBangSearchProviderElement
extends AutoDisposeFutureProviderElement<Uri> with TriggerBangSearchRef {
_TriggerBangSearchProviderElement(super.provider);
@override
BangData get bang => (origin as TriggerBangSearchProvider).bang;
@override
String get searchQuery => (origin as TriggerBangSearchProvider).searchQuery;
}
// 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
@@ -3,10 +3,10 @@ import 'dart:convert';
import 'package:drift/drift.dart';
import 'package:exceptions/exceptions.dart';
import 'package:lensai/domain/services/generic_website.dart';
import 'package:lensai/extensions/database_table_size.dart';
import 'package:lensai/features/bangs/data/database/database.dart';
import 'package:lensai/features/bangs/data/models/bang.dart';
import 'package:lensai/features/bangs/data/models/bang_data.dart';
import 'package:lensai/features/bangs/data/models/search_history_entry.dart';
import 'package:lensai/features/bangs/data/providers.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -63,29 +63,50 @@ class BangDataRepository extends _$BangDataRepository {
return _db.bangDao.getFrequentBangDataList(groups: groups).watch();
}
Stream<List<SearchHistoryEntry>> watchSearchHistory({required int limit}) {
return _db.searchHistoryEntries(limit: limit).watch();
}
Future<void> increaseFrequency(String trigger) {
return _db.bangDao.increaseBangFrequency(trigger);
}
Future<void> addSearchEntry(
String trigger,
String searchQuery, {
required int maxEntryCount,
}) {
//Pack in a transaction to bundle rebuilds of watch() queries
return _db.transaction(
() async {
await _db.bangDao.addSearchEntry(trigger, searchQuery);
await _db.evictHistoryEntries(limit: maxEntryCount);
},
);
}
Future<void> removeSearchEntry(String searchQuery) {
return _db.bangDao.removeSearchEntry(searchQuery);
}
Future<Result<BangData>> ensureIconAvailable(BangData bang) async {
if (bang.icon != null) {
return Result.success(bang);
}
final icon = await ref
.read(genericWebsiteServiceProvider.notifier)
.getUrlFavicon(url: Uri.parse(bang.getUrl('').origin));
final url = bang.getUrl('');
// await _db.bangDao.upsertBangIcon(bang.trigger, icon);
return Result.success(bang.copyWith.icon(icon));
}
final websiteProvider = ref.read(genericWebsiteServiceProvider.notifier);
final cachedIcon = await websiteProvider.getCachedIcon(url);
Stream<double> watchIconCacheSize() {
return _db.tableSize(_db.bangIcon).watchSingle();
}
if (cachedIcon != null) {
return Result.success(bang.copyWith.icon(cachedIcon));
}
Future<int> clearIconData() {
return _db.bangIcon.deleteAll();
return websiteProvider.fetchPageInfo(url).then(
(result) => result
.flatMap((pageInfo) => bang.copyWith.icon(pageInfo.favicon)),
);
}
Future<int> resetFrequencies() {
@@ -7,7 +7,7 @@ part of 'data.dart';
// **************************************************************************
String _$bangDataRepositoryHash() =>
r'abacc6db3a61958cae67a91cbfd312ae87c641b3';
r'b51786552a812ddd54d1418450fe03ff89351e28';
/// See also [BangDataRepository].
@ProviderFor(BangDataRepository)