intermediate
This commit is contained in:
@@ -94,6 +94,27 @@ class BangDao extends DatabaseAccessor<BangDatabase> with _$BangDaoMixin {
|
||||
return db.bangQuery(query: db.buildFtsQuery(searchString));
|
||||
}
|
||||
|
||||
Future<int> addSearchEntry(String trigger, String searchQuery) {
|
||||
return db.bangHistory.insertOne(
|
||||
BangHistoryCompanion.insert(
|
||||
searchQuery: searchQuery,
|
||||
trigger: trigger,
|
||||
searchDate: DateTime.now(),
|
||||
),
|
||||
onConflict: DoUpdate(
|
||||
target: [db.bangHistory.searchQuery],
|
||||
(old) => BangHistoryCompanion.custom(
|
||||
trigger: Variable(trigger),
|
||||
searchDate: Variable(DateTime.now()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> removeSearchEntry(String searchQuery) {
|
||||
return db.bangHistory.deleteWhere((t) => t.searchQuery.equals(searchQuery));
|
||||
}
|
||||
|
||||
// Future<int> upsertBangIcon(String trigger, BrowserIcon icon) async {
|
||||
// //TODO: swithc to WEBP in future, requires 3rd party
|
||||
// final compressed = await icon.image.toByteData(format: ImageByteFormat.png);
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:lensai/features/bangs/data/database/daos/sync.dart';
|
||||
import 'package:lensai/features/bangs/data/database/drift/converters/bang_format.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/search/domain/fts_tokenizer.dart';
|
||||
|
||||
part 'database.g.dart';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:lensai/features/bangs/data/database/drift/converters/bang_format.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang.dart';
|
||||
import 'package:lensai/features/bangs/data/models/search_history_entry.dart';
|
||||
|
||||
CREATE TABLE bang (
|
||||
"trigger" TEXT PRIMARY KEY NOT NULL,
|
||||
@@ -24,10 +25,10 @@ CREATE TABLE bang_frequency (
|
||||
last_used DATETIME NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE bang_icon (
|
||||
"trigger" TEXT PRIMARY KEY NOT NULL REFERENCES bang ("trigger") ON DELETE CASCADE,
|
||||
icon_data BLOB NOT NULL,
|
||||
fetch_date DATETIME NOT NULL
|
||||
CREATE TABLE bang_history (
|
||||
search_query TEXT UNIQUE NOT NULL,
|
||||
"trigger" TEXT NOT NULL REFERENCES bang ("trigger"),
|
||||
search_date DATETIME NOT NULL
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE bang_fts
|
||||
@@ -42,14 +43,11 @@ CREATE VIEW bang_data_view WITH BangData AS
|
||||
SELECT
|
||||
b.*,
|
||||
bf.frequency,
|
||||
bf.last_used,
|
||||
bi.icon_data
|
||||
bf.last_used
|
||||
FROM
|
||||
bang b
|
||||
LEFT JOIN
|
||||
bang_frequency bf ON b."trigger" = bf."trigger"
|
||||
LEFT JOIN
|
||||
bang_icon bi ON b."trigger" = bi."trigger";
|
||||
bang_frequency bf ON b."trigger" = bf."trigger";
|
||||
|
||||
-- Triggers to keep the FTS index up to date.
|
||||
CREATE TRIGGER bang_after_insert AFTER INSERT ON bang BEGIN
|
||||
@@ -78,16 +76,13 @@ bangQuery WITH BangData:
|
||||
SELECT
|
||||
b.*,
|
||||
bf.frequency,
|
||||
bf.last_used,
|
||||
bi.icon_data
|
||||
bf.last_used
|
||||
FROM
|
||||
bang_fts(:query) fts
|
||||
INNER JOIN
|
||||
bang b ON b.rowid = fts.rowid
|
||||
LEFT JOIN
|
||||
bang_frequency bf ON b."trigger" = bf."trigger"
|
||||
LEFT JOIN
|
||||
bang_icon bi ON b."trigger" = bi."trigger"
|
||||
ORDER BY
|
||||
RANK,
|
||||
bf.frequency NULLS LAST;
|
||||
@@ -113,4 +108,19 @@ categoriesJson:
|
||||
c.category,
|
||||
json(c.sub_categories)
|
||||
) AS categories_json
|
||||
FROM categories c;
|
||||
FROM categories c;
|
||||
|
||||
searchHistoryEntries WITH SearchHistoryEntry:
|
||||
SELECT *
|
||||
FROM bang_history
|
||||
ORDER BY search_date DESC
|
||||
LIMIT :limit;
|
||||
|
||||
evictHistoryEntries:
|
||||
DELETE FROM bang_history
|
||||
WHERE rowid IN (
|
||||
SELECT rowid
|
||||
FROM bang_history
|
||||
ORDER BY search_date DESC
|
||||
LIMIT -1 OFFSET :limit
|
||||
);
|
||||
@@ -599,171 +599,173 @@ class BangFrequencyCompanion extends UpdateCompanion<BangFrequencyData> {
|
||||
}
|
||||
}
|
||||
|
||||
class BangIcon extends Table with TableInfo<BangIcon, BangIconData> {
|
||||
class BangHistory extends Table with TableInfo<BangHistory, BangHistoryData> {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
BangIcon(this.attachedDatabase, [this._alias]);
|
||||
BangHistory(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> searchQuery = GeneratedColumn<String>(
|
||||
'search_query', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'UNIQUE NOT NULL');
|
||||
late final GeneratedColumn<String> trigger = GeneratedColumn<String>(
|
||||
'trigger', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints:
|
||||
'PRIMARY KEY NOT NULL REFERENCES bang("trigger")ON DELETE CASCADE');
|
||||
late final GeneratedColumn<Uint8List> iconData = GeneratedColumn<Uint8List>(
|
||||
'icon_data', aliasedName, false,
|
||||
type: DriftSqlType.blob,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<DateTime> fetchDate = GeneratedColumn<DateTime>(
|
||||
'fetch_date', aliasedName, false,
|
||||
$customConstraints: 'NOT NULL REFERENCES bang("trigger")');
|
||||
late final GeneratedColumn<DateTime> searchDate = GeneratedColumn<DateTime>(
|
||||
'search_date', aliasedName, false,
|
||||
type: DriftSqlType.dateTime,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [trigger, iconData, fetchDate];
|
||||
List<GeneratedColumn> get $columns => [searchQuery, trigger, searchDate];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'bang_icon';
|
||||
static const String $name = 'bang_history';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {trigger};
|
||||
Set<GeneratedColumn> get $primaryKey => const {};
|
||||
@override
|
||||
BangIconData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
BangHistoryData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return BangIconData(
|
||||
return BangHistoryData(
|
||||
searchQuery: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}search_query'])!,
|
||||
trigger: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}trigger'])!,
|
||||
iconData: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.blob, data['${effectivePrefix}icon_data'])!,
|
||||
fetchDate: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.dateTime, data['${effectivePrefix}fetch_date'])!,
|
||||
searchDate: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.dateTime, data['${effectivePrefix}search_date'])!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
BangIcon createAlias(String alias) {
|
||||
return BangIcon(attachedDatabase, alias);
|
||||
BangHistory createAlias(String alias) {
|
||||
return BangHistory(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class BangIconData extends DataClass implements Insertable<BangIconData> {
|
||||
class BangHistoryData extends DataClass implements Insertable<BangHistoryData> {
|
||||
final String searchQuery;
|
||||
final String trigger;
|
||||
final Uint8List iconData;
|
||||
final DateTime fetchDate;
|
||||
const BangIconData(
|
||||
{required this.trigger, required this.iconData, required this.fetchDate});
|
||||
final DateTime searchDate;
|
||||
const BangHistoryData(
|
||||
{required this.searchQuery,
|
||||
required this.trigger,
|
||||
required this.searchDate});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['search_query'] = Variable<String>(searchQuery);
|
||||
map['trigger'] = Variable<String>(trigger);
|
||||
map['icon_data'] = Variable<Uint8List>(iconData);
|
||||
map['fetch_date'] = Variable<DateTime>(fetchDate);
|
||||
map['search_date'] = Variable<DateTime>(searchDate);
|
||||
return map;
|
||||
}
|
||||
|
||||
factory BangIconData.fromJson(Map<String, dynamic> json,
|
||||
factory BangHistoryData.fromJson(Map<String, dynamic> json,
|
||||
{ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return BangIconData(
|
||||
return BangHistoryData(
|
||||
searchQuery: serializer.fromJson<String>(json['search_query']),
|
||||
trigger: serializer.fromJson<String>(json['trigger']),
|
||||
iconData: serializer.fromJson<Uint8List>(json['icon_data']),
|
||||
fetchDate: serializer.fromJson<DateTime>(json['fetch_date']),
|
||||
searchDate: serializer.fromJson<DateTime>(json['search_date']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'search_query': serializer.toJson<String>(searchQuery),
|
||||
'trigger': serializer.toJson<String>(trigger),
|
||||
'icon_data': serializer.toJson<Uint8List>(iconData),
|
||||
'fetch_date': serializer.toJson<DateTime>(fetchDate),
|
||||
'search_date': serializer.toJson<DateTime>(searchDate),
|
||||
};
|
||||
}
|
||||
|
||||
BangIconData copyWith(
|
||||
{String? trigger, Uint8List? iconData, DateTime? fetchDate}) =>
|
||||
BangIconData(
|
||||
BangHistoryData copyWith(
|
||||
{String? searchQuery, String? trigger, DateTime? searchDate}) =>
|
||||
BangHistoryData(
|
||||
searchQuery: searchQuery ?? this.searchQuery,
|
||||
trigger: trigger ?? this.trigger,
|
||||
iconData: iconData ?? this.iconData,
|
||||
fetchDate: fetchDate ?? this.fetchDate,
|
||||
searchDate: searchDate ?? this.searchDate,
|
||||
);
|
||||
BangIconData copyWithCompanion(BangIconCompanion data) {
|
||||
return BangIconData(
|
||||
BangHistoryData copyWithCompanion(BangHistoryCompanion data) {
|
||||
return BangHistoryData(
|
||||
searchQuery:
|
||||
data.searchQuery.present ? data.searchQuery.value : this.searchQuery,
|
||||
trigger: data.trigger.present ? data.trigger.value : this.trigger,
|
||||
iconData: data.iconData.present ? data.iconData.value : this.iconData,
|
||||
fetchDate: data.fetchDate.present ? data.fetchDate.value : this.fetchDate,
|
||||
searchDate:
|
||||
data.searchDate.present ? data.searchDate.value : this.searchDate,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('BangIconData(')
|
||||
return (StringBuffer('BangHistoryData(')
|
||||
..write('searchQuery: $searchQuery, ')
|
||||
..write('trigger: $trigger, ')
|
||||
..write('iconData: $iconData, ')
|
||||
..write('fetchDate: $fetchDate')
|
||||
..write('searchDate: $searchDate')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(trigger, $driftBlobEquality.hash(iconData), fetchDate);
|
||||
int get hashCode => Object.hash(searchQuery, trigger, searchDate);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is BangIconData &&
|
||||
(other is BangHistoryData &&
|
||||
other.searchQuery == this.searchQuery &&
|
||||
other.trigger == this.trigger &&
|
||||
$driftBlobEquality.equals(other.iconData, this.iconData) &&
|
||||
other.fetchDate == this.fetchDate);
|
||||
other.searchDate == this.searchDate);
|
||||
}
|
||||
|
||||
class BangIconCompanion extends UpdateCompanion<BangIconData> {
|
||||
class BangHistoryCompanion extends UpdateCompanion<BangHistoryData> {
|
||||
final Value<String> searchQuery;
|
||||
final Value<String> trigger;
|
||||
final Value<Uint8List> iconData;
|
||||
final Value<DateTime> fetchDate;
|
||||
final Value<DateTime> searchDate;
|
||||
final Value<int> rowid;
|
||||
const BangIconCompanion({
|
||||
const BangHistoryCompanion({
|
||||
this.searchQuery = const Value.absent(),
|
||||
this.trigger = const Value.absent(),
|
||||
this.iconData = const Value.absent(),
|
||||
this.fetchDate = const Value.absent(),
|
||||
this.searchDate = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
});
|
||||
BangIconCompanion.insert({
|
||||
BangHistoryCompanion.insert({
|
||||
required String searchQuery,
|
||||
required String trigger,
|
||||
required Uint8List iconData,
|
||||
required DateTime fetchDate,
|
||||
required DateTime searchDate,
|
||||
this.rowid = const Value.absent(),
|
||||
}) : trigger = Value(trigger),
|
||||
iconData = Value(iconData),
|
||||
fetchDate = Value(fetchDate);
|
||||
static Insertable<BangIconData> custom({
|
||||
}) : searchQuery = Value(searchQuery),
|
||||
trigger = Value(trigger),
|
||||
searchDate = Value(searchDate);
|
||||
static Insertable<BangHistoryData> custom({
|
||||
Expression<String>? searchQuery,
|
||||
Expression<String>? trigger,
|
||||
Expression<Uint8List>? iconData,
|
||||
Expression<DateTime>? fetchDate,
|
||||
Expression<DateTime>? searchDate,
|
||||
Expression<int>? rowid,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (searchQuery != null) 'search_query': searchQuery,
|
||||
if (trigger != null) 'trigger': trigger,
|
||||
if (iconData != null) 'icon_data': iconData,
|
||||
if (fetchDate != null) 'fetch_date': fetchDate,
|
||||
if (searchDate != null) 'search_date': searchDate,
|
||||
if (rowid != null) 'rowid': rowid,
|
||||
});
|
||||
}
|
||||
|
||||
BangIconCompanion copyWith(
|
||||
{Value<String>? trigger,
|
||||
Value<Uint8List>? iconData,
|
||||
Value<DateTime>? fetchDate,
|
||||
BangHistoryCompanion copyWith(
|
||||
{Value<String>? searchQuery,
|
||||
Value<String>? trigger,
|
||||
Value<DateTime>? searchDate,
|
||||
Value<int>? rowid}) {
|
||||
return BangIconCompanion(
|
||||
return BangHistoryCompanion(
|
||||
searchQuery: searchQuery ?? this.searchQuery,
|
||||
trigger: trigger ?? this.trigger,
|
||||
iconData: iconData ?? this.iconData,
|
||||
fetchDate: fetchDate ?? this.fetchDate,
|
||||
searchDate: searchDate ?? this.searchDate,
|
||||
rowid: rowid ?? this.rowid,
|
||||
);
|
||||
}
|
||||
@@ -771,14 +773,14 @@ class BangIconCompanion extends UpdateCompanion<BangIconData> {
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (searchQuery.present) {
|
||||
map['search_query'] = Variable<String>(searchQuery.value);
|
||||
}
|
||||
if (trigger.present) {
|
||||
map['trigger'] = Variable<String>(trigger.value);
|
||||
}
|
||||
if (iconData.present) {
|
||||
map['icon_data'] = Variable<Uint8List>(iconData.value);
|
||||
}
|
||||
if (fetchDate.present) {
|
||||
map['fetch_date'] = Variable<DateTime>(fetchDate.value);
|
||||
if (searchDate.present) {
|
||||
map['search_date'] = Variable<DateTime>(searchDate.value);
|
||||
}
|
||||
if (rowid.present) {
|
||||
map['rowid'] = Variable<int>(rowid.value);
|
||||
@@ -788,10 +790,10 @@ class BangIconCompanion extends UpdateCompanion<BangIconData> {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('BangIconCompanion(')
|
||||
return (StringBuffer('BangHistoryCompanion(')
|
||||
..write('searchQuery: $searchQuery, ')
|
||||
..write('trigger: $trigger, ')
|
||||
..write('iconData: $iconData, ')
|
||||
..write('fetchDate: $fetchDate, ')
|
||||
..write('searchDate: $searchDate, ')
|
||||
..write('rowid: $rowid')
|
||||
..write(')'))
|
||||
.toString();
|
||||
@@ -985,8 +987,7 @@ class BangDataView extends ViewInfo<BangDataView, BangData>
|
||||
subCategory,
|
||||
format,
|
||||
frequency,
|
||||
lastUsed,
|
||||
iconData
|
||||
lastUsed
|
||||
];
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
@@ -995,7 +996,7 @@ class BangDataView extends ViewInfo<BangDataView, BangData>
|
||||
@override
|
||||
Map<SqlDialect, String> get createViewStatements => {
|
||||
SqlDialect.sqlite:
|
||||
'CREATE VIEW bang_data_view AS SELECT b.*, bf.frequency, bf.last_used, bi.icon_data FROM bang AS b LEFT JOIN bang_frequency AS bf ON b."trigger" = bf."trigger" LEFT JOIN bang_icon AS bi ON b."trigger" = bi."trigger"',
|
||||
'CREATE VIEW bang_data_view AS SELECT b.*, bf.frequency, bf.last_used FROM bang AS b LEFT JOIN bang_frequency AS bf ON b."trigger" = bf."trigger"',
|
||||
};
|
||||
@override
|
||||
BangDataView get asDslTable => this;
|
||||
@@ -1055,9 +1056,6 @@ class BangDataView extends ViewInfo<BangDataView, BangData>
|
||||
late final GeneratedColumn<DateTime> lastUsed = GeneratedColumn<DateTime>(
|
||||
'last_used', aliasedName, true,
|
||||
type: DriftSqlType.dateTime);
|
||||
late final GeneratedColumn<Uint8List> iconData = GeneratedColumn<Uint8List>(
|
||||
'icon_data', aliasedName, true,
|
||||
type: DriftSqlType.blob);
|
||||
@override
|
||||
BangDataView createAlias(String alias) {
|
||||
return BangDataView(attachedDatabase, alias);
|
||||
@@ -1066,7 +1064,7 @@ class BangDataView extends ViewInfo<BangDataView, BangData>
|
||||
@override
|
||||
Query? get query => null;
|
||||
@override
|
||||
Set<String> get readTables => const {'bang', 'bang_frequency', 'bang_icon'};
|
||||
Set<String> get readTables => const {'bang', 'bang_frequency'};
|
||||
}
|
||||
|
||||
abstract class _$BangDatabase extends GeneratedDatabase {
|
||||
@@ -1075,7 +1073,7 @@ abstract class _$BangDatabase extends GeneratedDatabase {
|
||||
late final BangTable bang = BangTable(this);
|
||||
late final BangSync bangSync = BangSync(this);
|
||||
late final BangFrequency bangFrequency = BangFrequency(this);
|
||||
late final BangIcon bangIcon = BangIcon(this);
|
||||
late final BangHistory bangHistory = BangHistory(this);
|
||||
late final BangFts bangFts = BangFts(this);
|
||||
late final BangDataView bangDataView = BangDataView(this);
|
||||
late final Trigger bangAfterInsert = Trigger(
|
||||
@@ -1099,13 +1097,12 @@ abstract class _$BangDatabase extends GeneratedDatabase {
|
||||
|
||||
Selectable<BangData> bangQuery({required String query}) {
|
||||
return customSelect(
|
||||
'SELECT b.*, bf.frequency, bf.last_used, bi.icon_data FROM bang_fts(?1)AS fts INNER JOIN bang AS b ON b."rowid" = fts."rowid" LEFT JOIN bang_frequency AS bf ON b."trigger" = bf."trigger" LEFT JOIN bang_icon AS bi ON b."trigger" = bi."trigger" ORDER BY RANK, bf.frequency NULLS LAST',
|
||||
'SELECT b.*, bf.frequency, bf.last_used FROM bang_fts(?1)AS fts INNER JOIN bang AS b ON b."rowid" = fts."rowid" LEFT JOIN bang_frequency AS bf ON b."trigger" = bf."trigger" ORDER BY RANK, bf.frequency NULLS LAST',
|
||||
variables: [
|
||||
Variable<String>(query)
|
||||
],
|
||||
readsFrom: {
|
||||
bangFrequency,
|
||||
bangIcon,
|
||||
bang,
|
||||
bangFts,
|
||||
}).map((QueryRow row) => BangData(
|
||||
@@ -1131,6 +1128,30 @@ abstract class _$BangDatabase extends GeneratedDatabase {
|
||||
}).map((QueryRow row) => row.read<String>('categories_json'));
|
||||
}
|
||||
|
||||
Selectable<SearchHistoryEntry> searchHistoryEntries({required int limit}) {
|
||||
return customSelect(
|
||||
'SELECT * FROM bang_history ORDER BY search_date DESC LIMIT ?1',
|
||||
variables: [
|
||||
Variable<int>(limit)
|
||||
],
|
||||
readsFrom: {
|
||||
bangHistory,
|
||||
}).map((QueryRow row) => SearchHistoryEntry(
|
||||
searchQuery: row.read<String>('search_query'),
|
||||
trigger: row.read<String>('trigger'),
|
||||
searchDate: row.read<DateTime>('search_date'),
|
||||
));
|
||||
}
|
||||
|
||||
Future<int> evictHistoryEntries({required int limit}) {
|
||||
return customUpdate(
|
||||
'DELETE FROM bang_history WHERE "rowid" IN (SELECT "rowid" FROM bang_history ORDER BY search_date DESC LIMIT -1 OFFSET ?1)',
|
||||
variables: [Variable<int>(limit)],
|
||||
updates: {bangHistory},
|
||||
updateKind: UpdateKind.delete,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@@ -1139,7 +1160,7 @@ abstract class _$BangDatabase extends GeneratedDatabase {
|
||||
bang,
|
||||
bangSync,
|
||||
bangFrequency,
|
||||
bangIcon,
|
||||
bangHistory,
|
||||
bangFts,
|
||||
bangDataView,
|
||||
bangAfterInsert,
|
||||
@@ -1156,13 +1177,6 @@ abstract class _$BangDatabase extends GeneratedDatabase {
|
||||
TableUpdate('bang_frequency', kind: UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
WritePropagation(
|
||||
on: TableUpdateQuery.onTableName('bang',
|
||||
limitUpdateKind: UpdateKind.delete),
|
||||
result: [
|
||||
TableUpdate('bang_icon', kind: UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
WritePropagation(
|
||||
on: TableUpdateQuery.onTableName('bang',
|
||||
limitUpdateKind: UpdateKind.insert),
|
||||
@@ -1230,17 +1244,17 @@ final class $BangTableReferences
|
||||
manager.$state.copyWith(prefetchedData: cache));
|
||||
}
|
||||
|
||||
static MultiTypedResultKey<BangIcon, List<BangIconData>> _bangIconRefsTable(
|
||||
_$BangDatabase db) =>
|
||||
MultiTypedResultKey.fromTable(db.bangIcon,
|
||||
static MultiTypedResultKey<BangHistory, List<BangHistoryData>>
|
||||
_bangHistoryRefsTable(_$BangDatabase db) => MultiTypedResultKey.fromTable(
|
||||
db.bangHistory,
|
||||
aliasName:
|
||||
$_aliasNameGenerator(db.bang.trigger, db.bangIcon.trigger));
|
||||
$_aliasNameGenerator(db.bang.trigger, db.bangHistory.trigger));
|
||||
|
||||
$BangIconProcessedTableManager get bangIconRefs {
|
||||
final manager = $BangIconTableManager($_db, $_db.bangIcon)
|
||||
$BangHistoryProcessedTableManager get bangHistoryRefs {
|
||||
final manager = $BangHistoryTableManager($_db, $_db.bangHistory)
|
||||
.filter((f) => f.trigger.trigger($_item.trigger));
|
||||
|
||||
final cache = $_typedResult.readTableOrNull(_bangIconRefsTable($_db));
|
||||
final cache = $_typedResult.readTableOrNull(_bangHistoryRefsTable($_db));
|
||||
return ProcessedTableManager(
|
||||
manager.$state.copyWith(prefetchedData: cache));
|
||||
}
|
||||
@@ -1303,19 +1317,19 @@ class $BangTableFilterComposer extends Composer<_$BangDatabase, BangTable> {
|
||||
return f(composer);
|
||||
}
|
||||
|
||||
Expression<bool> bangIconRefs(
|
||||
Expression<bool> Function($BangIconFilterComposer f) f) {
|
||||
final $BangIconFilterComposer composer = $composerBuilder(
|
||||
Expression<bool> bangHistoryRefs(
|
||||
Expression<bool> Function($BangHistoryFilterComposer f) f) {
|
||||
final $BangHistoryFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $db.bangIcon,
|
||||
referencedTable: $db.bangHistory,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangIconFilterComposer(
|
||||
$BangHistoryFilterComposer(
|
||||
$db: $db,
|
||||
$table: $db.bangIcon,
|
||||
$table: $db.bangHistory,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
@@ -1411,19 +1425,19 @@ class $BangTableAnnotationComposer extends Composer<_$BangDatabase, BangTable> {
|
||||
return f(composer);
|
||||
}
|
||||
|
||||
Expression<T> bangIconRefs<T extends Object>(
|
||||
Expression<T> Function($BangIconAnnotationComposer a) f) {
|
||||
final $BangIconAnnotationComposer composer = $composerBuilder(
|
||||
Expression<T> bangHistoryRefs<T extends Object>(
|
||||
Expression<T> Function($BangHistoryAnnotationComposer a) f) {
|
||||
final $BangHistoryAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $db.bangIcon,
|
||||
referencedTable: $db.bangHistory,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangIconAnnotationComposer(
|
||||
$BangHistoryAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: $db.bangIcon,
|
||||
$table: $db.bangHistory,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
@@ -1444,7 +1458,7 @@ class $BangTableTableManager extends RootTableManager<
|
||||
$BangTableUpdateCompanionBuilder,
|
||||
(Bang, $BangTableReferences),
|
||||
Bang,
|
||||
PrefetchHooks Function({bool bangFrequencyRefs, bool bangIconRefs})> {
|
||||
PrefetchHooks Function({bool bangFrequencyRefs, bool bangHistoryRefs})> {
|
||||
$BangTableTableManager(_$BangDatabase db, BangTable table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
@@ -1504,12 +1518,12 @@ class $BangTableTableManager extends RootTableManager<
|
||||
(e.readTable(table), $BangTableReferences(db, table, e)))
|
||||
.toList(),
|
||||
prefetchHooksCallback: (
|
||||
{bangFrequencyRefs = false, bangIconRefs = false}) {
|
||||
{bangFrequencyRefs = false, bangHistoryRefs = false}) {
|
||||
return PrefetchHooks(
|
||||
db: db,
|
||||
explicitlyWatchedTables: [
|
||||
if (bangFrequencyRefs) db.bangFrequency,
|
||||
if (bangIconRefs) db.bangIcon
|
||||
if (bangHistoryRefs) db.bangHistory
|
||||
],
|
||||
addJoins: null,
|
||||
getPrefetchedDataCallback: (items) async {
|
||||
@@ -1526,13 +1540,13 @@ class $BangTableTableManager extends RootTableManager<
|
||||
(item, referencedItems) => referencedItems
|
||||
.where((e) => e.trigger == item.trigger),
|
||||
typedResults: items),
|
||||
if (bangIconRefs)
|
||||
if (bangHistoryRefs)
|
||||
await $_getPrefetchedData(
|
||||
currentTable: table,
|
||||
referencedTable:
|
||||
$BangTableReferences._bangIconRefsTable(db),
|
||||
$BangTableReferences._bangHistoryRefsTable(db),
|
||||
managerFromTypedResult: (p0) =>
|
||||
$BangTableReferences(db, table, p0).bangIconRefs,
|
||||
$BangTableReferences(db, table, p0).bangHistoryRefs,
|
||||
referencedItemsForCurrentItem:
|
||||
(item, referencedItems) => referencedItems
|
||||
.where((e) => e.trigger == item.trigger),
|
||||
@@ -1555,7 +1569,7 @@ typedef $BangTableProcessedTableManager = ProcessedTableManager<
|
||||
$BangTableUpdateCompanionBuilder,
|
||||
(Bang, $BangTableReferences),
|
||||
Bang,
|
||||
PrefetchHooks Function({bool bangFrequencyRefs, bool bangIconRefs})>;
|
||||
PrefetchHooks Function({bool bangFrequencyRefs, bool bangHistoryRefs})>;
|
||||
typedef $BangSyncCreateCompanionBuilder = BangSyncCompanion Function({
|
||||
Value<BangGroup> group,
|
||||
required DateTime lastSync,
|
||||
@@ -1906,25 +1920,25 @@ typedef $BangFrequencyProcessedTableManager = ProcessedTableManager<
|
||||
(BangFrequencyData, $BangFrequencyReferences),
|
||||
BangFrequencyData,
|
||||
PrefetchHooks Function({bool trigger})>;
|
||||
typedef $BangIconCreateCompanionBuilder = BangIconCompanion Function({
|
||||
typedef $BangHistoryCreateCompanionBuilder = BangHistoryCompanion Function({
|
||||
required String searchQuery,
|
||||
required String trigger,
|
||||
required Uint8List iconData,
|
||||
required DateTime fetchDate,
|
||||
required DateTime searchDate,
|
||||
Value<int> rowid,
|
||||
});
|
||||
typedef $BangIconUpdateCompanionBuilder = BangIconCompanion Function({
|
||||
typedef $BangHistoryUpdateCompanionBuilder = BangHistoryCompanion Function({
|
||||
Value<String> searchQuery,
|
||||
Value<String> trigger,
|
||||
Value<Uint8List> iconData,
|
||||
Value<DateTime> fetchDate,
|
||||
Value<DateTime> searchDate,
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
final class $BangIconReferences
|
||||
extends BaseReferences<_$BangDatabase, BangIcon, BangIconData> {
|
||||
$BangIconReferences(super.$_db, super.$_table, super.$_typedResult);
|
||||
final class $BangHistoryReferences
|
||||
extends BaseReferences<_$BangDatabase, BangHistory, BangHistoryData> {
|
||||
$BangHistoryReferences(super.$_db, super.$_table, super.$_typedResult);
|
||||
|
||||
static BangTable _triggerTable(_$BangDatabase db) => db.bang
|
||||
.createAlias($_aliasNameGenerator(db.bangIcon.trigger, db.bang.trigger));
|
||||
static BangTable _triggerTable(_$BangDatabase db) => db.bang.createAlias(
|
||||
$_aliasNameGenerator(db.bangHistory.trigger, db.bang.trigger));
|
||||
|
||||
$BangTableProcessedTableManager get trigger {
|
||||
final manager = $BangTableTableManager($_db, $_db.bang)
|
||||
@@ -1936,19 +1950,19 @@ final class $BangIconReferences
|
||||
}
|
||||
}
|
||||
|
||||
class $BangIconFilterComposer extends Composer<_$BangDatabase, BangIcon> {
|
||||
$BangIconFilterComposer({
|
||||
class $BangHistoryFilterComposer extends Composer<_$BangDatabase, BangHistory> {
|
||||
$BangHistoryFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<Uint8List> get iconData => $composableBuilder(
|
||||
column: $table.iconData, builder: (column) => ColumnFilters(column));
|
||||
ColumnFilters<String> get searchQuery => $composableBuilder(
|
||||
column: $table.searchQuery, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<DateTime> get fetchDate => $composableBuilder(
|
||||
column: $table.fetchDate, builder: (column) => ColumnFilters(column));
|
||||
ColumnFilters<DateTime> get searchDate => $composableBuilder(
|
||||
column: $table.searchDate, builder: (column) => ColumnFilters(column));
|
||||
|
||||
$BangTableFilterComposer get trigger {
|
||||
final $BangTableFilterComposer composer = $composerBuilder(
|
||||
@@ -1971,19 +1985,20 @@ class $BangIconFilterComposer extends Composer<_$BangDatabase, BangIcon> {
|
||||
}
|
||||
}
|
||||
|
||||
class $BangIconOrderingComposer extends Composer<_$BangDatabase, BangIcon> {
|
||||
$BangIconOrderingComposer({
|
||||
class $BangHistoryOrderingComposer
|
||||
extends Composer<_$BangDatabase, BangHistory> {
|
||||
$BangHistoryOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<Uint8List> get iconData => $composableBuilder(
|
||||
column: $table.iconData, builder: (column) => ColumnOrderings(column));
|
||||
ColumnOrderings<String> get searchQuery => $composableBuilder(
|
||||
column: $table.searchQuery, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<DateTime> get fetchDate => $composableBuilder(
|
||||
column: $table.fetchDate, builder: (column) => ColumnOrderings(column));
|
||||
ColumnOrderings<DateTime> get searchDate => $composableBuilder(
|
||||
column: $table.searchDate, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
$BangTableOrderingComposer get trigger {
|
||||
final $BangTableOrderingComposer composer = $composerBuilder(
|
||||
@@ -2006,19 +2021,20 @@ class $BangIconOrderingComposer extends Composer<_$BangDatabase, BangIcon> {
|
||||
}
|
||||
}
|
||||
|
||||
class $BangIconAnnotationComposer extends Composer<_$BangDatabase, BangIcon> {
|
||||
$BangIconAnnotationComposer({
|
||||
class $BangHistoryAnnotationComposer
|
||||
extends Composer<_$BangDatabase, BangHistory> {
|
||||
$BangHistoryAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<Uint8List> get iconData =>
|
||||
$composableBuilder(column: $table.iconData, builder: (column) => column);
|
||||
GeneratedColumn<String> get searchQuery => $composableBuilder(
|
||||
column: $table.searchQuery, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<DateTime> get fetchDate =>
|
||||
$composableBuilder(column: $table.fetchDate, builder: (column) => column);
|
||||
GeneratedColumn<DateTime> get searchDate => $composableBuilder(
|
||||
column: $table.searchDate, builder: (column) => column);
|
||||
|
||||
$BangTableAnnotationComposer get trigger {
|
||||
final $BangTableAnnotationComposer composer = $composerBuilder(
|
||||
@@ -2041,55 +2057,55 @@ class $BangIconAnnotationComposer extends Composer<_$BangDatabase, BangIcon> {
|
||||
}
|
||||
}
|
||||
|
||||
class $BangIconTableManager extends RootTableManager<
|
||||
class $BangHistoryTableManager extends RootTableManager<
|
||||
_$BangDatabase,
|
||||
BangIcon,
|
||||
BangIconData,
|
||||
$BangIconFilterComposer,
|
||||
$BangIconOrderingComposer,
|
||||
$BangIconAnnotationComposer,
|
||||
$BangIconCreateCompanionBuilder,
|
||||
$BangIconUpdateCompanionBuilder,
|
||||
(BangIconData, $BangIconReferences),
|
||||
BangIconData,
|
||||
BangHistory,
|
||||
BangHistoryData,
|
||||
$BangHistoryFilterComposer,
|
||||
$BangHistoryOrderingComposer,
|
||||
$BangHistoryAnnotationComposer,
|
||||
$BangHistoryCreateCompanionBuilder,
|
||||
$BangHistoryUpdateCompanionBuilder,
|
||||
(BangHistoryData, $BangHistoryReferences),
|
||||
BangHistoryData,
|
||||
PrefetchHooks Function({bool trigger})> {
|
||||
$BangIconTableManager(_$BangDatabase db, BangIcon table)
|
||||
$BangHistoryTableManager(_$BangDatabase db, BangHistory table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
createFilteringComposer: () =>
|
||||
$BangIconFilterComposer($db: db, $table: table),
|
||||
$BangHistoryFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$BangIconOrderingComposer($db: db, $table: table),
|
||||
$BangHistoryOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$BangIconAnnotationComposer($db: db, $table: table),
|
||||
$BangHistoryAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> searchQuery = const Value.absent(),
|
||||
Value<String> trigger = const Value.absent(),
|
||||
Value<Uint8List> iconData = const Value.absent(),
|
||||
Value<DateTime> fetchDate = const Value.absent(),
|
||||
Value<DateTime> searchDate = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
BangIconCompanion(
|
||||
BangHistoryCompanion(
|
||||
searchQuery: searchQuery,
|
||||
trigger: trigger,
|
||||
iconData: iconData,
|
||||
fetchDate: fetchDate,
|
||||
searchDate: searchDate,
|
||||
rowid: rowid,
|
||||
),
|
||||
createCompanionCallback: ({
|
||||
required String searchQuery,
|
||||
required String trigger,
|
||||
required Uint8List iconData,
|
||||
required DateTime fetchDate,
|
||||
required DateTime searchDate,
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
BangIconCompanion.insert(
|
||||
BangHistoryCompanion.insert(
|
||||
searchQuery: searchQuery,
|
||||
trigger: trigger,
|
||||
iconData: iconData,
|
||||
fetchDate: fetchDate,
|
||||
searchDate: searchDate,
|
||||
rowid: rowid,
|
||||
),
|
||||
withReferenceMapper: (p0) => p0
|
||||
.map((e) =>
|
||||
(e.readTable(table), $BangIconReferences(db, table, e)))
|
||||
(e.readTable(table), $BangHistoryReferences(db, table, e)))
|
||||
.toList(),
|
||||
prefetchHooksCallback: ({trigger = false}) {
|
||||
return PrefetchHooks(
|
||||
@@ -2112,9 +2128,9 @@ class $BangIconTableManager extends RootTableManager<
|
||||
state = state.withJoin(
|
||||
currentTable: table,
|
||||
currentColumn: table.trigger,
|
||||
referencedTable: $BangIconReferences._triggerTable(db),
|
||||
referencedTable: $BangHistoryReferences._triggerTable(db),
|
||||
referencedColumn:
|
||||
$BangIconReferences._triggerTable(db).trigger,
|
||||
$BangHistoryReferences._triggerTable(db).trigger,
|
||||
) as T;
|
||||
}
|
||||
|
||||
@@ -2128,17 +2144,17 @@ class $BangIconTableManager extends RootTableManager<
|
||||
));
|
||||
}
|
||||
|
||||
typedef $BangIconProcessedTableManager = ProcessedTableManager<
|
||||
typedef $BangHistoryProcessedTableManager = ProcessedTableManager<
|
||||
_$BangDatabase,
|
||||
BangIcon,
|
||||
BangIconData,
|
||||
$BangIconFilterComposer,
|
||||
$BangIconOrderingComposer,
|
||||
$BangIconAnnotationComposer,
|
||||
$BangIconCreateCompanionBuilder,
|
||||
$BangIconUpdateCompanionBuilder,
|
||||
(BangIconData, $BangIconReferences),
|
||||
BangIconData,
|
||||
BangHistory,
|
||||
BangHistoryData,
|
||||
$BangHistoryFilterComposer,
|
||||
$BangHistoryOrderingComposer,
|
||||
$BangHistoryAnnotationComposer,
|
||||
$BangHistoryCreateCompanionBuilder,
|
||||
$BangHistoryUpdateCompanionBuilder,
|
||||
(BangHistoryData, $BangHistoryReferences),
|
||||
BangHistoryData,
|
||||
PrefetchHooks Function({bool trigger})>;
|
||||
typedef $BangFtsCreateCompanionBuilder = BangFtsCompanion Function({
|
||||
required String trigger,
|
||||
@@ -2266,7 +2282,7 @@ class $BangDatabaseManager {
|
||||
$BangSyncTableManager(_db, _db.bangSync);
|
||||
$BangFrequencyTableManager get bangFrequency =>
|
||||
$BangFrequencyTableManager(_db, _db.bangFrequency);
|
||||
$BangIconTableManager get bangIcon =>
|
||||
$BangIconTableManager(_db, _db.bangIcon);
|
||||
$BangHistoryTableManager get bangHistory =>
|
||||
$BangHistoryTableManager(_db, _db.bangHistory);
|
||||
$BangFtsTableManager get bangFts => $BangFtsTableManager(_db, _db.bangFts);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:fast_equatable/fast_equatable.dart';
|
||||
|
||||
class SearchHistoryEntry with FastEquatable {
|
||||
final String searchQuery;
|
||||
final String trigger;
|
||||
final DateTime searchDate;
|
||||
|
||||
SearchHistoryEntry({
|
||||
required this.searchQuery,
|
||||
required this.trigger,
|
||||
required this.searchDate,
|
||||
});
|
||||
|
||||
@override
|
||||
bool get cacheHash => true;
|
||||
|
||||
@override
|
||||
List<Object?> get hashParameters => [
|
||||
searchQuery,
|
||||
trigger,
|
||||
searchDate,
|
||||
];
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -8,8 +8,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/features/bangs/domain/repositories/search.dart';
|
||||
import 'package:lensai/features/bangs/presentation/widgets/bang_details.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
|
||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||
import 'package:lensai/features/user/domain/repositories/settings.dart';
|
||||
import 'package:lensai/presentation/hooks/listenable_callback.dart';
|
||||
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
||||
|
||||
@@ -22,9 +21,7 @@ class BangSearchScreen extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final resultsAsync = ref.watch(bangSearchProvider);
|
||||
final incognitoEnabled = ref.watch(
|
||||
settingsRepositoryProvider.select(
|
||||
(value) => (value.valueOrNull ?? Settings.withDefaults()).incognitoMode,
|
||||
),
|
||||
settingsRepositoryProvider.select((value) => value.incognitoMode),
|
||||
);
|
||||
|
||||
final textEditingController =
|
||||
|
||||
@@ -5,9 +5,6 @@ import 'package:lensai/core/routing/routes.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||
import 'package:lensai/utils/ui_helper.dart' as ui_helper;
|
||||
|
||||
class BangDetails extends HookConsumerWidget {
|
||||
final BangData bangData;
|
||||
@@ -71,24 +68,12 @@ class BangDetails extends HookConsumerWidget {
|
||||
onPressed: () async {
|
||||
final url = Uri.parse(bangData.getUrl('').origin);
|
||||
|
||||
final launchExternal = ref.read(
|
||||
settingsRepositoryProvider.select(
|
||||
(value) =>
|
||||
(value.valueOrNull ?? Settings.withDefaults())
|
||||
.launchUrlExternal,
|
||||
),
|
||||
);
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: url);
|
||||
|
||||
if (launchExternal) {
|
||||
await ui_helper.launchUrlFeedback(context, url);
|
||||
} else {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: url);
|
||||
|
||||
if (context.mounted) {
|
||||
context.go(BrowserRoute().location);
|
||||
}
|
||||
if (context.mounted) {
|
||||
context.go(BrowserRoute().location);
|
||||
}
|
||||
},
|
||||
label: Text(bangData.domain),
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
// The default Material-style Autocomplete options.
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/search/domain/providers/search_suggestions.dart';
|
||||
import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/speech_to_text_button.dart';
|
||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||
import 'package:lensai/features/search/domain/providers/search_suggestions.dart';
|
||||
import 'package:lensai/features/user/domain/repositories/settings.dart';
|
||||
import 'package:lensai/presentation/widgets/autocomplete.dart';
|
||||
|
||||
class SearchField extends HookConsumerWidget {
|
||||
@@ -31,19 +29,17 @@ class SearchField extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final incognitoEnabled = ref.watch(
|
||||
settingsRepositoryProvider.select(
|
||||
(value) => (value.valueOrNull ?? Settings.withDefaults()).incognitoMode,
|
||||
),
|
||||
settingsRepositoryProvider.select((value) => value.incognitoMode),
|
||||
);
|
||||
|
||||
final optionsStream = ref.watch(searchSuggestionsProvider());
|
||||
|
||||
final focusNode = useFocusNode();
|
||||
|
||||
final quickAnswer = useListenableSelector(
|
||||
textController,
|
||||
() => textController.text.endsWith('?'),
|
||||
);
|
||||
// final quickAnswer = useListenableSelector(
|
||||
// textController,
|
||||
// () => textController.text.endsWith('?'),
|
||||
// );
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -89,7 +85,7 @@ class SearchField extends HookConsumerWidget {
|
||||
child: BangIcon(activeBang!, iconSize: 24.0),
|
||||
)
|
||||
: null,
|
||||
label: const Text('Query'),
|
||||
// label: const Text('Query'),
|
||||
hintText: 'Ask anything...',
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
suffixIcon: SpeechToTextButton(
|
||||
@@ -113,21 +109,21 @@ class SearchField extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
if (activeBang?.domain.endsWith('kagi.com') == true)
|
||||
SwitchListTile(
|
||||
value: quickAnswer,
|
||||
onChanged: (_) {
|
||||
if (textController.text.endsWith('?')) {
|
||||
textController.text = textController.text
|
||||
.substring(0, textController.text.length - 1);
|
||||
} else {
|
||||
textController.text = '${textController.text}?';
|
||||
}
|
||||
},
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: const Text('Quick Answer'),
|
||||
secondary: const Icon(MdiIcons.lightningBolt),
|
||||
),
|
||||
// if (activeBang?.domain.endsWith('kagi.com') == true)
|
||||
// SwitchListTile(
|
||||
// value: quickAnswer,
|
||||
// onChanged: (_) {
|
||||
// if (textController.text.endsWith('?')) {
|
||||
// textController.text = textController.text
|
||||
// .substring(0, textController.text.length - 1);
|
||||
// } else {
|
||||
// textController.text = '${textController.text}?';
|
||||
// }
|
||||
// },
|
||||
// contentPadding: EdgeInsets.zero,
|
||||
// title: const Text('Quick Answer'),
|
||||
// secondary: const Icon(MdiIcons.lightningBolt),
|
||||
// ),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/domain/repositories/data.dart';
|
||||
import 'package:lensai/features/bangs/domain/providers/search.dart';
|
||||
import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart';
|
||||
import 'package:lensai/features/bangs/presentation/widgets/search_field.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
@@ -36,13 +36,11 @@ class SiteSearch extends HookConsumerWidget {
|
||||
|
||||
Future<void> submitSearch() async {
|
||||
if (activeBang != null && (formKey.currentState?.validate() == true)) {
|
||||
await ref
|
||||
.read(bangDataRepositoryProvider.notifier)
|
||||
.increaseFrequency(activeBang.trigger);
|
||||
final searchUri = await ref.read(
|
||||
triggerBangSearchProvider(activeBang, textController.text).future,
|
||||
);
|
||||
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: activeBang.getUrl(textController.text));
|
||||
await ref.read(tabRepositoryProvider.notifier).addTab(url: searchUri);
|
||||
|
||||
ref.read(overlayDialogControllerProvider.notifier).dismiss();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user