improve tab insertion process

This commit is contained in:
Fabian Freund
2026-01-01 17:45:18 +01:00
parent 8848bd5d09
commit 61267c899d
28 changed files with 2109 additions and 91 deletions
+441
View File
@@ -0,0 +1,441 @@
{
"_meta": {
"description": "This file contains a serialized version of schema entities for drift.",
"version": "1.3.0"
},
"options": {
"store_date_time_values_as_text": false
},
"entities": [
{
"id": 0,
"references": [],
"type": "table",
"data": {
"name": "container",
"was_declared_in_moor": true,
"columns": [
{
"name": "id",
"getter_name": "id",
"moor_type": "string",
"nullable": false,
"customConstraints": "PRIMARY KEY NOT NULL",
"default_dart": null,
"default_client_dart": null,
"dsl_features": [
"primary-key"
]
},
{
"name": "name",
"getter_name": "name",
"moor_type": "string",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "color",
"getter_name": "color",
"moor_type": "int",
"nullable": false,
"customConstraints": "NOT NULL",
"default_dart": null,
"default_client_dart": null,
"dsl_features": [],
"type_converter": {
"dart_expr": "const ColorConverter()",
"dart_type_name": "Color"
}
},
{
"name": "metadata",
"getter_name": "metadata",
"moor_type": "string",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": [],
"type_converter": {
"dart_expr": "const ContainerMetadataConverter()",
"dart_type_name": "ContainerMetadata"
}
}
],
"is_virtual": false,
"without_rowid": false,
"constraints": []
}
},
{
"id": 1,
"references": [
0
],
"type": "table",
"data": {
"name": "tab",
"was_declared_in_moor": true,
"columns": [
{
"name": "id",
"getter_name": "id",
"moor_type": "string",
"nullable": false,
"customConstraints": "PRIMARY KEY NOT NULL",
"default_dart": null,
"default_client_dart": null,
"dsl_features": [
"primary-key"
]
},
{
"name": "source",
"getter_name": "source",
"moor_type": "int",
"nullable": false,
"customConstraints": "NOT NULL",
"default_dart": null,
"default_client_dart": null,
"dsl_features": [],
"type_converter": {
"dart_expr": "const EnumIndexConverter<TabSource>(TabSource.values)",
"dart_type_name": "TabSource"
}
},
{
"name": "parent_id",
"getter_name": "parentId",
"moor_type": "string",
"nullable": true,
"customConstraints": "REFERENCES tab(id)ON DELETE SET NULL",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "container_id",
"getter_name": "containerId",
"moor_type": "string",
"nullable": true,
"customConstraints": "REFERENCES container(id)ON DELETE CASCADE",
"default_dart": null,
"default_client_dart": null,
"dsl_features": [
{
"foreign_key": {
"to": {
"table": "container",
"column": "id"
},
"initially_deferred": false,
"on_update": null,
"on_delete": "cascade"
}
}
]
},
{
"name": "order_key",
"getter_name": "orderKey",
"moor_type": "string",
"nullable": false,
"customConstraints": "NOT NULL",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "url",
"getter_name": "url",
"moor_type": "string",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": [],
"type_converter": {
"dart_expr": "const UriConverterNullable()",
"dart_type_name": "Uri?"
}
},
{
"name": "title",
"getter_name": "title",
"moor_type": "string",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "is_private",
"getter_name": "isPrivate",
"moor_type": "bool",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "is_probably_readerable",
"getter_name": "isProbablyReaderable",
"moor_type": "bool",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "extracted_content_markdown",
"getter_name": "extractedContentMarkdown",
"moor_type": "string",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "extracted_content_plain",
"getter_name": "extractedContentPlain",
"moor_type": "string",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "full_content_markdown",
"getter_name": "fullContentMarkdown",
"moor_type": "string",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "full_content_plain",
"getter_name": "fullContentPlain",
"moor_type": "string",
"nullable": true,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "timestamp",
"getter_name": "timestamp",
"moor_type": "dateTime",
"nullable": false,
"customConstraints": "NOT NULL",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
}
],
"is_virtual": false,
"without_rowid": false,
"constraints": []
}
},
{
"id": 2,
"references": [
1
],
"type": "table",
"data": {
"name": "tab_fts",
"was_declared_in_moor": true,
"columns": [
{
"name": "title",
"getter_name": "title",
"moor_type": "string",
"nullable": false,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "url",
"getter_name": "url",
"moor_type": "string",
"nullable": false,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "extracted_content_plain",
"getter_name": "extractedContentPlain",
"moor_type": "string",
"nullable": false,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
},
{
"name": "full_content_plain",
"getter_name": "fullContentPlain",
"moor_type": "string",
"nullable": false,
"customConstraints": "",
"default_dart": null,
"default_client_dart": null,
"dsl_features": []
}
],
"is_virtual": true,
"create_virtual_stmt": "CREATE VIRTUAL TABLE \"tab_fts\" USING fts5(title, url, extracted_content_plain, full_content_plain, content=tab, tokenize=\"trigram\")",
"without_rowid": false,
"constraints": []
}
},
{
"id": 3,
"references": [
1
],
"type": "trigger",
"data": {
"on": 1,
"references_in_body": [
1
],
"name": "tab_maintain_parent_chain_on_delete",
"sql": "CREATE TRIGGER tab_maintain_parent_chain_on_delete BEFORE DELETE ON tab BEGIN\n -- Update all children of the deleted row to point to its parent\n UPDATE tab \n SET parent_id = OLD.parent_id \n WHERE parent_id = OLD.id;\nEND;"
}
},
{
"id": 4,
"references": [
1,
2
],
"type": "trigger",
"data": {
"on": 1,
"references_in_body": [
1,
2
],
"name": "tab_after_insert",
"sql": "CREATE TRIGGER tab_after_insert AFTER INSERT ON tab BEGIN\n INSERT INTO \n tab_fts(rowid, title, url, extracted_content_plain, full_content_plain) \n VALUES (new.rowid, new.title, new.url, new.extracted_content_plain, new.full_content_plain);\nEND;"
}
},
{
"id": 5,
"references": [
1,
2
],
"type": "trigger",
"data": {
"on": 1,
"references_in_body": [
1,
2
],
"name": "tab_after_delete",
"sql": "CREATE TRIGGER tab_after_delete AFTER DELETE ON tab BEGIN\n INSERT INTO \n tab_fts(tab_fts, rowid, title, url, extracted_content_plain, full_content_plain) \n VALUES('delete', old.rowid, old.title, old.url, old.extracted_content_plain, old.full_content_plain);\nEND;"
}
},
{
"id": 6,
"references": [
1,
2
],
"type": "trigger",
"data": {
"on": 1,
"references_in_body": [
1,
2
],
"name": "tab_after_update",
"sql": "CREATE TRIGGER tab_after_update AFTER UPDATE ON tab BEGIN\n INSERT INTO \n tab_fts(tab_fts, rowid, title, url, extracted_content_plain, full_content_plain) \n VALUES('delete', old.rowid, old.title, old.url, old.extracted_content_plain, old.full_content_plain);\n INSERT INTO \n tab_fts(rowid, title, url, extracted_content_plain, full_content_plain) \n VALUES (new.rowid, new.title, new.url, new.extracted_content_plain, new.full_content_plain);\nEND;"
}
}
],
"fixed_sql": [
{
"name": "container",
"sql": [
{
"dialect": "sqlite",
"sql": "CREATE TABLE IF NOT EXISTS \"container\" (\"id\" TEXT PRIMARY KEY NOT NULL, \"name\" TEXT, \"color\" INTEGER NOT NULL, \"metadata\" TEXT);"
}
]
},
{
"name": "tab",
"sql": [
{
"dialect": "sqlite",
"sql": "CREATE TABLE IF NOT EXISTS \"tab\" (\"id\" TEXT PRIMARY KEY NOT NULL, \"source\" INTEGER NOT NULL, \"parent_id\" TEXT REFERENCES tab(id)ON DELETE SET NULL, \"container_id\" TEXT REFERENCES container(id)ON DELETE CASCADE, \"order_key\" TEXT NOT NULL, \"url\" TEXT, \"title\" TEXT, \"is_private\" INTEGER, \"is_probably_readerable\" INTEGER, \"extracted_content_markdown\" TEXT, \"extracted_content_plain\" TEXT, \"full_content_markdown\" TEXT, \"full_content_plain\" TEXT, \"timestamp\" INTEGER NOT NULL);"
}
]
},
{
"name": "tab_fts",
"sql": [
{
"dialect": "sqlite",
"sql": "CREATE VIRTUAL TABLE IF NOT EXISTS \"tab_fts\" USING fts5(title, url, extracted_content_plain, full_content_plain, content=tab, tokenize=\"trigram\");"
}
]
},
{
"name": "tab_maintain_parent_chain_on_delete",
"sql": [
{
"dialect": "sqlite",
"sql": "CREATE TRIGGER tab_maintain_parent_chain_on_delete BEFORE DELETE ON tab BEGIN UPDATE tab SET parent_id = OLD.parent_id WHERE parent_id = OLD.id;END"
}
]
},
{
"name": "tab_after_insert",
"sql": [
{
"dialect": "sqlite",
"sql": "CREATE TRIGGER tab_after_insert AFTER INSERT ON tab BEGIN INSERT INTO tab_fts (\"rowid\", title, url, extracted_content_plain, full_content_plain) VALUES (new.\"rowid\", new.title, new.url, new.extracted_content_plain, new.full_content_plain);END"
}
]
},
{
"name": "tab_after_delete",
"sql": [
{
"dialect": "sqlite",
"sql": "CREATE TRIGGER tab_after_delete AFTER DELETE ON tab BEGIN INSERT INTO tab_fts (tab_fts, \"rowid\", title, url, extracted_content_plain, full_content_plain) VALUES ('delete', old.\"rowid\", old.title, old.url, old.extracted_content_plain, old.full_content_plain);END"
}
]
},
{
"name": "tab_after_update",
"sql": [
{
"dialect": "sqlite",
"sql": "CREATE TRIGGER tab_after_update AFTER UPDATE ON tab BEGIN INSERT INTO tab_fts (tab_fts, \"rowid\", title, url, extracted_content_plain, full_content_plain) VALUES ('delete', old.\"rowid\", old.title, old.url, old.extracted_content_plain, old.full_content_plain);INSERT INTO tab_fts (\"rowid\", title, url, extracted_content_plain, full_content_plain) VALUES (new.\"rowid\", new.title, new.url, new.extracted_content_plain, new.full_content_plain);END"
}
]
}
]
}
@@ -96,7 +96,11 @@ class BangDetails extends HookConsumerWidget {
await ref
.read(tabRepositoryProvider.notifier)
.addTab(url: url, private: isPrivate);
.addTab(
url: url,
private: isPrivate,
selectTab: true,
);
if (context.mounted) {
const BrowserRoute().go(context);
@@ -103,7 +103,7 @@ class SiteSearch extends HookConsumerWidget {
if (searchInNewTab) {
await ref
.read(tabRepositoryProvider.notifier)
.addTab(url: searchUri, private: isPrivate);
.addTab(url: searchUri, private: isPrivate, selectTab: true);
} else {
await ref
.read(tabSessionProvider(tabId: null).notifier)
@@ -80,6 +80,7 @@ GeckoSelectionActionService selectionActionService(Ref ref) {
url: defaultSearchBang.getTemplateUrl(text),
parentId: currentTab?.id,
private: isPrivate,
selectTab: true,
);
} else {
logger.e('No default search bang found');
@@ -55,7 +55,7 @@ final class SelectionActionServiceProvider
}
String _$selectionActionServiceHash() =>
r'424c2c444524ee4bf2302405cac3358c148a7b16';
r'6250d2121375b2a41c2f0450512fc836c996f461';
@ProviderFor(eventService)
final eventServiceProvider = EventServiceProvider._();
@@ -30,6 +30,7 @@ import 'package:weblibre/features/geckoview/domain/providers.dart';
import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart';
import 'package:weblibre/features/geckoview/domain/providers/tab_list.dart';
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_source.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/providers.dart';
import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selected_container.dart';
@@ -55,7 +56,7 @@ class TabRepository extends _$TabRepository {
Future<String> addTab({
Uri? url,
bool selectTab = true,
required bool selectTab,
bool startLoading = true,
String? parentId,
LoadUrlFlags flags = LoadUrlFlags.NONE,
@@ -125,6 +126,7 @@ class TabRepository extends _$TabRepository {
await tabDao.insertTab(
tabId,
parentId: Value(tab.parentId),
source: TabSource.manual,
containerId: Value(container?.value?.id),
isPrivate: Value(tab.private),
url: Value(Uri.tryParse(tab.url)),
@@ -409,16 +411,14 @@ class TabRepository extends _$TabRepository {
final db = ref.watch(tabDatabaseProvider);
final tabAddedSub = eventSerivce.tabAddedStream.listen((tabId) async {
if (await db.tabDao.getTabDataById(tabId).getSingleOrNull() == null) {
// ignore: only_use_keep_alive_inside_keep_alive
final containerId = ref.read(selectedContainerProvider);
await db.tabDao.insertTab(
tabId,
parentId: const Value.absent(),
containerId: Value(containerId),
isPrivate: const Value.absent(),
);
}
final containerId = ref.read(selectedContainerProvider);
await db.tabDao.insertTab(
tabId,
parentId: const Value.absent(),
source: TabSource.addedEvent,
containerId: Value(containerId),
isPrivate: const Value.absent(),
);
});
final containerSiteAssignementSub = eventSerivce.siteAssignementEvent.listen((
@@ -451,6 +451,7 @@ class TabRepository extends _$TabRepository {
private: tabState.isPrivate,
container: Value(containerData),
parentId: tabState.id,
selectTab: true,
);
if (tabIsEmpty) {
@@ -41,7 +41,7 @@ final class TabRepositoryProvider
}
}
String _$tabRepositoryHash() => r'de20adb4a38f8cd443be7d2f4ea07eded58803a3';
String _$tabRepositoryHash() => r'7faec6d906e44b679d6fd67ad5e722f5d01cff0a';
abstract class _$TabRepository extends $Notifier<void> {
void build();
@@ -50,6 +50,7 @@ class OpenSharedContent extends HookConsumerWidget {
private: isPrivate,
container: Value(selectedContainer.value),
launchedFromIntent: true,
selectTab: true,
);
if (context.mounted) {
@@ -501,7 +501,7 @@ class QuickTabSwitcher extends HookConsumerWidget {
if (item.isHistory) {
await ref
.read(tabRepositoryProvider.notifier)
.addTab(url: item.url, private: false);
.addTab(url: item.url, private: false, selectTab: true);
} else {
await ref.read(tabRepositoryProvider.notifier).selectTab(item.id);
}
@@ -755,6 +755,7 @@ class NavigationMenuButton extends HookConsumerWidget {
url: Uri.parse('https://addons.mozilla.org'),
private: isPrivate,
container: const Value(null),
selectTab: true,
);
},
leadingIcon: const Icon(MdiIcons.puzzlePlus),
@@ -188,6 +188,7 @@ class _BrowserViewState extends ConsumerState<BrowserView>
settings.tabIntentOpenSetting ==
TabIntentOpenSetting.private,
launchedFromIntent: true,
selectTab: true,
);
case SharedText():
final bang =
@@ -202,6 +203,7 @@ class _BrowserViewState extends ConsumerState<BrowserView>
settings.tabIntentOpenSetting ==
TabIntentOpenSetting.private,
launchedFromIntent: true,
selectTab: true,
);
}
case TabIntentOpenSetting.ask:
@@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:drift/drift.dart' show Value;
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@@ -297,7 +298,7 @@ class TabViewHeader extends HookConsumerWidget {
ref
.read(tabRepositoryProvider.notifier)
.undoClose,
count: count,
count: count.length,
);
}
}
@@ -329,7 +330,7 @@ class TabViewHeader extends HookConsumerWidget {
ref
.read(tabRepositoryProvider.notifier)
.undoClose,
count: count,
count: count.length,
);
}
}
@@ -379,7 +380,7 @@ class TabViewHeader extends HookConsumerWidget {
if (result == true) {
try {
await ref
final closedTabIds = await ref
.read(
tabDataRepositoryProvider
.notifier,
@@ -402,25 +403,35 @@ class TabViewHeader extends HookConsumerWidget {
tabRepositoryProvider.notifier,
)
.addMultipleTabs(
tabs: tabs
.map(
(tab) => AddTabParams(
url: tab.url.toString(),
startLoading: true,
parentId: tab.parentId,
private:
tab.isPrivate ??
false,
flags: LoadUrlFlags.NONE
.toValue(),
source: Internal.newTab
.toValue(),
contextId: selectedContainer
.metadata
.contextualIdentity,
),
)
.toList(),
tabs: tabs.map((tab) {
var parentId = tab.parentId;
while (parentId != null &&
closedTabIds.contains(
parentId,
)) {
parentId = tabs
.firstWhereOrNull(
(old) =>
old.id == parentId,
)
?.parentId;
}
return AddTabParams(
url: tab.url.toString(),
startLoading: true,
parentId: parentId,
private:
tab.isPrivate ?? false,
flags: LoadUrlFlags.NONE
.toValue(),
source: Internal.newTab
.toValue(),
contextId: selectedContainer
.metadata
.contextualIdentity,
);
}).toList(),
container: Value(
selectedContainer,
),
@@ -473,6 +473,7 @@ class HistoryScreen extends HookConsumerWidget {
.addTab(
url: Uri.parse(item.url),
private: false,
selectTab: true,
);
if (context.mounted) {
@@ -116,6 +116,7 @@ class SearchScreen extends HookConsumerWidget {
? ref.read(selectedTabProvider)
: null,
launchedFromIntent: launchedFromIntent,
selectTab: true,
);
if (context.mounted) {
@@ -173,12 +174,14 @@ class SearchScreen extends HookConsumerWidget {
style: switch (selectedTabType.value) {
TabType.regular => null,
TabType.private => SegmentedButton.styleFrom(
selectedBackgroundColor: AppColors.privateSelectionOverlay,
selectedBackgroundColor:
AppColors.privateSelectionOverlay,
),
TabType.child =>
(currentTabTabType == TabType.private)
? SegmentedButton.styleFrom(
selectedBackgroundColor: AppColors.privateSelectionOverlay,
selectedBackgroundColor:
AppColors.privateSelectionOverlay,
)
: null,
},
@@ -232,6 +235,7 @@ class SearchScreen extends HookConsumerWidget {
? ref.read(selectedTabProvider)
: null,
launchedFromIntent: launchedFromIntent,
selectTab: true,
);
if (context.mounted) {
@@ -126,7 +126,11 @@ class HistorySuggestions extends HookConsumerWidget {
if (uri != null) {
await ref
.read(tabRepositoryProvider.notifier)
.addTab(url: uri, private: isPrivate);
.addTab(
url: uri,
private: isPrivate,
selectTab: true,
);
if (context.mounted) {
ref
@@ -26,6 +26,7 @@ import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/database/daos/tab.drift.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/database/database.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/database/definitions.drift.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_source.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/models/tab_query_result.dart';
@DriftAccessor()
@@ -122,6 +123,7 @@ class TabDao extends DatabaseAccessor<TabDatabase> with $TabDaoMixin {
TabCompanion.insert(
id: tabId,
parentId: parentId,
source: TabSource.manual,
timestamp: DateTime.now(),
containerId: containerId,
url: url,
@@ -131,11 +133,13 @@ class TabDao extends DatabaseAccessor<TabDatabase> with $TabDaoMixin {
),
onConflict: DoUpdate(
(old) => TabCompanion(
source: const Value(TabSource.manual),
parentId: parentId,
containerId: containerId,
orderKey: Value.absentIfNull(orderKey.value),
url: url,
title: title,
isPrivate: isPrivate,
orderKey: Value.absentIfNull(orderKey.value),
),
),
);
@@ -147,6 +151,7 @@ class TabDao extends DatabaseAccessor<TabDatabase> with $TabDaoMixin {
//Upsert an tab only if there is no container assigned yet
Future<String> insertTab(
String tabId, {
required TabSource source,
required Value<bool?> isPrivate,
required Value<String?> parentId,
Value<String?> containerId = const Value.absent(),
@@ -163,6 +168,7 @@ class TabDao extends DatabaseAccessor<TabDatabase> with $TabDaoMixin {
TabCompanion.insert(
id: tabId,
parentId: parentId,
source: source,
timestamp: DateTime.now(),
containerId: containerId,
orderKey: currentOrderKey,
@@ -170,7 +176,18 @@ class TabDao extends DatabaseAccessor<TabDatabase> with $TabDaoMixin {
url: url,
title: title,
),
mode: InsertMode.insertOrIgnore,
onConflict: DoUpdate(
(old) => TabCompanion(
source: Value(source),
parentId: parentId,
containerId: containerId,
url: url,
title: title,
isPrivate: isPrivate,
orderKey: Value.absentIfNull(orderKey.value),
),
where: (old) => old.source.isSmallerThanValue(source.index),
),
);
return tabId;
@@ -273,6 +290,7 @@ class TabDao extends DatabaseAccessor<TabDatabase> with $TabDaoMixin {
_undoHistory[id] ??
TabCompanion.insert(
id: id,
source: TabSource.syncEvent,
orderKey: currentOrderKey,
timestamp: DateTime.now(),
);
@@ -281,7 +299,7 @@ class TabDao extends DatabaseAccessor<TabDatabase> with $TabDaoMixin {
return insertable;
}),
mode: InsertMode.insertOrIgnore,
onConflict: DoNothing(),
);
});
}
@@ -25,12 +25,13 @@ import 'package:weblibre/features/geckoview/features/tabs/data/database/daos/con
import 'package:weblibre/features/geckoview/features/tabs/data/database/daos/tab.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/database/database.drift.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/database/database.steps.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_source.dart';
import 'package:weblibre/features/search/domain/fts_tokenizer.dart';
@DriftDatabase(include: {'definitions.drift'}, daos: [ContainerDao, TabDao])
class TabDatabase extends $TabDatabase with TrigramQueryBuilderMixin {
@override
final int schemaVersion = 3;
final int schemaVersion = 4;
@override
final int ftsTokenLimit = 10;
@@ -83,5 +84,16 @@ class TabDatabase extends $TabDatabase with TrigramQueryBuilderMixin {
final tabAtV3 = schema.tab;
await m.addColumn(tabAtV3, tabAtV3.isPrivate);
},
from3To4: (m, schema) async {
await m.alterTable(
TableMigration(
schema.tab,
columnTransformer: {
schema.tab.source: Constant(TabSource.manual.index),
},
newColumns: [schema.tab.source],
),
);
},
);
}
@@ -265,8 +265,127 @@ class Shape2 extends i0.VersionedVirtualTable {
columnsByName['full_content_plain']! as i1.GeneratedColumn<String>;
}
final class Schema4 extends i0.VersionedSchema {
Schema4({required super.database}) : super(version: 4);
@override
late final List<i1.DatabaseSchemaEntity> entities = [
container,
tab,
tabFts,
tabMaintainParentChainOnDelete,
tabAfterInsert,
tabAfterDelete,
tabAfterUpdate,
];
late final Shape0 container = Shape0(
source: i0.VersionedTable(
entityName: 'container',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [_column_0, _column_1, _column_2, _column_3],
attachedDatabase: database,
),
alias: null,
);
late final Shape3 tab = Shape3(
source: i0.VersionedTable(
entityName: 'tab',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_16,
_column_4,
_column_5,
_column_6,
_column_7,
_column_8,
_column_9,
_column_10,
_column_11,
_column_12,
_column_13,
_column_14,
_column_15,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape2 tabFts = Shape2(
source: i0.VersionedVirtualTable(
entityName: 'tab_fts',
moduleAndArgs:
'fts5(title, url, extracted_content_plain, full_content_plain, content=tab, tokenize="trigram")',
columns: [_column_8, _column_7, _column_12, _column_14],
attachedDatabase: database,
),
alias: null,
);
final i1.Trigger tabMaintainParentChainOnDelete = i1.Trigger(
'CREATE TRIGGER tab_maintain_parent_chain_on_delete BEFORE DELETE ON tab BEGIN UPDATE tab SET parent_id = OLD.parent_id WHERE parent_id = OLD.id;END',
'tab_maintain_parent_chain_on_delete',
);
final i1.Trigger tabAfterInsert = i1.Trigger(
'CREATE TRIGGER tab_after_insert AFTER INSERT ON tab BEGIN INSERT INTO tab_fts ("rowid", title, url, extracted_content_plain, full_content_plain) VALUES (new."rowid", new.title, new.url, new.extracted_content_plain, new.full_content_plain);END',
'tab_after_insert',
);
final i1.Trigger tabAfterDelete = i1.Trigger(
'CREATE TRIGGER tab_after_delete AFTER DELETE ON tab BEGIN INSERT INTO tab_fts (tab_fts, "rowid", title, url, extracted_content_plain, full_content_plain) VALUES (\'delete\', old."rowid", old.title, old.url, old.extracted_content_plain, old.full_content_plain);END',
'tab_after_delete',
);
final i1.Trigger tabAfterUpdate = i1.Trigger(
'CREATE TRIGGER tab_after_update AFTER UPDATE ON tab BEGIN INSERT INTO tab_fts (tab_fts, "rowid", title, url, extracted_content_plain, full_content_plain) VALUES (\'delete\', old."rowid", old.title, old.url, old.extracted_content_plain, old.full_content_plain);INSERT INTO tab_fts ("rowid", title, url, extracted_content_plain, full_content_plain) VALUES (new."rowid", new.title, new.url, new.extracted_content_plain, new.full_content_plain);END',
'tab_after_update',
);
}
class Shape3 extends i0.VersionedTable {
Shape3({required super.source, required super.alias}) : super.aliased();
i1.GeneratedColumn<String> get id =>
columnsByName['id']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<int> get source =>
columnsByName['source']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<String> get parentId =>
columnsByName['parent_id']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get containerId =>
columnsByName['container_id']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get orderKey =>
columnsByName['order_key']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get url =>
columnsByName['url']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get title =>
columnsByName['title']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<int> get isPrivate =>
columnsByName['is_private']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<int> get isProbablyReaderable =>
columnsByName['is_probably_readerable']! as i1.GeneratedColumn<int>;
i1.GeneratedColumn<String> get extractedContentMarkdown =>
columnsByName['extracted_content_markdown']!
as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get extractedContentPlain =>
columnsByName['extracted_content_plain']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get fullContentMarkdown =>
columnsByName['full_content_markdown']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<String> get fullContentPlain =>
columnsByName['full_content_plain']! as i1.GeneratedColumn<String>;
i1.GeneratedColumn<int> get timestamp =>
columnsByName['timestamp']! as i1.GeneratedColumn<int>;
}
i1.GeneratedColumn<int> _column_16(String aliasedName) =>
i1.GeneratedColumn<int>(
'source',
aliasedName,
false,
type: i1.DriftSqlType.int,
$customConstraints: 'NOT NULL',
);
i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
}) {
return (currentVersion, database) async {
switch (currentVersion) {
@@ -275,6 +394,11 @@ i0.MigrationStepWithVersion migrationSteps({
final migrator = i1.Migrator(database, schema);
await from2To3(migrator, schema);
return 3;
case 3:
final schema = Schema4(database: database);
final migrator = i1.Migrator(database, schema);
await from3To4(migrator, schema);
return 4;
default:
throw ArgumentError.value('Unknown migration from $currentVersion');
}
@@ -283,6 +407,7 @@ i0.MigrationStepWithVersion migrationSteps({
i1.OnUpgrade stepByStep({
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
}) => i0.VersionedSchema.stepByStepHelper(
step: migrationSteps(from2To3: from2To3),
step: migrationSteps(from2To3: from2To3, from3To4: from3To4),
);
@@ -4,6 +4,7 @@ import 'package:weblibre/features/geckoview/features/tabs/data/models/container_
import 'package:weblibre/features/geckoview/features/tabs/data/models/site_assignment.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/models/tab_query_result.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/database/converters/container_metadata_converter.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_source.dart';
CREATE TABLE container (
id TEXT PRIMARY KEY NOT NULL,
@@ -14,6 +15,7 @@ CREATE TABLE container (
CREATE TABLE tab(
id TEXT PRIMARY KEY NOT NULL,
source ENUM(TabSource) NOT NULL,
parent_id TEXT REFERENCES tab (id) ON DELETE SET NULL,
container_id TEXT REFERENCES container (id) ON DELETE CASCADE,
order_key TEXT NOT NULL,
@@ -9,12 +9,14 @@ import 'package:weblibre/features/geckoview/features/tabs/data/database/definiti
import 'package:weblibre/data/database/converters/color.dart' as i4;
import 'package:weblibre/features/geckoview/features/tabs/data/database/converters/container_metadata_converter.dart'
as i5;
import 'package:weblibre/data/database/converters/uri.dart' as i6;
import 'package:drift/internal/modular.dart' as i7;
import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_source.dart'
as i6;
import 'package:weblibre/data/database/converters/uri.dart' as i7;
import 'package:drift/internal/modular.dart' as i8;
import 'package:weblibre/features/geckoview/features/tabs/data/models/tab_query_result.dart'
as i8;
import 'package:weblibre/features/geckoview/features/tabs/data/models/site_assignment.dart'
as i9;
import 'package:weblibre/features/geckoview/features/tabs/data/models/site_assignment.dart'
as i10;
typedef $ContainerCreateCompanionBuilder =
i3.ContainerCompanion Function({
@@ -45,10 +47,10 @@ final class $ContainerReferences
static i0.MultiTypedResultKey<i3.Tab, List<i3.TabData>> _tabRefsTable(
i0.GeneratedDatabase db,
) => i0.MultiTypedResultKey.fromTable(
i7.ReadDatabaseContainer(db).resultSet<i3.Tab>('tab'),
i8.ReadDatabaseContainer(db).resultSet<i3.Tab>('tab'),
aliasName: i0.$_aliasNameGenerator(
i7.ReadDatabaseContainer(db).resultSet<i3.Container>('container').id,
i7.ReadDatabaseContainer(db).resultSet<i3.Tab>('tab').containerId,
i8.ReadDatabaseContainer(db).resultSet<i3.Container>('container').id,
i8.ReadDatabaseContainer(db).resultSet<i3.Tab>('tab').containerId,
),
);
@@ -56,7 +58,7 @@ final class $ContainerReferences
final manager = i3
.$TabTableManager(
$_db,
i7.ReadDatabaseContainer($_db).resultSet<i3.Tab>('tab'),
i8.ReadDatabaseContainer($_db).resultSet<i3.Tab>('tab'),
)
.filter((f) => f.containerId.id.sqlEquals($_itemColumn<String>('id')!));
@@ -108,7 +110,7 @@ class $ContainerFilterComposer
final i3.$TabFilterComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.id,
referencedTable: i7.ReadDatabaseContainer($db).resultSet<i3.Tab>('tab'),
referencedTable: i8.ReadDatabaseContainer($db).resultSet<i3.Tab>('tab'),
getReferencedColumn: (t) => t.containerId,
builder:
(
@@ -117,7 +119,7 @@ class $ContainerFilterComposer
$removeJoinBuilderFromRootComposer,
}) => i3.$TabFilterComposer(
$db: $db,
$table: i7.ReadDatabaseContainer($db).resultSet<i3.Tab>('tab'),
$table: i8.ReadDatabaseContainer($db).resultSet<i3.Tab>('tab'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
@@ -186,7 +188,7 @@ class $ContainerAnnotationComposer
final i3.$TabAnnotationComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.id,
referencedTable: i7.ReadDatabaseContainer($db).resultSet<i3.Tab>('tab'),
referencedTable: i8.ReadDatabaseContainer($db).resultSet<i3.Tab>('tab'),
getReferencedColumn: (t) => t.containerId,
builder:
(
@@ -195,7 +197,7 @@ class $ContainerAnnotationComposer
$removeJoinBuilderFromRootComposer,
}) => i3.$TabAnnotationComposer(
$db: $db,
$table: i7.ReadDatabaseContainer($db).resultSet<i3.Tab>('tab'),
$table: i8.ReadDatabaseContainer($db).resultSet<i3.Tab>('tab'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
@@ -273,7 +275,7 @@ class $ContainerTableManager
db: db,
explicitlyWatchedTables: [
if (tabRefs)
i7.ReadDatabaseContainer(db).resultSet<i3.Tab>('tab'),
i8.ReadDatabaseContainer(db).resultSet<i3.Tab>('tab'),
],
addJoins: null,
getPrefetchedDataCallback: (items) async {
@@ -321,6 +323,7 @@ typedef $ContainerProcessedTableManager =
typedef $TabCreateCompanionBuilder =
i3.TabCompanion Function({
required String id,
required i6.TabSource source,
i0.Value<String?> parentId,
i0.Value<String?> containerId,
required String orderKey,
@@ -338,6 +341,7 @@ typedef $TabCreateCompanionBuilder =
typedef $TabUpdateCompanionBuilder =
i3.TabCompanion Function({
i0.Value<String> id,
i0.Value<i6.TabSource> source,
i0.Value<String?> parentId,
i0.Value<String?> containerId,
i0.Value<String> orderKey,
@@ -358,12 +362,12 @@ final class $TabReferences
$TabReferences(super.$_db, super.$_table, super.$_typedResult);
static i3.Container _containerIdTable(i0.GeneratedDatabase db) =>
i7.ReadDatabaseContainer(db)
i8.ReadDatabaseContainer(db)
.resultSet<i3.Container>('container')
.createAlias(
i0.$_aliasNameGenerator(
i7.ReadDatabaseContainer(db).resultSet<i3.Tab>('tab').containerId,
i7.ReadDatabaseContainer(
i8.ReadDatabaseContainer(db).resultSet<i3.Tab>('tab').containerId,
i8.ReadDatabaseContainer(
db,
).resultSet<i3.Container>('container').id,
),
@@ -375,7 +379,7 @@ final class $TabReferences
final manager = i3
.$ContainerTableManager(
$_db,
i7.ReadDatabaseContainer($_db).resultSet<i3.Container>('container'),
i8.ReadDatabaseContainer($_db).resultSet<i3.Container>('container'),
)
.filter((f) => f.id.sqlEquals($_column));
final item = $_typedResult.readTableOrNull(_containerIdTable($_db));
@@ -399,6 +403,12 @@ class $TabFilterComposer extends i0.Composer<i0.GeneratedDatabase, i3.Tab> {
builder: (column) => i0.ColumnFilters(column),
);
i0.ColumnWithTypeConverterFilters<i6.TabSource, i6.TabSource, int>
get source => $composableBuilder(
column: $table.source,
builder: (column) => i0.ColumnWithTypeConverterFilters(column),
);
i0.ColumnFilters<String> get parentId => $composableBuilder(
column: $table.parentId,
builder: (column) => i0.ColumnFilters(column),
@@ -459,7 +469,7 @@ class $TabFilterComposer extends i0.Composer<i0.GeneratedDatabase, i3.Tab> {
final i3.$ContainerFilterComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.containerId,
referencedTable: i7.ReadDatabaseContainer(
referencedTable: i8.ReadDatabaseContainer(
$db,
).resultSet<i3.Container>('container'),
getReferencedColumn: (t) => t.id,
@@ -470,7 +480,7 @@ class $TabFilterComposer extends i0.Composer<i0.GeneratedDatabase, i3.Tab> {
$removeJoinBuilderFromRootComposer,
}) => i3.$ContainerFilterComposer(
$db: $db,
$table: i7.ReadDatabaseContainer(
$table: i8.ReadDatabaseContainer(
$db,
).resultSet<i3.Container>('container'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
@@ -496,6 +506,11 @@ class $TabOrderingComposer extends i0.Composer<i0.GeneratedDatabase, i3.Tab> {
builder: (column) => i0.ColumnOrderings(column),
);
i0.ColumnOrderings<int> get source => $composableBuilder(
column: $table.source,
builder: (column) => i0.ColumnOrderings(column),
);
i0.ColumnOrderings<String> get parentId => $composableBuilder(
column: $table.parentId,
builder: (column) => i0.ColumnOrderings(column),
@@ -555,7 +570,7 @@ class $TabOrderingComposer extends i0.Composer<i0.GeneratedDatabase, i3.Tab> {
final i3.$ContainerOrderingComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.containerId,
referencedTable: i7.ReadDatabaseContainer(
referencedTable: i8.ReadDatabaseContainer(
$db,
).resultSet<i3.Container>('container'),
getReferencedColumn: (t) => t.id,
@@ -566,7 +581,7 @@ class $TabOrderingComposer extends i0.Composer<i0.GeneratedDatabase, i3.Tab> {
$removeJoinBuilderFromRootComposer,
}) => i3.$ContainerOrderingComposer(
$db: $db,
$table: i7.ReadDatabaseContainer(
$table: i8.ReadDatabaseContainer(
$db,
).resultSet<i3.Container>('container'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
@@ -590,6 +605,9 @@ class $TabAnnotationComposer extends i0.Composer<i0.GeneratedDatabase, i3.Tab> {
i0.GeneratedColumn<String> get id =>
$composableBuilder(column: $table.id, builder: (column) => column);
i0.GeneratedColumnWithTypeConverter<i6.TabSource, int> get source =>
$composableBuilder(column: $table.source, builder: (column) => column);
i0.GeneratedColumn<String> get parentId =>
$composableBuilder(column: $table.parentId, builder: (column) => column);
@@ -637,7 +655,7 @@ class $TabAnnotationComposer extends i0.Composer<i0.GeneratedDatabase, i3.Tab> {
final i3.$ContainerAnnotationComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.containerId,
referencedTable: i7.ReadDatabaseContainer(
referencedTable: i8.ReadDatabaseContainer(
$db,
).resultSet<i3.Container>('container'),
getReferencedColumn: (t) => t.id,
@@ -648,7 +666,7 @@ class $TabAnnotationComposer extends i0.Composer<i0.GeneratedDatabase, i3.Tab> {
$removeJoinBuilderFromRootComposer,
}) => i3.$ContainerAnnotationComposer(
$db: $db,
$table: i7.ReadDatabaseContainer(
$table: i8.ReadDatabaseContainer(
$db,
).resultSet<i3.Container>('container'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
@@ -690,6 +708,7 @@ class $TabTableManager
updateCompanionCallback:
({
i0.Value<String> id = const i0.Value.absent(),
i0.Value<i6.TabSource> source = const i0.Value.absent(),
i0.Value<String?> parentId = const i0.Value.absent(),
i0.Value<String?> containerId = const i0.Value.absent(),
i0.Value<String> orderKey = const i0.Value.absent(),
@@ -707,6 +726,7 @@ class $TabTableManager
i0.Value<int> rowid = const i0.Value.absent(),
}) => i3.TabCompanion(
id: id,
source: source,
parentId: parentId,
containerId: containerId,
orderKey: orderKey,
@@ -724,6 +744,7 @@ class $TabTableManager
createCompanionCallback:
({
required String id,
required i6.TabSource source,
i0.Value<String?> parentId = const i0.Value.absent(),
i0.Value<String?> containerId = const i0.Value.absent(),
required String orderKey,
@@ -741,6 +762,7 @@ class $TabTableManager
i0.Value<int> rowid = const i0.Value.absent(),
}) => i3.TabCompanion.insert(
id: id,
source: source,
parentId: parentId,
containerId: containerId,
orderKey: orderKey,
@@ -1196,6 +1218,15 @@ class Tab extends i0.Table with i0.TableInfo<Tab, i3.TabData> {
requiredDuringInsert: true,
$customConstraints: 'PRIMARY KEY NOT NULL',
);
late final i0.GeneratedColumnWithTypeConverter<i6.TabSource, int> source =
i0.GeneratedColumn<int>(
'source',
aliasedName,
false,
type: i0.DriftSqlType.int,
requiredDuringInsert: true,
$customConstraints: 'NOT NULL',
).withConverter<i6.TabSource>(i3.Tab.$convertersource);
late final i0.GeneratedColumn<String> parentId = i0.GeneratedColumn<String>(
'parent_id',
aliasedName,
@@ -1303,6 +1334,7 @@ class Tab extends i0.Table with i0.TableInfo<Tab, i3.TabData> {
@override
List<i0.GeneratedColumn> get $columns => [
id,
source,
parentId,
containerId,
orderKey,
@@ -1331,6 +1363,12 @@ class Tab extends i0.Table with i0.TableInfo<Tab, i3.TabData> {
i0.DriftSqlType.string,
data['${effectivePrefix}id'],
)!,
source: i3.Tab.$convertersource.fromSql(
attachedDatabase.typeMapping.read(
i0.DriftSqlType.int,
data['${effectivePrefix}source'],
)!,
),
parentId: attachedDatabase.typeMapping.read(
i0.DriftSqlType.string,
data['${effectivePrefix}parent_id'],
@@ -1389,14 +1427,17 @@ class Tab extends i0.Table with i0.TableInfo<Tab, i3.TabData> {
return Tab(attachedDatabase, alias);
}
static i0.JsonTypeConverter2<i6.TabSource, int, int> $convertersource =
const i0.EnumIndexConverter<i6.TabSource>(i6.TabSource.values);
static i0.TypeConverter<Uri?, String?> $converterurl =
const i6.UriConverterNullable();
const i7.UriConverterNullable();
@override
bool get dontWriteConstraints => true;
}
class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
final String id;
final i6.TabSource source;
final String? parentId;
final String? containerId;
final String orderKey;
@@ -1411,6 +1452,7 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
final DateTime timestamp;
const TabData({
required this.id,
required this.source,
this.parentId,
this.containerId,
required this.orderKey,
@@ -1428,6 +1470,9 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{};
map['id'] = i0.Variable<String>(id);
{
map['source'] = i0.Variable<int>(i3.Tab.$convertersource.toSql(source));
}
if (!nullToAbsent || parentId != null) {
map['parent_id'] = i0.Variable<String>(parentId);
}
@@ -1474,6 +1519,9 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return TabData(
id: serializer.fromJson<String>(json['id']),
source: i3.Tab.$convertersource.fromJson(
serializer.fromJson<int>(json['source']),
),
parentId: serializer.fromJson<String?>(json['parent_id']),
containerId: serializer.fromJson<String?>(json['container_id']),
orderKey: serializer.fromJson<String>(json['order_key']),
@@ -1503,6 +1551,7 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<String>(id),
'source': serializer.toJson<int>(i3.Tab.$convertersource.toJson(source)),
'parent_id': serializer.toJson<String?>(parentId),
'container_id': serializer.toJson<String?>(containerId),
'order_key': serializer.toJson<String>(orderKey),
@@ -1524,6 +1573,7 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
i3.TabData copyWith({
String? id,
i6.TabSource? source,
i0.Value<String?> parentId = const i0.Value.absent(),
i0.Value<String?> containerId = const i0.Value.absent(),
String? orderKey,
@@ -1538,6 +1588,7 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
DateTime? timestamp,
}) => i3.TabData(
id: id ?? this.id,
source: source ?? this.source,
parentId: parentId.present ? parentId.value : this.parentId,
containerId: containerId.present ? containerId.value : this.containerId,
orderKey: orderKey ?? this.orderKey,
@@ -1564,6 +1615,7 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
TabData copyWithCompanion(i3.TabCompanion data) {
return TabData(
id: data.id.present ? data.id.value : this.id,
source: data.source.present ? data.source.value : this.source,
parentId: data.parentId.present ? data.parentId.value : this.parentId,
containerId: data.containerId.present
? data.containerId.value
@@ -1595,6 +1647,7 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
String toString() {
return (StringBuffer('TabData(')
..write('id: $id, ')
..write('source: $source, ')
..write('parentId: $parentId, ')
..write('containerId: $containerId, ')
..write('orderKey: $orderKey, ')
@@ -1614,6 +1667,7 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
@override
int get hashCode => Object.hash(
id,
source,
parentId,
containerId,
orderKey,
@@ -1632,6 +1686,7 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
identical(this, other) ||
(other is i3.TabData &&
other.id == this.id &&
other.source == this.source &&
other.parentId == this.parentId &&
other.containerId == this.containerId &&
other.orderKey == this.orderKey &&
@@ -1648,6 +1703,7 @@ class TabData extends i0.DataClass implements i0.Insertable<i3.TabData> {
class TabCompanion extends i0.UpdateCompanion<i3.TabData> {
final i0.Value<String> id;
final i0.Value<i6.TabSource> source;
final i0.Value<String?> parentId;
final i0.Value<String?> containerId;
final i0.Value<String> orderKey;
@@ -1663,6 +1719,7 @@ class TabCompanion extends i0.UpdateCompanion<i3.TabData> {
final i0.Value<int> rowid;
const TabCompanion({
this.id = const i0.Value.absent(),
this.source = const i0.Value.absent(),
this.parentId = const i0.Value.absent(),
this.containerId = const i0.Value.absent(),
this.orderKey = const i0.Value.absent(),
@@ -1679,6 +1736,7 @@ class TabCompanion extends i0.UpdateCompanion<i3.TabData> {
});
TabCompanion.insert({
required String id,
required i6.TabSource source,
this.parentId = const i0.Value.absent(),
this.containerId = const i0.Value.absent(),
required String orderKey,
@@ -1693,10 +1751,12 @@ class TabCompanion extends i0.UpdateCompanion<i3.TabData> {
required DateTime timestamp,
this.rowid = const i0.Value.absent(),
}) : id = i0.Value(id),
source = i0.Value(source),
orderKey = i0.Value(orderKey),
timestamp = i0.Value(timestamp);
static i0.Insertable<i3.TabData> custom({
i0.Expression<String>? id,
i0.Expression<int>? source,
i0.Expression<String>? parentId,
i0.Expression<String>? containerId,
i0.Expression<String>? orderKey,
@@ -1713,6 +1773,7 @@ class TabCompanion extends i0.UpdateCompanion<i3.TabData> {
}) {
return i0.RawValuesInsertable({
if (id != null) 'id': id,
if (source != null) 'source': source,
if (parentId != null) 'parent_id': parentId,
if (containerId != null) 'container_id': containerId,
if (orderKey != null) 'order_key': orderKey,
@@ -1735,6 +1796,7 @@ class TabCompanion extends i0.UpdateCompanion<i3.TabData> {
i3.TabCompanion copyWith({
i0.Value<String>? id,
i0.Value<i6.TabSource>? source,
i0.Value<String?>? parentId,
i0.Value<String?>? containerId,
i0.Value<String>? orderKey,
@@ -1751,6 +1813,7 @@ class TabCompanion extends i0.UpdateCompanion<i3.TabData> {
}) {
return i3.TabCompanion(
id: id ?? this.id,
source: source ?? this.source,
parentId: parentId ?? this.parentId,
containerId: containerId ?? this.containerId,
orderKey: orderKey ?? this.orderKey,
@@ -1775,6 +1838,11 @@ class TabCompanion extends i0.UpdateCompanion<i3.TabData> {
if (id.present) {
map['id'] = i0.Variable<String>(id.value);
}
if (source.present) {
map['source'] = i0.Variable<int>(
i3.Tab.$convertersource.toSql(source.value),
);
}
if (parentId.present) {
map['parent_id'] = i0.Variable<String>(parentId.value);
}
@@ -1829,6 +1897,7 @@ class TabCompanion extends i0.UpdateCompanion<i3.TabData> {
String toString() {
return (StringBuffer('TabCompanion(')
..write('id: $id, ')
..write('source: $source, ')
..write('parentId: $parentId, ')
..write('containerId: $containerId, ')
..write('orderKey: $orderKey, ')
@@ -2142,7 +2211,7 @@ i0.Trigger get tabAfterUpdate => i0.Trigger(
'tab_after_update',
);
class DefinitionsDrift extends i7.ModularAccessor {
class DefinitionsDrift extends i8.ModularAccessor {
DefinitionsDrift(i0.GeneratedDatabase db) : super(db);
Future<int> optimizeFtsIndex() {
return customInsert(
@@ -2215,13 +2284,13 @@ class DefinitionsDrift extends i7.ModularAccessor {
).map((i0.QueryRow row) => row.read<String>('_c0'));
}
i0.Selectable<i8.TabQueryResult> queryTabsBasic({required String query}) {
i0.Selectable<i9.TabQueryResult> queryTabsBasic({required String query}) {
return customSelect(
'WITH weights AS (SELECT 10.0 AS title_weight, 5.0 AS url_weight) SELECT t.id, t.container_id, t.is_private, t.title, CAST(t.url AS TEXT) AS url, t.url AS clean_url, bm25(tab_fts, weights.title_weight, weights.url_weight) AS weighted_rank FROM tab_fts AS fts INNER JOIN tab AS t ON t."rowid" = fts."rowid" CROSS JOIN weights WHERE fts.title LIKE ?1 OR fts.url LIKE ?1 ORDER BY weighted_rank ASC, t.timestamp DESC',
variables: [i0.Variable<String>(query)],
readsFrom: {tab, tabFts},
).map(
(i0.QueryRow row) => i8.TabQueryResult(
(i0.QueryRow row) => i9.TabQueryResult(
id: row.read<String>('id'),
containerId: row.readNullable<String>('container_id'),
isPrivate: row.readNullable<bool>('is_private'),
@@ -2235,7 +2304,7 @@ class DefinitionsDrift extends i7.ModularAccessor {
);
}
i0.Selectable<i8.TabQueryResult> queryTabsFullContent({
i0.Selectable<i9.TabQueryResult> queryTabsFullContent({
required String beforeMatch,
required String afterMatch,
required String ellipsis,
@@ -2253,7 +2322,7 @@ class DefinitionsDrift extends i7.ModularAccessor {
],
readsFrom: {tab, tabFts},
).map(
(i0.QueryRow row) => i8.TabQueryResult(
(i0.QueryRow row) => i9.TabQueryResult(
id: row.read<String>('id'),
containerId: row.readNullable<String>('container_id'),
isPrivate: row.readNullable<bool>('is_private'),
@@ -2369,13 +2438,13 @@ class DefinitionsDrift extends i7.ModularAccessor {
).map((i0.QueryRow row) => row.read<String>('id'));
}
i0.Selectable<i9.SiteAssignment> allAssignedSites() {
i0.Selectable<i10.SiteAssignment> allAssignedSites() {
return customSelect(
'SELECT container.id, COALESCE(container.metadata ->> \'\$.contextualIdentity\', \'general\') AS contextualIdentity, value AS assigned_site FROM container CROSS JOIN json_each(container.metadata, \'\$.assignedSites\')WHERE value IS NOT NULL',
variables: [],
readsFrom: {container},
).map(
(i0.QueryRow row) => i9.SiteAssignment(
(i0.QueryRow row) => i10.SiteAssignment(
id: row.read<String>('id'),
contextualIdentity: row.read<String>('contextualIdentity'),
assignedSite: row.readNullable<String>('assigned_site'),
@@ -2391,14 +2460,14 @@ class DefinitionsDrift extends i7.ModularAccessor {
).map((i0.QueryRow row) => row.readNullable<String>('contextual_identity'));
}
i3.TabFts get tabFts => i7.ReadDatabaseContainer(
i3.TabFts get tabFts => i8.ReadDatabaseContainer(
attachedDatabase,
).resultSet<i3.TabFts>('tab_fts');
i3.Container get container => i7.ReadDatabaseContainer(
i3.Container get container => i8.ReadDatabaseContainer(
attachedDatabase,
).resultSet<i3.Container>('container');
i3.Tab get tab =>
i7.ReadDatabaseContainer(attachedDatabase).resultSet<i3.Tab>('tab');
i8.ReadDatabaseContainer(attachedDatabase).resultSet<i3.Tab>('tab');
}
class TabTreesResult {
@@ -0,0 +1 @@
enum TabSource { syncEvent, addedEvent, manual }
@@ -123,13 +123,15 @@ class SelectedContainer extends _$SelectedContainer {
selectedTabProvider,
(previous, next) async {
if (next != null) {
final tabContainerId = await ref
final tabData = await ref
.read(tabDataRepositoryProvider.notifier)
.getTabContainerId(next);
.getTabDataById(next);
if (ref.mounted && tabContainerId != stateOrNull) {
if (tabContainerId != null) {
await setContainerId(tabContainerId);
if (ref.mounted &&
tabData != null &&
tabData.containerId != stateOrNull) {
if (tabData.containerId != null) {
await setContainerId(tabData.containerId!);
} else {
clearContainer();
}
@@ -41,7 +41,7 @@ final class SelectedContainerProvider
}
}
String _$selectedContainerHash() => r'35a8fc409e563758156a197bb8b114387d31b389';
String _$selectedContainerHash() => r'e1d20f0c2e7764e82937ba486de52c92184c0e4a';
abstract class _$SelectedContainer extends $Notifier<String?> {
String? build();
@@ -64,6 +64,7 @@ class TabDataRepository extends _$TabDataRepository {
private: tabState.isPrivate,
container: Value(targetContainer),
parentId: tabState.parentId,
selectTab: false,
);
}
}
@@ -95,6 +96,7 @@ class TabDataRepository extends _$TabDataRepository {
private: tabState.isPrivate,
container: const Value(null),
parentId: tabState.parentId,
selectTab: false,
);
}
}
@@ -127,7 +129,7 @@ class TabDataRepository extends _$TabDataRepository {
return tabIds.length;
}
Future<int> closeContainerTabs(
Future<List<String>> closeContainerTabs(
String? containerId, {
bool includeRegular = true,
bool includePrivate = true,
@@ -146,7 +148,7 @@ class TabDataRepository extends _$TabDataRepository {
await ref.read(tabRepositoryProvider.notifier).closeTabs(tabIds);
}
return tabIds.length;
return tabIds;
}
Future<int> closeAllTabsByHost(String? containerId, String host) async {
@@ -41,7 +41,7 @@ final class TabDataRepositoryProvider
}
}
String _$tabDataRepositoryHash() => r'eab2a5040541fec955ffe23947cbb57952d29c6c';
String _$tabDataRepositoryHash() => r'2c2ba950834fac4be9ef6c7042e6ed5a76577b1c';
abstract class _$TabDataRepository extends $Notifier<void> {
void build();
@@ -149,6 +149,7 @@ class OnboardingScreen extends HookConsumerWidget {
url: ref.read(docsUriProvider),
private: false,
container: const Value(null),
selectTab: true,
);
ref.invalidate(routerProvider);
@@ -207,6 +207,7 @@ class FeedArticleScreen extends HookConsumerWidget {
url: articleLink.uri,
private: isPrivate,
container: const Value(null),
selectTab: true,
);
if (context.mounted) {
@@ -251,7 +252,11 @@ class FeedArticleScreen extends HookConsumerWidget {
await ref
.read(tabRepositoryProvider.notifier)
.addTab(url: url, private: isPrivate);
.addTab(
url: url,
private: isPrivate,
selectTab: true,
);
if (context.mounted) {
showTabOpenedMessage(
+4 -1
View File
@@ -5,6 +5,7 @@ import 'package:drift/drift.dart';
import 'package:drift/internal/migrations.dart';
import 'schema_v2.dart' as v2;
import 'schema_v3.dart' as v3;
import 'schema_v4.dart' as v4;
class GeneratedHelper implements SchemaInstantiationHelper {
@override
@@ -14,10 +15,12 @@ class GeneratedHelper implements SchemaInstantiationHelper {
return v2.DatabaseAtV2(db);
case 3:
return v3.DatabaseAtV3(db);
case 4:
return v4.DatabaseAtV4(db);
default:
throw MissingSchemaException(version, versions);
}
}
static const versions = const [2, 3];
static const versions = const [2, 3, 4];
}
File diff suppressed because it is too large Load Diff