prepare for multiple apps

This commit is contained in:
Fabian Freund
2026-04-06 12:23:11 +02:00
parent bd1600e8dc
commit 5afc323f04
904 changed files with 29 additions and 29 deletions
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2024-2026 Fabian Freund.
*
* This file is part of WebLibre
* (see https://weblibre.eu).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* 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/>.
*/
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:weblibre/features/bangs/data/models/bang_data.dart';
import 'package:weblibre/features/bangs/data/models/bang_group.dart';
import 'package:weblibre/features/bangs/data/models/bang_key.dart';
import 'package:weblibre/features/bangs/data/models/search_history_entry.dart';
import 'package:weblibre/features/bangs/domain/repositories/data.dart';
import 'package:weblibre/features/bangs/domain/repositories/sync.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
part 'bangs.g.dart';
@Riverpod(keepAlive: true)
Stream<BangData?> defaultSearchBangData(Ref ref) {
final key = ref.watch(
generalSettingsWithDefaultsProvider.select(
(value) => value.defaultSearchProvider,
),
);
final repository = ref.watch(bangDataRepositoryProvider.notifier);
return repository.watchBang(key);
}
@Riverpod()
Stream<BangData?> bangData(Ref ref, BangKey key) {
final repository = ref.watch(bangDataRepositoryProvider.notifier);
return repository.watchBang(key);
}
@Riverpod()
Stream<Map<String, List<String>>> bangCategories(Ref ref) {
final repository = ref.watch(bangDataRepositoryProvider.notifier);
return repository.watchCategories();
}
@Riverpod()
Stream<List<BangData>> bangList(
Ref ref, {
List<String>? triggers,
List<BangGroup>? groups,
String? domain,
({String category, String? subCategory})? categoryFilter,
bool? orderMostFrequentFirst,
}) {
final repository = ref.watch(bangDataRepositoryProvider.notifier);
return repository.watchBangs(
triggers: triggers,
groups: groups,
domain: domain,
categoryFilter: categoryFilter,
orderMostFrequentFirst: orderMostFrequentFirst,
);
}
@Riverpod()
Stream<List<BangData>> frequentBangList(Ref ref) {
final repository = ref.watch(bangDataRepositoryProvider.notifier);
return repository.watchFrequentBangs();
}
@Riverpod()
Stream<List<SearchHistoryEntry>> searchHistory(Ref ref) {
final repository = ref.watch(bangDataRepositoryProvider.notifier);
final maxSearchHistoryEntries = ref.watch(
generalSettingsWithDefaultsProvider.select(
(s) => s.maxSearchHistoryEntries,
),
);
return repository.watchSearchHistory(limit: maxSearchHistoryEntries);
}
@Riverpod()
Stream<DateTime?> lastSyncOfGroup(Ref ref, BangGroup group) {
final repository = ref.watch(bangSyncRepositoryProvider.notifier);
return repository.watchLastSyncOfGroup(group);
}
@Riverpod()
Stream<int> bangCountOfGroup(Ref ref, BangGroup group) {
final repository = ref.watch(bangDataRepositoryProvider.notifier);
return repository.watchBangCount(group);
}
@@ -0,0 +1,496 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'bangs.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(defaultSearchBangData)
final defaultSearchBangDataProvider = DefaultSearchBangDataProvider._();
final class DefaultSearchBangDataProvider
extends
$FunctionalProvider<AsyncValue<BangData?>, BangData?, Stream<BangData?>>
with $FutureModifier<BangData?>, $StreamProvider<BangData?> {
DefaultSearchBangDataProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'defaultSearchBangDataProvider',
isAutoDispose: false,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$defaultSearchBangDataHash();
@$internal
@override
$StreamProviderElement<BangData?> $createElement($ProviderPointer pointer) =>
$StreamProviderElement(pointer);
@override
Stream<BangData?> create(Ref ref) {
return defaultSearchBangData(ref);
}
}
String _$defaultSearchBangDataHash() =>
r'5f43b8989219cf3cb2f5ca65df351b6cb100427f';
@ProviderFor(bangData)
final bangDataProvider = BangDataFamily._();
final class BangDataProvider
extends
$FunctionalProvider<AsyncValue<BangData?>, BangData?, Stream<BangData?>>
with $FutureModifier<BangData?>, $StreamProvider<BangData?> {
BangDataProvider._({
required BangDataFamily super.from,
required BangKey super.argument,
}) : super(
retry: null,
name: r'bangDataProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$bangDataHash();
@override
String toString() {
return r'bangDataProvider'
''
'($argument)';
}
@$internal
@override
$StreamProviderElement<BangData?> $createElement($ProviderPointer pointer) =>
$StreamProviderElement(pointer);
@override
Stream<BangData?> create(Ref ref) {
final argument = this.argument as BangKey;
return bangData(ref, argument);
}
@override
bool operator ==(Object other) {
return other is BangDataProvider && other.argument == argument;
}
@override
int get hashCode {
return argument.hashCode;
}
}
String _$bangDataHash() => r'bd9f5ec8b29aab74620a9b5a4246cb7e3b2fd377';
final class BangDataFamily extends $Family
with $FunctionalFamilyOverride<Stream<BangData?>, BangKey> {
BangDataFamily._()
: super(
retry: null,
name: r'bangDataProvider',
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
);
BangDataProvider call(BangKey key) =>
BangDataProvider._(argument: key, from: this);
@override
String toString() => r'bangDataProvider';
}
@ProviderFor(bangCategories)
final bangCategoriesProvider = BangCategoriesProvider._();
final class BangCategoriesProvider
extends
$FunctionalProvider<
AsyncValue<Map<String, List<String>>>,
Map<String, List<String>>,
Stream<Map<String, List<String>>>
>
with
$FutureModifier<Map<String, List<String>>>,
$StreamProvider<Map<String, List<String>>> {
BangCategoriesProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'bangCategoriesProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$bangCategoriesHash();
@$internal
@override
$StreamProviderElement<Map<String, List<String>>> $createElement(
$ProviderPointer pointer,
) => $StreamProviderElement(pointer);
@override
Stream<Map<String, List<String>>> create(Ref ref) {
return bangCategories(ref);
}
}
String _$bangCategoriesHash() => r'947fcfd2dffcc7f585c6ed7379d319f4fe72293a';
@ProviderFor(bangList)
final bangListProvider = BangListFamily._();
final class BangListProvider
extends
$FunctionalProvider<
AsyncValue<List<BangData>>,
List<BangData>,
Stream<List<BangData>>
>
with $FutureModifier<List<BangData>>, $StreamProvider<List<BangData>> {
BangListProvider._({
required BangListFamily super.from,
required ({
List<String>? triggers,
List<BangGroup>? groups,
String? domain,
({String category, String? subCategory})? categoryFilter,
bool? orderMostFrequentFirst,
})
super.argument,
}) : super(
retry: null,
name: r'bangListProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$bangListHash();
@override
String toString() {
return r'bangListProvider'
''
'$argument';
}
@$internal
@override
$StreamProviderElement<List<BangData>> $createElement(
$ProviderPointer pointer,
) => $StreamProviderElement(pointer);
@override
Stream<List<BangData>> create(Ref ref) {
final argument =
this.argument
as ({
List<String>? triggers,
List<BangGroup>? groups,
String? domain,
({String category, String? subCategory})? categoryFilter,
bool? orderMostFrequentFirst,
});
return bangList(
ref,
triggers: argument.triggers,
groups: argument.groups,
domain: argument.domain,
categoryFilter: argument.categoryFilter,
orderMostFrequentFirst: argument.orderMostFrequentFirst,
);
}
@override
bool operator ==(Object other) {
return other is BangListProvider && other.argument == argument;
}
@override
int get hashCode {
return argument.hashCode;
}
}
String _$bangListHash() => r'd1e0bb9fa4f523ce516e075c0d149bf7803ebb2b';
final class BangListFamily extends $Family
with
$FunctionalFamilyOverride<
Stream<List<BangData>>,
({
List<String>? triggers,
List<BangGroup>? groups,
String? domain,
({String category, String? subCategory})? categoryFilter,
bool? orderMostFrequentFirst,
})
> {
BangListFamily._()
: super(
retry: null,
name: r'bangListProvider',
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
);
BangListProvider call({
List<String>? triggers,
List<BangGroup>? groups,
String? domain,
({String category, String? subCategory})? categoryFilter,
bool? orderMostFrequentFirst,
}) => BangListProvider._(
argument: (
triggers: triggers,
groups: groups,
domain: domain,
categoryFilter: categoryFilter,
orderMostFrequentFirst: orderMostFrequentFirst,
),
from: this,
);
@override
String toString() => r'bangListProvider';
}
@ProviderFor(frequentBangList)
final frequentBangListProvider = FrequentBangListProvider._();
final class FrequentBangListProvider
extends
$FunctionalProvider<
AsyncValue<List<BangData>>,
List<BangData>,
Stream<List<BangData>>
>
with $FutureModifier<List<BangData>>, $StreamProvider<List<BangData>> {
FrequentBangListProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'frequentBangListProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$frequentBangListHash();
@$internal
@override
$StreamProviderElement<List<BangData>> $createElement(
$ProviderPointer pointer,
) => $StreamProviderElement(pointer);
@override
Stream<List<BangData>> create(Ref ref) {
return frequentBangList(ref);
}
}
String _$frequentBangListHash() => r'2c1ecb7e9416772fc1c32d01d767e1eb4f865975';
@ProviderFor(searchHistory)
final searchHistoryProvider = SearchHistoryProvider._();
final class SearchHistoryProvider
extends
$FunctionalProvider<
AsyncValue<List<SearchHistoryEntry>>,
List<SearchHistoryEntry>,
Stream<List<SearchHistoryEntry>>
>
with
$FutureModifier<List<SearchHistoryEntry>>,
$StreamProvider<List<SearchHistoryEntry>> {
SearchHistoryProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'searchHistoryProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$searchHistoryHash();
@$internal
@override
$StreamProviderElement<List<SearchHistoryEntry>> $createElement(
$ProviderPointer pointer,
) => $StreamProviderElement(pointer);
@override
Stream<List<SearchHistoryEntry>> create(Ref ref) {
return searchHistory(ref);
}
}
String _$searchHistoryHash() => r'5f9508a6b286bfcd1b641bd429de46ad052a3dfe';
@ProviderFor(lastSyncOfGroup)
final lastSyncOfGroupProvider = LastSyncOfGroupFamily._();
final class LastSyncOfGroupProvider
extends
$FunctionalProvider<AsyncValue<DateTime?>, DateTime?, Stream<DateTime?>>
with $FutureModifier<DateTime?>, $StreamProvider<DateTime?> {
LastSyncOfGroupProvider._({
required LastSyncOfGroupFamily super.from,
required BangGroup super.argument,
}) : super(
retry: null,
name: r'lastSyncOfGroupProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$lastSyncOfGroupHash();
@override
String toString() {
return r'lastSyncOfGroupProvider'
''
'($argument)';
}
@$internal
@override
$StreamProviderElement<DateTime?> $createElement($ProviderPointer pointer) =>
$StreamProviderElement(pointer);
@override
Stream<DateTime?> create(Ref ref) {
final argument = this.argument as BangGroup;
return lastSyncOfGroup(ref, argument);
}
@override
bool operator ==(Object other) {
return other is LastSyncOfGroupProvider && other.argument == argument;
}
@override
int get hashCode {
return argument.hashCode;
}
}
String _$lastSyncOfGroupHash() => r'23d07f3132ba9bb35a31f74e3a69698d31d4c569';
final class LastSyncOfGroupFamily extends $Family
with $FunctionalFamilyOverride<Stream<DateTime?>, BangGroup> {
LastSyncOfGroupFamily._()
: super(
retry: null,
name: r'lastSyncOfGroupProvider',
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
);
LastSyncOfGroupProvider call(BangGroup group) =>
LastSyncOfGroupProvider._(argument: group, from: this);
@override
String toString() => r'lastSyncOfGroupProvider';
}
@ProviderFor(bangCountOfGroup)
final bangCountOfGroupProvider = BangCountOfGroupFamily._();
final class BangCountOfGroupProvider
extends $FunctionalProvider<AsyncValue<int>, int, Stream<int>>
with $FutureModifier<int>, $StreamProvider<int> {
BangCountOfGroupProvider._({
required BangCountOfGroupFamily super.from,
required BangGroup super.argument,
}) : super(
retry: null,
name: r'bangCountOfGroupProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$bangCountOfGroupHash();
@override
String toString() {
return r'bangCountOfGroupProvider'
''
'($argument)';
}
@$internal
@override
$StreamProviderElement<int> $createElement($ProviderPointer pointer) =>
$StreamProviderElement(pointer);
@override
Stream<int> create(Ref ref) {
final argument = this.argument as BangGroup;
return bangCountOfGroup(ref, argument);
}
@override
bool operator ==(Object other) {
return other is BangCountOfGroupProvider && other.argument == argument;
}
@override
int get hashCode {
return argument.hashCode;
}
}
String _$bangCountOfGroupHash() => r'211ffcd7f49b637a7953f913dc5eafda344423f3';
final class BangCountOfGroupFamily extends $Family
with $FunctionalFamilyOverride<Stream<int>, BangGroup> {
BangCountOfGroupFamily._()
: super(
retry: null,
name: r'bangCountOfGroupProvider',
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
);
BangCountOfGroupProvider call(BangGroup group) =>
BangCountOfGroupProvider._(argument: group, from: this);
@override
String toString() => r'bangCountOfGroupProvider';
}
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2024-2026 Fabian Freund.
*
* This file is part of WebLibre
* (see https://weblibre.eu).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* 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/>.
*/
import 'dart:async';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:weblibre/features/bangs/data/models/bang_data.dart';
import 'package:weblibre/features/bangs/data/providers.dart';
import 'package:weblibre/features/bangs/domain/providers/bangs.dart';
import 'package:weblibre/features/bangs/domain/repositories/data.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
part 'search.g.dart';
@Riverpod()
class BangSearch extends _$BangSearch {
late StreamController<List<BangData>> _streamController;
Future<Uri> triggerBangSearch(BangData bang, String searchQuery) async {
final bangDataNotifier = ref.read(bangDataRepositoryProvider.notifier);
final settings = ref.read(generalSettingsWithDefaultsProvider);
await bangDataNotifier.increaseFrequency(bang.toKey());
await bangDataNotifier.addSearchEntry(
bang.group,
bang.trigger,
searchQuery,
maxEntryCount: settings.maxSearchHistoryEntries,
);
return bang.getTemplateUrl(searchQuery);
}
Future<void> search(String input) async {
if (input.isNotEmpty) {
await ref.read(bangDatabaseProvider).bangDao.queryBangs(input).get().then(
(value) {
if (!_streamController.isClosed) {
_streamController.add(value);
}
},
);
}
}
@override
Stream<List<BangData>> build() {
_streamController = StreamController();
// Emit initial empty list so UI doesn't show loading state
_streamController.add([]);
ref.onDispose(() async {
await _streamController.close();
});
return _streamController.stream;
}
}
@Riverpod()
class SeamlessBang extends _$SeamlessBang {
bool _hasSearch = false;
void search(String input) {
if (input.isNotEmpty) {
if (!_hasSearch) {
_hasSearch = true;
ref.invalidateSelf();
}
//Don't block
unawaited(ref.read(bangSearchProvider.notifier).search(input));
} else if (_hasSearch) {
_hasSearch = false;
ref.invalidateSelf();
}
}
@override
AsyncValue<List<BangData>> build() {
return _hasSearch
? ref.watch(bangSearchProvider)
: ref.watch(frequentBangListProvider);
}
}
@@ -0,0 +1,111 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'search.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(BangSearch)
final bangSearchProvider = BangSearchProvider._();
final class BangSearchProvider
extends $StreamNotifierProvider<BangSearch, List<BangData>> {
BangSearchProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'bangSearchProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$bangSearchHash();
@$internal
@override
BangSearch create() => BangSearch();
}
String _$bangSearchHash() => r'feed24edfe703b0697f4a855be9c7359c456b0f2';
abstract class _$BangSearch extends $StreamNotifier<List<BangData>> {
Stream<List<BangData>> build();
@$mustCallSuper
@override
void runBuild() {
final ref = this.ref as $Ref<AsyncValue<List<BangData>>, List<BangData>>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<AsyncValue<List<BangData>>, List<BangData>>,
AsyncValue<List<BangData>>,
Object?,
Object?
>;
element.handleCreate(ref, build);
}
}
@ProviderFor(SeamlessBang)
final seamlessBangProvider = SeamlessBangProvider._();
final class SeamlessBangProvider
extends $NotifierProvider<SeamlessBang, AsyncValue<List<BangData>>> {
SeamlessBangProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'seamlessBangProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$seamlessBangHash();
@$internal
@override
SeamlessBang create() => SeamlessBang();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(AsyncValue<List<BangData>> value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<AsyncValue<List<BangData>>>(value),
);
}
}
String _$seamlessBangHash() => r'8bd7a2cbe4c302ae08f85167290666a7437f8b9b';
abstract class _$SeamlessBang extends $Notifier<AsyncValue<List<BangData>>> {
AsyncValue<List<BangData>> build();
@$mustCallSuper
@override
void runBuild() {
final ref =
this.ref
as $Ref<AsyncValue<List<BangData>>, AsyncValue<List<BangData>>>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<
AsyncValue<List<BangData>>,
AsyncValue<List<BangData>>
>,
AsyncValue<List<BangData>>,
Object?,
Object?
>;
element.handleCreate(ref, build);
}
}