better handling of default/seeded sites
This commit is contained in:
+1
-1
@@ -590,7 +590,7 @@ class _PinTopSiteTile extends HookConsumerWidget {
|
|||||||
() => url != null
|
() => url != null
|
||||||
? ref
|
? ref
|
||||||
.read(topSiteRepositoryProvider.notifier)
|
.read(topSiteRepositoryProvider.notifier)
|
||||||
.isPersistedTopSiteUrl(url)
|
.isPinnedTopSiteUrl(url)
|
||||||
: Future.value(false),
|
: Future.value(false),
|
||||||
[url],
|
[url],
|
||||||
);
|
);
|
||||||
|
|||||||
+87
-19
@@ -19,6 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'
|
||||||
|
show MdiIcons;
|
||||||
import 'package:flutter_reorderable_grid_view/widgets/custom_draggable.dart';
|
import 'package:flutter_reorderable_grid_view/widgets/custom_draggable.dart';
|
||||||
import 'package:flutter_reorderable_grid_view/widgets/reorderable_builder.dart';
|
import 'package:flutter_reorderable_grid_view/widgets/reorderable_builder.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@@ -221,8 +223,7 @@ class _ReorderableTopSitesGrid extends HookConsumerWidget {
|
|||||||
if (newIndex < 0 || newIndex > localItems.value.length) return;
|
if (newIndex < 0 || newIndex > localItems.value.length) return;
|
||||||
|
|
||||||
final items = localItems.value.toList();
|
final items = localItems.value.toList();
|
||||||
final movedItem = items.removeAt(oldIndex);
|
var movedItem = items.removeAt(oldIndex);
|
||||||
if (movedItem.id == null) return;
|
|
||||||
|
|
||||||
final targetIndex = newIndex.clamp(0, items.length);
|
final targetIndex = newIndex.clamp(0, items.length);
|
||||||
|
|
||||||
@@ -234,6 +235,41 @@ class _ReorderableTopSitesGrid extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
final repo = ref.read(topSiteRepositoryProvider.notifier);
|
final repo = ref.read(topSiteRepositoryProvider.notifier);
|
||||||
|
|
||||||
|
// Auto-persist default sites that don't have an ID yet
|
||||||
|
if (movedItem.id == null && movedItem.isDefault) {
|
||||||
|
final id = await repo.ensureDefaultPersisted(
|
||||||
|
title: movedItem.title,
|
||||||
|
url: movedItem.url,
|
||||||
|
);
|
||||||
|
movedItem = TopSiteItem(
|
||||||
|
id: id,
|
||||||
|
title: movedItem.title,
|
||||||
|
url: movedItem.url,
|
||||||
|
source: movedItem.source,
|
||||||
|
orderKey: movedItem.orderKey,
|
||||||
|
createdAt: movedItem.createdAt,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (movedItem.id == null) return;
|
||||||
|
|
||||||
|
// Ensure neighbors are persisted too
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
if (items[i].id == null && items[i].isDefault) {
|
||||||
|
final id = await repo.ensureDefaultPersisted(
|
||||||
|
title: items[i].title,
|
||||||
|
url: items[i].url,
|
||||||
|
);
|
||||||
|
items[i] = TopSiteItem(
|
||||||
|
id: id,
|
||||||
|
title: items[i].title,
|
||||||
|
url: items[i].url,
|
||||||
|
source: items[i].source,
|
||||||
|
orderKey: items[i].orderKey,
|
||||||
|
createdAt: items[i].createdAt,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final String key;
|
final String key;
|
||||||
if (targetIndex <= 0) {
|
if (targetIndex <= 0) {
|
||||||
key = await repo.getLeadingOrderKey();
|
key = await repo.getLeadingOrderKey();
|
||||||
@@ -483,10 +519,31 @@ class _TopSiteGridTileState extends State<_TopSiteGridTile> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (widget.item.source == TopSiteSource.defaultSite)
|
||||||
|
Positioned(
|
||||||
|
top: 4,
|
||||||
|
right: 4,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: colorScheme.primaryContainer,
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(10.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(3.0),
|
||||||
|
child: Icon(
|
||||||
|
MdiIcons.crown,
|
||||||
|
size: 12,
|
||||||
|
color: colorScheme.onPrimaryContainer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
if (widget.showDragHandle)
|
if (widget.showDragHandle)
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 2,
|
top: 2,
|
||||||
right: 2,
|
left: 2,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.drag_indicator,
|
Icons.drag_indicator,
|
||||||
size: 16,
|
size: 16,
|
||||||
@@ -525,8 +582,6 @@ Future<void> _editItem(
|
|||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
TopSiteItem item,
|
TopSiteItem item,
|
||||||
) async {
|
) async {
|
||||||
if (item.id == null) return;
|
|
||||||
|
|
||||||
final result = await showEditTopSiteDialog(
|
final result = await showEditTopSiteDialog(
|
||||||
context,
|
context,
|
||||||
initialTitle: item.title,
|
initialTitle: item.title,
|
||||||
@@ -536,13 +591,25 @@ Future<void> _editItem(
|
|||||||
if (result == null || !context.mounted) return;
|
if (result == null || !context.mounted) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ref
|
final repo = ref.read(topSiteRepositoryProvider.notifier);
|
||||||
.read(topSiteRepositoryProvider.notifier)
|
|
||||||
.updatePersistedSite(
|
// If the item has no ID (unpersisted default), persist it first
|
||||||
id: item.id!,
|
var id = item.id;
|
||||||
title: result.title,
|
if (id == null && item.isDefault) {
|
||||||
url: result.url,
|
id = await repo.ensureDefaultPersisted(
|
||||||
);
|
title: item.title,
|
||||||
|
url: item.url,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (id == null) return;
|
||||||
|
|
||||||
|
// If the URL changed, hide the original so it doesn't reappear
|
||||||
|
// from the const defaults list.
|
||||||
|
if (item.url != result.url) {
|
||||||
|
await repo.hideDefaultSite(item.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
await repo.updateSite(id: id, title: result.title, url: result.url);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ui_helper.showInfoMessage(context, 'Top site updated');
|
ui_helper.showInfoMessage(context, 'Top site updated');
|
||||||
}
|
}
|
||||||
@@ -558,12 +625,15 @@ Future<void> _removeItem(
|
|||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
TopSiteItem item,
|
TopSiteItem item,
|
||||||
) async {
|
) async {
|
||||||
if (item.id == null) return;
|
final repo = ref.read(topSiteRepositoryProvider.notifier);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ref
|
if (item.id != null) {
|
||||||
.read(topSiteRepositoryProvider.notifier)
|
await repo.removeSite(item.id!);
|
||||||
.removePersistedSite(item.id!);
|
}
|
||||||
|
// Hide the URL so it doesn't reappear from the const defaults list
|
||||||
|
await repo.hideDefaultSite(item.url);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ui_helper.showInfoMessage(
|
ui_helper.showInfoMessage(
|
||||||
context,
|
context,
|
||||||
@@ -572,9 +642,7 @@ Future<void> _removeItem(
|
|||||||
label: 'Undo',
|
label: 'Undo',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
try {
|
try {
|
||||||
await ref
|
await repo.addPinnedSite(title: item.title, url: item.url);
|
||||||
.read(topSiteRepositoryProvider.notifier)
|
|
||||||
.addPinnedSite(title: item.title, url: item.url);
|
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
+24
-16
@@ -18,29 +18,37 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/daos/seed_state.drift.dart';
|
import 'package:weblibre/extensions/uri.dart';
|
||||||
|
import 'package:weblibre/features/geckoview/features/top_sites/data/database/daos/hidden_top_site.drift.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.dart';
|
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/definitions.drift.dart';
|
import 'package:weblibre/features/geckoview/features/top_sites/data/database/definitions.drift.dart';
|
||||||
|
|
||||||
@DriftAccessor()
|
@DriftAccessor()
|
||||||
class TopSiteSeedStateDao extends DatabaseAccessor<TopSiteDatabase>
|
class HiddenTopSiteDao extends DatabaseAccessor<TopSiteDatabase>
|
||||||
with $TopSiteSeedStateDaoMixin {
|
with $HiddenTopSiteDaoMixin {
|
||||||
TopSiteSeedStateDao(super.db);
|
HiddenTopSiteDao(super.db);
|
||||||
|
|
||||||
Future<bool> hasSeed(String seedId) async {
|
Future<Set<String>> getHiddenUrls() async {
|
||||||
final row =
|
final rows = await db.hiddenTopSite.select().get();
|
||||||
await (db.topSiteSeedState.select()
|
return rows.map((r) => r.url.normalized.toString()).toSet();
|
||||||
..where((t) => t.seedId.equals(seedId)))
|
|
||||||
.getSingleOrNull();
|
|
||||||
return row != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> markSeedApplied(String seedId) {
|
Stream<Set<String>> watchHiddenUrls() {
|
||||||
return db.topSiteSeedState.insertOne(
|
return db.hiddenTopSite.select().watch().map(
|
||||||
TopSiteSeedStateCompanion.insert(
|
(rows) => rows.map((r) => r.url.normalized.toString()).toSet(),
|
||||||
seedId: seedId,
|
|
||||||
appliedAt: DateTime.now(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> hideUrl(Uri url) {
|
||||||
|
return db.hiddenTopSite.insertOne(
|
||||||
|
HiddenTopSiteCompanion.insert(url: url.normalized),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> unhideUrl(Uri url) {
|
||||||
|
return (db.hiddenTopSite.delete()
|
||||||
|
..where((t) => t.url.equalsValue(url.normalized)))
|
||||||
|
.go();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// dart format width=80
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:drift/drift.dart' as i0;
|
||||||
|
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.dart'
|
||||||
|
as i1;
|
||||||
|
|
||||||
|
mixin $HiddenTopSiteDaoMixin on i0.DatabaseAccessor<i1.TopSiteDatabase> {
|
||||||
|
HiddenTopSiteDaoManager get managers => HiddenTopSiteDaoManager(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class HiddenTopSiteDaoManager {
|
||||||
|
final $HiddenTopSiteDaoMixin _db;
|
||||||
|
HiddenTopSiteDaoManager(this._db);
|
||||||
|
}
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
// dart format width=80
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
import 'package:drift/drift.dart' as i0;
|
|
||||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.dart'
|
|
||||||
as i1;
|
|
||||||
|
|
||||||
mixin $TopSiteSeedStateDaoMixin on i0.DatabaseAccessor<i1.TopSiteDatabase> {
|
|
||||||
TopSiteSeedStateDaoManager get managers => TopSiteSeedStateDaoManager(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
class TopSiteSeedStateDaoManager {
|
|
||||||
final $TopSiteSeedStateDaoMixin _db;
|
|
||||||
TopSiteSeedStateDaoManager(this._db);
|
|
||||||
}
|
|
||||||
@@ -29,36 +29,30 @@ class TopSiteDao extends DatabaseAccessor<TopSiteDatabase>
|
|||||||
with $TopSiteDaoMixin {
|
with $TopSiteDaoMixin {
|
||||||
TopSiteDao(super.db);
|
TopSiteDao(super.db);
|
||||||
|
|
||||||
Selectable<TopSiteData> selectPersistedTopSites() {
|
Selectable<TopSiteData> selectAllTopSites() {
|
||||||
return db.topSite.select()..orderBy([(t) => OrderingTerm.asc(t.orderKey)]);
|
return db.topSite.select()..orderBy([(t) => OrderingTerm.asc(t.orderKey)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<TopSiteData>> getPersistedTopSites() {
|
Future<List<TopSiteData>> getAllTopSites() {
|
||||||
return selectPersistedTopSites().get();
|
return selectAllTopSites().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<TopSiteData?> getPersistedTopSiteById(String id) {
|
Future<TopSiteData?> getTopSiteById(String id) {
|
||||||
return (db.topSite.select()..where((t) => t.id.equals(id)))
|
return (db.topSite.select()..where((t) => t.id.equals(id)))
|
||||||
.getSingleOrNull();
|
.getSingleOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<TopSiteData?> getPersistedTopSiteByUrl(Uri url) {
|
Future<TopSiteData?> getTopSiteByUrl(Uri url) {
|
||||||
return (db.topSite.select()
|
return (db.topSite.select()
|
||||||
..where((t) => t.url.equalsValue(url.normalized)))
|
..where((t) => t.url.equalsValue(url.normalized)))
|
||||||
.getSingleOrNull();
|
.getSingleOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> countPersistedSites() async {
|
Future<int> insertSite({
|
||||||
final count = db.topSite.id.count();
|
|
||||||
final query = db.selectOnly(db.topSite)..addColumns([count]);
|
|
||||||
final result = await query.getSingle();
|
|
||||||
return result.read(count)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int> insertPinnedSite({
|
|
||||||
required String id,
|
required String id,
|
||||||
required String title,
|
required String title,
|
||||||
required Uri url,
|
required Uri url,
|
||||||
|
required StoredTopSiteSource source,
|
||||||
required String orderKey,
|
required String orderKey,
|
||||||
}) {
|
}) {
|
||||||
return db.topSite.insertOne(
|
return db.topSite.insertOne(
|
||||||
@@ -66,20 +60,14 @@ class TopSiteDao extends DatabaseAccessor<TopSiteDatabase>
|
|||||||
id: id,
|
id: id,
|
||||||
title: title,
|
title: title,
|
||||||
url: url.normalized,
|
url: url.normalized,
|
||||||
source: StoredTopSiteSource.pinned,
|
source: source,
|
||||||
orderKey: orderKey,
|
orderKey: orderKey,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> insertSeededSites(List<TopSiteCompanion> rows) {
|
Future<int> updateSite(
|
||||||
return db.batch((batch) {
|
|
||||||
batch.insertAll(db.topSite, rows);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int> updatePersistedSite(
|
|
||||||
String id, {
|
String id, {
|
||||||
required String title,
|
required String title,
|
||||||
required Uri url,
|
required Uri url,
|
||||||
@@ -89,7 +77,7 @@ class TopSiteDao extends DatabaseAccessor<TopSiteDatabase>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> deletePersistedSite(String id) {
|
Future<int> deleteSite(String id) {
|
||||||
return (db.topSite.delete()..where((t) => t.id.equals(id))).go();
|
return (db.topSite.delete()..where((t) => t.id.equals(id))).go();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,13 +20,13 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:drift_dev/api/migrations_native.dart';
|
import 'package:drift_dev/api/migrations_native.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/daos/seed_state.dart';
|
import 'package:weblibre/features/geckoview/features/top_sites/data/database/daos/hidden_top_site.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/daos/top_site.dart';
|
import 'package:weblibre/features/geckoview/features/top_sites/data/database/daos/top_site.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.drift.dart';
|
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.drift.dart';
|
||||||
|
|
||||||
@DriftDatabase(
|
@DriftDatabase(
|
||||||
include: {'definitions.drift'},
|
include: {'definitions.drift'},
|
||||||
daos: [TopSiteDao, TopSiteSeedStateDao],
|
daos: [TopSiteDao, HiddenTopSiteDao],
|
||||||
)
|
)
|
||||||
class TopSiteDatabase extends $TopSiteDatabase {
|
class TopSiteDatabase extends $TopSiteDatabase {
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'package:weblibre/features/geckoview/features/top_sites/data/database/dao
|
|||||||
as i2;
|
as i2;
|
||||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.dart'
|
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.dart'
|
||||||
as i3;
|
as i3;
|
||||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/daos/seed_state.dart'
|
import 'package:weblibre/features/geckoview/features/top_sites/data/database/daos/hidden_top_site.dart'
|
||||||
as i4;
|
as i4;
|
||||||
import 'package:drift/internal/modular.dart' as i5;
|
import 'package:drift/internal/modular.dart' as i5;
|
||||||
import 'package:sqlite3/common.dart' as i6;
|
import 'package:sqlite3/common.dart' as i6;
|
||||||
@@ -16,12 +16,13 @@ abstract class $TopSiteDatabase extends i0.GeneratedDatabase {
|
|||||||
$TopSiteDatabase(i0.QueryExecutor e) : super(e);
|
$TopSiteDatabase(i0.QueryExecutor e) : super(e);
|
||||||
$TopSiteDatabaseManager get managers => $TopSiteDatabaseManager(this);
|
$TopSiteDatabaseManager get managers => $TopSiteDatabaseManager(this);
|
||||||
late final i1.TopSite topSite = i1.TopSite(this);
|
late final i1.TopSite topSite = i1.TopSite(this);
|
||||||
late final i1.TopSiteSeedState topSiteSeedState = i1.TopSiteSeedState(this);
|
late final i1.HiddenTopSite hiddenTopSite = i1.HiddenTopSite(this);
|
||||||
late final i2.TopSiteDao topSiteDao = i2.TopSiteDao(
|
late final i2.TopSiteDao topSiteDao = i2.TopSiteDao(
|
||||||
this as i3.TopSiteDatabase,
|
this as i3.TopSiteDatabase,
|
||||||
);
|
);
|
||||||
late final i4.TopSiteSeedStateDao topSiteSeedStateDao =
|
late final i4.HiddenTopSiteDao hiddenTopSiteDao = i4.HiddenTopSiteDao(
|
||||||
i4.TopSiteSeedStateDao(this as i3.TopSiteDatabase);
|
this as i3.TopSiteDatabase,
|
||||||
|
);
|
||||||
i1.DefinitionsDrift get definitionsDrift => i5.ReadDatabaseContainer(
|
i1.DefinitionsDrift get definitionsDrift => i5.ReadDatabaseContainer(
|
||||||
this,
|
this,
|
||||||
).accessor<i1.DefinitionsDrift>(i1.DefinitionsDrift.new);
|
).accessor<i1.DefinitionsDrift>(i1.DefinitionsDrift.new);
|
||||||
@@ -32,7 +33,7 @@ abstract class $TopSiteDatabase extends i0.GeneratedDatabase {
|
|||||||
List<i0.DatabaseSchemaEntity> get allSchemaEntities => [
|
List<i0.DatabaseSchemaEntity> get allSchemaEntities => [
|
||||||
topSite,
|
topSite,
|
||||||
i1.idxTopSiteOrderKey,
|
i1.idxTopSiteOrderKey,
|
||||||
topSiteSeedState,
|
hiddenTopSite,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,8 +42,8 @@ class $TopSiteDatabaseManager {
|
|||||||
$TopSiteDatabaseManager(this._db);
|
$TopSiteDatabaseManager(this._db);
|
||||||
i1.$TopSiteTableManager get topSite =>
|
i1.$TopSiteTableManager get topSite =>
|
||||||
i1.$TopSiteTableManager(_db, _db.topSite);
|
i1.$TopSiteTableManager(_db, _db.topSite);
|
||||||
i1.$TopSiteSeedStateTableManager get topSiteSeedState =>
|
i1.$HiddenTopSiteTableManager get hiddenTopSite =>
|
||||||
i1.$TopSiteSeedStateTableManager(_db, _db.topSiteSeedState);
|
i1.$HiddenTopSiteTableManager(_db, _db.hiddenTopSite);
|
||||||
}
|
}
|
||||||
|
|
||||||
extension DefineFunctions on i6.CommonDatabase {
|
extension DefineFunctions on i6.CommonDatabase {
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ CREATE TABLE top_site (
|
|||||||
|
|
||||||
CREATE INDEX idx_top_site_order_key ON top_site(order_key);
|
CREATE INDEX idx_top_site_order_key ON top_site(order_key);
|
||||||
|
|
||||||
CREATE TABLE top_site_seed_state (
|
CREATE TABLE hidden_top_site (
|
||||||
seed_id TEXT PRIMARY KEY NOT NULL,
|
url TEXT PRIMARY KEY NOT NULL MAPPED BY `const UriConverter()`
|
||||||
applied_at DATETIME NOT NULL
|
|
||||||
);
|
);
|
||||||
|
|
||||||
leadingOrderKey(:bucket AS INTEGER):
|
leadingOrderKey(:bucket AS INTEGER):
|
||||||
|
|||||||
+119
-184
@@ -234,130 +234,101 @@ typedef $TopSiteProcessedTableManager =
|
|||||||
i1.TopSiteData,
|
i1.TopSiteData,
|
||||||
i0.PrefetchHooks Function()
|
i0.PrefetchHooks Function()
|
||||||
>;
|
>;
|
||||||
typedef $TopSiteSeedStateCreateCompanionBuilder =
|
typedef $HiddenTopSiteCreateCompanionBuilder =
|
||||||
i1.TopSiteSeedStateCompanion Function({
|
i1.HiddenTopSiteCompanion Function({required Uri url, i0.Value<int> rowid});
|
||||||
required String seedId,
|
typedef $HiddenTopSiteUpdateCompanionBuilder =
|
||||||
required DateTime appliedAt,
|
i1.HiddenTopSiteCompanion Function({
|
||||||
i0.Value<int> rowid,
|
i0.Value<Uri> url,
|
||||||
});
|
|
||||||
typedef $TopSiteSeedStateUpdateCompanionBuilder =
|
|
||||||
i1.TopSiteSeedStateCompanion Function({
|
|
||||||
i0.Value<String> seedId,
|
|
||||||
i0.Value<DateTime> appliedAt,
|
|
||||||
i0.Value<int> rowid,
|
i0.Value<int> rowid,
|
||||||
});
|
});
|
||||||
|
|
||||||
class $TopSiteSeedStateFilterComposer
|
class $HiddenTopSiteFilterComposer
|
||||||
extends i0.Composer<i0.GeneratedDatabase, i1.TopSiteSeedState> {
|
extends i0.Composer<i0.GeneratedDatabase, i1.HiddenTopSite> {
|
||||||
$TopSiteSeedStateFilterComposer({
|
$HiddenTopSiteFilterComposer({
|
||||||
required super.$db,
|
required super.$db,
|
||||||
required super.$table,
|
required super.$table,
|
||||||
super.joinBuilder,
|
super.joinBuilder,
|
||||||
super.$addJoinBuilderToRootComposer,
|
super.$addJoinBuilderToRootComposer,
|
||||||
super.$removeJoinBuilderFromRootComposer,
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
});
|
});
|
||||||
i0.ColumnFilters<String> get seedId => $composableBuilder(
|
i0.ColumnWithTypeConverterFilters<Uri, Uri, String> get url =>
|
||||||
column: $table.seedId,
|
$composableBuilder(
|
||||||
builder: (column) => i0.ColumnFilters(column),
|
column: $table.url,
|
||||||
);
|
builder: (column) => i0.ColumnWithTypeConverterFilters(column),
|
||||||
|
);
|
||||||
i0.ColumnFilters<DateTime> get appliedAt => $composableBuilder(
|
|
||||||
column: $table.appliedAt,
|
|
||||||
builder: (column) => i0.ColumnFilters(column),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class $TopSiteSeedStateOrderingComposer
|
class $HiddenTopSiteOrderingComposer
|
||||||
extends i0.Composer<i0.GeneratedDatabase, i1.TopSiteSeedState> {
|
extends i0.Composer<i0.GeneratedDatabase, i1.HiddenTopSite> {
|
||||||
$TopSiteSeedStateOrderingComposer({
|
$HiddenTopSiteOrderingComposer({
|
||||||
required super.$db,
|
required super.$db,
|
||||||
required super.$table,
|
required super.$table,
|
||||||
super.joinBuilder,
|
super.joinBuilder,
|
||||||
super.$addJoinBuilderToRootComposer,
|
super.$addJoinBuilderToRootComposer,
|
||||||
super.$removeJoinBuilderFromRootComposer,
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
});
|
});
|
||||||
i0.ColumnOrderings<String> get seedId => $composableBuilder(
|
i0.ColumnOrderings<String> get url => $composableBuilder(
|
||||||
column: $table.seedId,
|
column: $table.url,
|
||||||
builder: (column) => i0.ColumnOrderings(column),
|
|
||||||
);
|
|
||||||
|
|
||||||
i0.ColumnOrderings<DateTime> get appliedAt => $composableBuilder(
|
|
||||||
column: $table.appliedAt,
|
|
||||||
builder: (column) => i0.ColumnOrderings(column),
|
builder: (column) => i0.ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $TopSiteSeedStateAnnotationComposer
|
class $HiddenTopSiteAnnotationComposer
|
||||||
extends i0.Composer<i0.GeneratedDatabase, i1.TopSiteSeedState> {
|
extends i0.Composer<i0.GeneratedDatabase, i1.HiddenTopSite> {
|
||||||
$TopSiteSeedStateAnnotationComposer({
|
$HiddenTopSiteAnnotationComposer({
|
||||||
required super.$db,
|
required super.$db,
|
||||||
required super.$table,
|
required super.$table,
|
||||||
super.joinBuilder,
|
super.joinBuilder,
|
||||||
super.$addJoinBuilderToRootComposer,
|
super.$addJoinBuilderToRootComposer,
|
||||||
super.$removeJoinBuilderFromRootComposer,
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
});
|
});
|
||||||
i0.GeneratedColumn<String> get seedId =>
|
i0.GeneratedColumnWithTypeConverter<Uri, String> get url =>
|
||||||
$composableBuilder(column: $table.seedId, builder: (column) => column);
|
$composableBuilder(column: $table.url, builder: (column) => column);
|
||||||
|
|
||||||
i0.GeneratedColumn<DateTime> get appliedAt =>
|
|
||||||
$composableBuilder(column: $table.appliedAt, builder: (column) => column);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class $TopSiteSeedStateTableManager
|
class $HiddenTopSiteTableManager
|
||||||
extends
|
extends
|
||||||
i0.RootTableManager<
|
i0.RootTableManager<
|
||||||
i0.GeneratedDatabase,
|
i0.GeneratedDatabase,
|
||||||
i1.TopSiteSeedState,
|
i1.HiddenTopSite,
|
||||||
i1.TopSiteSeedStateData,
|
i1.HiddenTopSiteData,
|
||||||
i1.$TopSiteSeedStateFilterComposer,
|
i1.$HiddenTopSiteFilterComposer,
|
||||||
i1.$TopSiteSeedStateOrderingComposer,
|
i1.$HiddenTopSiteOrderingComposer,
|
||||||
i1.$TopSiteSeedStateAnnotationComposer,
|
i1.$HiddenTopSiteAnnotationComposer,
|
||||||
$TopSiteSeedStateCreateCompanionBuilder,
|
$HiddenTopSiteCreateCompanionBuilder,
|
||||||
$TopSiteSeedStateUpdateCompanionBuilder,
|
$HiddenTopSiteUpdateCompanionBuilder,
|
||||||
(
|
(
|
||||||
i1.TopSiteSeedStateData,
|
i1.HiddenTopSiteData,
|
||||||
i0.BaseReferences<
|
i0.BaseReferences<
|
||||||
i0.GeneratedDatabase,
|
i0.GeneratedDatabase,
|
||||||
i1.TopSiteSeedState,
|
i1.HiddenTopSite,
|
||||||
i1.TopSiteSeedStateData
|
i1.HiddenTopSiteData
|
||||||
>,
|
>,
|
||||||
),
|
),
|
||||||
i1.TopSiteSeedStateData,
|
i1.HiddenTopSiteData,
|
||||||
i0.PrefetchHooks Function()
|
i0.PrefetchHooks Function()
|
||||||
> {
|
> {
|
||||||
$TopSiteSeedStateTableManager(
|
$HiddenTopSiteTableManager(i0.GeneratedDatabase db, i1.HiddenTopSite table)
|
||||||
i0.GeneratedDatabase db,
|
: super(
|
||||||
i1.TopSiteSeedState table,
|
|
||||||
) : super(
|
|
||||||
i0.TableManagerState(
|
i0.TableManagerState(
|
||||||
db: db,
|
db: db,
|
||||||
table: table,
|
table: table,
|
||||||
createFilteringComposer: () =>
|
createFilteringComposer: () =>
|
||||||
i1.$TopSiteSeedStateFilterComposer($db: db, $table: table),
|
i1.$HiddenTopSiteFilterComposer($db: db, $table: table),
|
||||||
createOrderingComposer: () =>
|
createOrderingComposer: () =>
|
||||||
i1.$TopSiteSeedStateOrderingComposer($db: db, $table: table),
|
i1.$HiddenTopSiteOrderingComposer($db: db, $table: table),
|
||||||
createComputedFieldComposer: () =>
|
createComputedFieldComposer: () =>
|
||||||
i1.$TopSiteSeedStateAnnotationComposer($db: db, $table: table),
|
i1.$HiddenTopSiteAnnotationComposer($db: db, $table: table),
|
||||||
updateCompanionCallback:
|
updateCompanionCallback:
|
||||||
({
|
({
|
||||||
i0.Value<String> seedId = const i0.Value.absent(),
|
i0.Value<Uri> url = const i0.Value.absent(),
|
||||||
i0.Value<DateTime> appliedAt = const i0.Value.absent(),
|
|
||||||
i0.Value<int> rowid = const i0.Value.absent(),
|
i0.Value<int> rowid = const i0.Value.absent(),
|
||||||
}) => i1.TopSiteSeedStateCompanion(
|
}) => i1.HiddenTopSiteCompanion(url: url, rowid: rowid),
|
||||||
seedId: seedId,
|
|
||||||
appliedAt: appliedAt,
|
|
||||||
rowid: rowid,
|
|
||||||
),
|
|
||||||
createCompanionCallback:
|
createCompanionCallback:
|
||||||
({
|
({
|
||||||
required String seedId,
|
required Uri url,
|
||||||
required DateTime appliedAt,
|
|
||||||
i0.Value<int> rowid = const i0.Value.absent(),
|
i0.Value<int> rowid = const i0.Value.absent(),
|
||||||
}) => i1.TopSiteSeedStateCompanion.insert(
|
}) => i1.HiddenTopSiteCompanion.insert(url: url, rowid: rowid),
|
||||||
seedId: seedId,
|
|
||||||
appliedAt: appliedAt,
|
|
||||||
rowid: rowid,
|
|
||||||
),
|
|
||||||
withReferenceMapper: (p0) => p0
|
withReferenceMapper: (p0) => p0
|
||||||
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
|
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
|
||||||
.toList(),
|
.toList(),
|
||||||
@@ -366,25 +337,25 @@ class $TopSiteSeedStateTableManager
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef $TopSiteSeedStateProcessedTableManager =
|
typedef $HiddenTopSiteProcessedTableManager =
|
||||||
i0.ProcessedTableManager<
|
i0.ProcessedTableManager<
|
||||||
i0.GeneratedDatabase,
|
i0.GeneratedDatabase,
|
||||||
i1.TopSiteSeedState,
|
i1.HiddenTopSite,
|
||||||
i1.TopSiteSeedStateData,
|
i1.HiddenTopSiteData,
|
||||||
i1.$TopSiteSeedStateFilterComposer,
|
i1.$HiddenTopSiteFilterComposer,
|
||||||
i1.$TopSiteSeedStateOrderingComposer,
|
i1.$HiddenTopSiteOrderingComposer,
|
||||||
i1.$TopSiteSeedStateAnnotationComposer,
|
i1.$HiddenTopSiteAnnotationComposer,
|
||||||
$TopSiteSeedStateCreateCompanionBuilder,
|
$HiddenTopSiteCreateCompanionBuilder,
|
||||||
$TopSiteSeedStateUpdateCompanionBuilder,
|
$HiddenTopSiteUpdateCompanionBuilder,
|
||||||
(
|
(
|
||||||
i1.TopSiteSeedStateData,
|
i1.HiddenTopSiteData,
|
||||||
i0.BaseReferences<
|
i0.BaseReferences<
|
||||||
i0.GeneratedDatabase,
|
i0.GeneratedDatabase,
|
||||||
i1.TopSiteSeedState,
|
i1.HiddenTopSite,
|
||||||
i1.TopSiteSeedStateData
|
i1.HiddenTopSiteData
|
||||||
>,
|
>,
|
||||||
),
|
),
|
||||||
i1.TopSiteSeedStateData,
|
i1.HiddenTopSiteData,
|
||||||
i0.PrefetchHooks Function()
|
i0.PrefetchHooks Function()
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@@ -755,164 +726,130 @@ i0.Index get idxTopSiteOrderKey => i0.Index(
|
|||||||
'CREATE INDEX idx_top_site_order_key ON top_site (order_key)',
|
'CREATE INDEX idx_top_site_order_key ON top_site (order_key)',
|
||||||
);
|
);
|
||||||
|
|
||||||
class TopSiteSeedState extends i0.Table
|
class HiddenTopSite extends i0.Table
|
||||||
with i0.TableInfo<TopSiteSeedState, i1.TopSiteSeedStateData> {
|
with i0.TableInfo<HiddenTopSite, i1.HiddenTopSiteData> {
|
||||||
@override
|
@override
|
||||||
final i0.GeneratedDatabase attachedDatabase;
|
final i0.GeneratedDatabase attachedDatabase;
|
||||||
final String? _alias;
|
final String? _alias;
|
||||||
TopSiteSeedState(this.attachedDatabase, [this._alias]);
|
HiddenTopSite(this.attachedDatabase, [this._alias]);
|
||||||
late final i0.GeneratedColumn<String> seedId = i0.GeneratedColumn<String>(
|
late final i0.GeneratedColumnWithTypeConverter<Uri, String> url =
|
||||||
'seed_id',
|
i0.GeneratedColumn<String>(
|
||||||
aliasedName,
|
'url',
|
||||||
false,
|
|
||||||
type: i0.DriftSqlType.string,
|
|
||||||
requiredDuringInsert: true,
|
|
||||||
$customConstraints: 'PRIMARY KEY NOT NULL',
|
|
||||||
);
|
|
||||||
late final i0.GeneratedColumn<DateTime> appliedAt =
|
|
||||||
i0.GeneratedColumn<DateTime>(
|
|
||||||
'applied_at',
|
|
||||||
aliasedName,
|
aliasedName,
|
||||||
false,
|
false,
|
||||||
type: i0.DriftSqlType.dateTime,
|
type: i0.DriftSqlType.string,
|
||||||
requiredDuringInsert: true,
|
requiredDuringInsert: true,
|
||||||
$customConstraints: 'NOT NULL',
|
$customConstraints: 'PRIMARY KEY NOT NULL',
|
||||||
);
|
).withConverter<Uri>(i1.HiddenTopSite.$converterurl);
|
||||||
@override
|
@override
|
||||||
List<i0.GeneratedColumn> get $columns => [seedId, appliedAt];
|
List<i0.GeneratedColumn> get $columns => [url];
|
||||||
@override
|
@override
|
||||||
String get aliasedName => _alias ?? actualTableName;
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
@override
|
@override
|
||||||
String get actualTableName => $name;
|
String get actualTableName => $name;
|
||||||
static const String $name = 'top_site_seed_state';
|
static const String $name = 'hidden_top_site';
|
||||||
@override
|
@override
|
||||||
Set<i0.GeneratedColumn> get $primaryKey => {seedId};
|
Set<i0.GeneratedColumn> get $primaryKey => {url};
|
||||||
@override
|
@override
|
||||||
i1.TopSiteSeedStateData map(
|
i1.HiddenTopSiteData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||||
Map<String, dynamic> data, {
|
|
||||||
String? tablePrefix,
|
|
||||||
}) {
|
|
||||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||||
return i1.TopSiteSeedStateData(
|
return i1.HiddenTopSiteData(
|
||||||
seedId: attachedDatabase.typeMapping.read(
|
url: i1.HiddenTopSite.$converterurl.fromSql(
|
||||||
i0.DriftSqlType.string,
|
attachedDatabase.typeMapping.read(
|
||||||
data['${effectivePrefix}seed_id'],
|
i0.DriftSqlType.string,
|
||||||
)!,
|
data['${effectivePrefix}url'],
|
||||||
appliedAt: attachedDatabase.typeMapping.read(
|
)!,
|
||||||
i0.DriftSqlType.dateTime,
|
),
|
||||||
data['${effectivePrefix}applied_at'],
|
|
||||||
)!,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
TopSiteSeedState createAlias(String alias) {
|
HiddenTopSite createAlias(String alias) {
|
||||||
return TopSiteSeedState(attachedDatabase, alias);
|
return HiddenTopSite(attachedDatabase, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static i0.TypeConverter<Uri, String> $converterurl = const i3.UriConverter();
|
||||||
@override
|
@override
|
||||||
bool get dontWriteConstraints => true;
|
bool get dontWriteConstraints => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TopSiteSeedStateData extends i0.DataClass
|
class HiddenTopSiteData extends i0.DataClass
|
||||||
implements i0.Insertable<i1.TopSiteSeedStateData> {
|
implements i0.Insertable<i1.HiddenTopSiteData> {
|
||||||
final String seedId;
|
final Uri url;
|
||||||
final DateTime appliedAt;
|
const HiddenTopSiteData({required this.url});
|
||||||
const TopSiteSeedStateData({required this.seedId, required this.appliedAt});
|
|
||||||
@override
|
@override
|
||||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
final map = <String, i0.Expression>{};
|
final map = <String, i0.Expression>{};
|
||||||
map['seed_id'] = i0.Variable<String>(seedId);
|
{
|
||||||
map['applied_at'] = i0.Variable<DateTime>(appliedAt);
|
map['url'] = i0.Variable<String>(
|
||||||
|
i1.HiddenTopSite.$converterurl.toSql(url),
|
||||||
|
);
|
||||||
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
factory TopSiteSeedStateData.fromJson(
|
factory HiddenTopSiteData.fromJson(
|
||||||
Map<String, dynamic> json, {
|
Map<String, dynamic> json, {
|
||||||
i0.ValueSerializer? serializer,
|
i0.ValueSerializer? serializer,
|
||||||
}) {
|
}) {
|
||||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
return TopSiteSeedStateData(
|
return HiddenTopSiteData(url: serializer.fromJson<Uri>(json['url']));
|
||||||
seedId: serializer.fromJson<String>(json['seed_id']),
|
|
||||||
appliedAt: serializer.fromJson<DateTime>(json['applied_at']),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
return <String, dynamic>{
|
return <String, dynamic>{'url': serializer.toJson<Uri>(url)};
|
||||||
'seed_id': serializer.toJson<String>(seedId),
|
|
||||||
'applied_at': serializer.toJson<DateTime>(appliedAt),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i1.TopSiteSeedStateData copyWith({String? seedId, DateTime? appliedAt}) =>
|
i1.HiddenTopSiteData copyWith({Uri? url}) =>
|
||||||
i1.TopSiteSeedStateData(
|
i1.HiddenTopSiteData(url: url ?? this.url);
|
||||||
seedId: seedId ?? this.seedId,
|
HiddenTopSiteData copyWithCompanion(i1.HiddenTopSiteCompanion data) {
|
||||||
appliedAt: appliedAt ?? this.appliedAt,
|
return HiddenTopSiteData(url: data.url.present ? data.url.value : this.url);
|
||||||
);
|
|
||||||
TopSiteSeedStateData copyWithCompanion(i1.TopSiteSeedStateCompanion data) {
|
|
||||||
return TopSiteSeedStateData(
|
|
||||||
seedId: data.seedId.present ? data.seedId.value : this.seedId,
|
|
||||||
appliedAt: data.appliedAt.present ? data.appliedAt.value : this.appliedAt,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return (StringBuffer('TopSiteSeedStateData(')
|
return (StringBuffer('HiddenTopSiteData(')
|
||||||
..write('seedId: $seedId, ')
|
..write('url: $url')
|
||||||
..write('appliedAt: $appliedAt')
|
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(seedId, appliedAt);
|
int get hashCode => url.hashCode;
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
(other is i1.TopSiteSeedStateData &&
|
(other is i1.HiddenTopSiteData && other.url == this.url);
|
||||||
other.seedId == this.seedId &&
|
|
||||||
other.appliedAt == this.appliedAt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TopSiteSeedStateCompanion
|
class HiddenTopSiteCompanion extends i0.UpdateCompanion<i1.HiddenTopSiteData> {
|
||||||
extends i0.UpdateCompanion<i1.TopSiteSeedStateData> {
|
final i0.Value<Uri> url;
|
||||||
final i0.Value<String> seedId;
|
|
||||||
final i0.Value<DateTime> appliedAt;
|
|
||||||
final i0.Value<int> rowid;
|
final i0.Value<int> rowid;
|
||||||
const TopSiteSeedStateCompanion({
|
const HiddenTopSiteCompanion({
|
||||||
this.seedId = const i0.Value.absent(),
|
this.url = const i0.Value.absent(),
|
||||||
this.appliedAt = const i0.Value.absent(),
|
|
||||||
this.rowid = const i0.Value.absent(),
|
this.rowid = const i0.Value.absent(),
|
||||||
});
|
});
|
||||||
TopSiteSeedStateCompanion.insert({
|
HiddenTopSiteCompanion.insert({
|
||||||
required String seedId,
|
required Uri url,
|
||||||
required DateTime appliedAt,
|
|
||||||
this.rowid = const i0.Value.absent(),
|
this.rowid = const i0.Value.absent(),
|
||||||
}) : seedId = i0.Value(seedId),
|
}) : url = i0.Value(url);
|
||||||
appliedAt = i0.Value(appliedAt);
|
static i0.Insertable<i1.HiddenTopSiteData> custom({
|
||||||
static i0.Insertable<i1.TopSiteSeedStateData> custom({
|
i0.Expression<String>? url,
|
||||||
i0.Expression<String>? seedId,
|
|
||||||
i0.Expression<DateTime>? appliedAt,
|
|
||||||
i0.Expression<int>? rowid,
|
i0.Expression<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return i0.RawValuesInsertable({
|
return i0.RawValuesInsertable({
|
||||||
if (seedId != null) 'seed_id': seedId,
|
if (url != null) 'url': url,
|
||||||
if (appliedAt != null) 'applied_at': appliedAt,
|
|
||||||
if (rowid != null) 'rowid': rowid,
|
if (rowid != null) 'rowid': rowid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
i1.TopSiteSeedStateCompanion copyWith({
|
i1.HiddenTopSiteCompanion copyWith({
|
||||||
i0.Value<String>? seedId,
|
i0.Value<Uri>? url,
|
||||||
i0.Value<DateTime>? appliedAt,
|
|
||||||
i0.Value<int>? rowid,
|
i0.Value<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return i1.TopSiteSeedStateCompanion(
|
return i1.HiddenTopSiteCompanion(
|
||||||
seedId: seedId ?? this.seedId,
|
url: url ?? this.url,
|
||||||
appliedAt: appliedAt ?? this.appliedAt,
|
|
||||||
rowid: rowid ?? this.rowid,
|
rowid: rowid ?? this.rowid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -920,11 +857,10 @@ class TopSiteSeedStateCompanion
|
|||||||
@override
|
@override
|
||||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
final map = <String, i0.Expression>{};
|
final map = <String, i0.Expression>{};
|
||||||
if (seedId.present) {
|
if (url.present) {
|
||||||
map['seed_id'] = i0.Variable<String>(seedId.value);
|
map['url'] = i0.Variable<String>(
|
||||||
}
|
i1.HiddenTopSite.$converterurl.toSql(url.value),
|
||||||
if (appliedAt.present) {
|
);
|
||||||
map['applied_at'] = i0.Variable<DateTime>(appliedAt.value);
|
|
||||||
}
|
}
|
||||||
if (rowid.present) {
|
if (rowid.present) {
|
||||||
map['rowid'] = i0.Variable<int>(rowid.value);
|
map['rowid'] = i0.Variable<int>(rowid.value);
|
||||||
@@ -934,9 +870,8 @@ class TopSiteSeedStateCompanion
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return (StringBuffer('TopSiteSeedStateCompanion(')
|
return (StringBuffer('HiddenTopSiteCompanion(')
|
||||||
..write('seedId: $seedId, ')
|
..write('url: $url, ')
|
||||||
..write('appliedAt: $appliedAt, ')
|
|
||||||
..write('rowid: $rowid')
|
..write('rowid: $rowid')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
|
|||||||
+1
-1
@@ -17,4 +17,4 @@
|
|||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
enum StoredTopSiteSource { seeded, pinned }
|
enum StoredTopSiteSource { defaultSite, pinned }
|
||||||
|
|||||||
@@ -43,8 +43,13 @@ class TopSiteItem with FastEquatable {
|
|||||||
this.historyPlaceId,
|
this.historyPlaceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
bool get isPersisted =>
|
bool get isPinned => source == TopSiteSource.pinned;
|
||||||
source == TopSiteSource.seeded || source == TopSiteSource.pinned;
|
|
||||||
|
bool get isDefault => source == TopSiteSource.defaultSite;
|
||||||
|
|
||||||
|
bool get isHistory => source == TopSiteSource.history;
|
||||||
|
|
||||||
|
bool get isPersisted => isPinned || isDefault;
|
||||||
|
|
||||||
bool get isReorderable => isPersisted;
|
bool get isReorderable => isPersisted;
|
||||||
|
|
||||||
|
|||||||
@@ -17,4 +17,4 @@
|
|||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
enum TopSiteSource { seeded, pinned, history }
|
enum TopSiteSource { defaultSite, pinned, history }
|
||||||
|
|||||||
@@ -23,14 +23,20 @@ import 'package:weblibre/features/geckoview/features/top_sites/domain/repositori
|
|||||||
|
|
||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
const defaultTopSites = [
|
||||||
List<({String title, Uri url})> topSiteDefaultSeeds(Ref ref) {
|
(title: 'Wikipedia', url: 'https://wikipedia.org/'),
|
||||||
return [
|
(title: 'OpenStreetMap', url: 'https://www.openstreetmap.org/'),
|
||||||
(title: 'Wikipedia', url: Uri.parse('https://wikipedia.org')),
|
(
|
||||||
(title: 'OpenStreetMap', url: Uri.parse('https://www.openstreetmap.org')),
|
title:
|
||||||
(title: 'Project Gutenberg', url: Uri.parse('https://www.gutenberg.org/')),
|
'Internet Archive: Digital Library of Free & Borrowable Texts, Movies, Music & Wayback Machine',
|
||||||
];
|
url: 'https://archive.org/',
|
||||||
}
|
),
|
||||||
|
(
|
||||||
|
title: 'Mozilla - Internet for people, not profit',
|
||||||
|
url: 'https://www.mozilla.org/',
|
||||||
|
),
|
||||||
|
(title: 'Tor Project | Anonymity Online', url: 'https://www.torproject.org/'),
|
||||||
|
];
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<List<TopSiteItem>> topSiteList(Ref ref, {int limit = 8}) {
|
Stream<List<TopSiteItem>> topSiteList(Ref ref, {int limit = 8}) {
|
||||||
@@ -40,6 +46,6 @@ Stream<List<TopSiteItem>> topSiteList(Ref ref, {int limit = 8}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<List<TopSiteItem>> persistedTopSiteList(Ref ref) {
|
Stream<List<TopSiteItem>> pinnedTopSiteList(Ref ref) {
|
||||||
return ref.watch(topSiteRepositoryProvider.notifier).watchPersistedTopSites();
|
return ref.watch(topSiteRepositoryProvider.notifier).watchPinnedTopSites();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,56 +9,6 @@ part of 'providers.dart';
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(topSiteDefaultSeeds)
|
|
||||||
final topSiteDefaultSeedsProvider = TopSiteDefaultSeedsProvider._();
|
|
||||||
|
|
||||||
final class TopSiteDefaultSeedsProvider
|
|
||||||
extends
|
|
||||||
$FunctionalProvider<
|
|
||||||
List<({String title, Uri url})>,
|
|
||||||
List<({String title, Uri url})>,
|
|
||||||
List<({String title, Uri url})>
|
|
||||||
>
|
|
||||||
with $Provider<List<({String title, Uri url})>> {
|
|
||||||
TopSiteDefaultSeedsProvider._()
|
|
||||||
: super(
|
|
||||||
from: null,
|
|
||||||
argument: null,
|
|
||||||
retry: null,
|
|
||||||
name: r'topSiteDefaultSeedsProvider',
|
|
||||||
isAutoDispose: false,
|
|
||||||
dependencies: null,
|
|
||||||
$allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String debugGetCreateSourceHash() => _$topSiteDefaultSeedsHash();
|
|
||||||
|
|
||||||
@$internal
|
|
||||||
@override
|
|
||||||
$ProviderElement<List<({String title, Uri url})>> $createElement(
|
|
||||||
$ProviderPointer pointer,
|
|
||||||
) => $ProviderElement(pointer);
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<({String title, Uri url})> create(Ref ref) {
|
|
||||||
return topSiteDefaultSeeds(ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// {@macro riverpod.override_with_value}
|
|
||||||
Override overrideWithValue(List<({String title, Uri url})> value) {
|
|
||||||
return $ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
providerOverride: $SyncValueProvider<List<({String title, Uri url})>>(
|
|
||||||
value,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String _$topSiteDefaultSeedsHash() =>
|
|
||||||
r'd15156e1ebe1896a11dc2d983db9fb90a2222380';
|
|
||||||
|
|
||||||
@ProviderFor(topSiteList)
|
@ProviderFor(topSiteList)
|
||||||
final topSiteListProvider = TopSiteListFamily._();
|
final topSiteListProvider = TopSiteListFamily._();
|
||||||
|
|
||||||
@@ -136,10 +86,10 @@ final class TopSiteListFamily extends $Family
|
|||||||
String toString() => r'topSiteListProvider';
|
String toString() => r'topSiteListProvider';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ProviderFor(persistedTopSiteList)
|
@ProviderFor(pinnedTopSiteList)
|
||||||
final persistedTopSiteListProvider = PersistedTopSiteListProvider._();
|
final pinnedTopSiteListProvider = PinnedTopSiteListProvider._();
|
||||||
|
|
||||||
final class PersistedTopSiteListProvider
|
final class PinnedTopSiteListProvider
|
||||||
extends
|
extends
|
||||||
$FunctionalProvider<
|
$FunctionalProvider<
|
||||||
AsyncValue<List<TopSiteItem>>,
|
AsyncValue<List<TopSiteItem>>,
|
||||||
@@ -149,19 +99,19 @@ final class PersistedTopSiteListProvider
|
|||||||
with
|
with
|
||||||
$FutureModifier<List<TopSiteItem>>,
|
$FutureModifier<List<TopSiteItem>>,
|
||||||
$StreamProvider<List<TopSiteItem>> {
|
$StreamProvider<List<TopSiteItem>> {
|
||||||
PersistedTopSiteListProvider._()
|
PinnedTopSiteListProvider._()
|
||||||
: super(
|
: super(
|
||||||
from: null,
|
from: null,
|
||||||
argument: null,
|
argument: null,
|
||||||
retry: null,
|
retry: null,
|
||||||
name: r'persistedTopSiteListProvider',
|
name: r'pinnedTopSiteListProvider',
|
||||||
isAutoDispose: true,
|
isAutoDispose: true,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
$allTransitiveDependencies: null,
|
$allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String debugGetCreateSourceHash() => _$persistedTopSiteListHash();
|
String debugGetCreateSourceHash() => _$pinnedTopSiteListHash();
|
||||||
|
|
||||||
@$internal
|
@$internal
|
||||||
@override
|
@override
|
||||||
@@ -171,9 +121,8 @@ final class PersistedTopSiteListProvider
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<List<TopSiteItem>> create(Ref ref) {
|
Stream<List<TopSiteItem>> create(Ref ref) {
|
||||||
return persistedTopSiteList(ref);
|
return pinnedTopSiteList(ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$persistedTopSiteListHash() =>
|
String _$pinnedTopSiteListHash() => r'83adb6584ef738be14a2e0b55b33986ebb4520a9';
|
||||||
r'f0f7f087dccc0cea8498811ea2ad2af5e6d3fbb8';
|
|
||||||
|
|||||||
+159
-108
@@ -19,8 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:weblibre/core/uuid.dart';
|
import 'package:weblibre/core/uuid.dart';
|
||||||
import 'package:weblibre/extensions/uri.dart';
|
import 'package:weblibre/extensions/uri.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/history/domain/repositories/history.dart';
|
import 'package:weblibre/features/geckoview/features/history/domain/repositories/history.dart';
|
||||||
@@ -36,92 +36,88 @@ part 'top_site_repository.g.dart';
|
|||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
class TopSiteRepository extends _$TopSiteRepository {
|
class TopSiteRepository extends _$TopSiteRepository {
|
||||||
Future<void> ensureSeeded() async {
|
Stream<List<TopSiteItem>> watchTopSites({int limit = 8}) {
|
||||||
final db = ref.read(topSiteDatabaseProvider);
|
final db = ref.read(topSiteDatabaseProvider);
|
||||||
final seeds = ref.read(topSiteDefaultSeedsProvider);
|
|
||||||
|
|
||||||
await db.transaction(() async {
|
return CombineLatestStream.combine2(
|
||||||
final alreadySeeded = await db.topSiteSeedStateDao.hasSeed(
|
db.topSiteDao.selectAllTopSites().watch(),
|
||||||
'initial-defaults-v1',
|
db.hiddenTopSiteDao.watchHiddenUrls(),
|
||||||
|
(List<TopSiteData> rows, Set<String> hiddenUrls) => (rows, hiddenUrls),
|
||||||
|
).asyncMap((record) async {
|
||||||
|
final (rows, hiddenUrls) = record;
|
||||||
|
final persistedItems = rows.map(_mapRow).toList();
|
||||||
|
final persistedUrls = persistedItems
|
||||||
|
.map((s) => s.url.normalized.toString())
|
||||||
|
.toSet();
|
||||||
|
|
||||||
|
final defaultItems = _getVisibleDefaults(
|
||||||
|
persistedUrls: persistedUrls,
|
||||||
|
hiddenUrls: hiddenUrls,
|
||||||
);
|
);
|
||||||
if (alreadySeeded) return;
|
|
||||||
|
|
||||||
final now = DateTime.now();
|
final combined = [...persistedItems, ...defaultItems];
|
||||||
|
final targetCount = limit < 0 ? 0 : limit;
|
||||||
|
|
||||||
for (var i = 0; i < seeds.length; i++) {
|
if (combined.length >= targetCount) {
|
||||||
final orderKey = await db.topSiteDao
|
return combined;
|
||||||
.generateTrailingOrderKey()
|
|
||||||
.getSingle();
|
|
||||||
// Insert one-by-one so trailing key advances
|
|
||||||
await db.topSite.insertOne(
|
|
||||||
TopSiteCompanion.insert(
|
|
||||||
id: uuid.v7(),
|
|
||||||
title: seeds[i].title,
|
|
||||||
url: seeds[i].url.normalized,
|
|
||||||
source: StoredTopSiteSource.seeded,
|
|
||||||
orderKey: orderKey,
|
|
||||||
createdAt: now,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.topSiteSeedStateDao.markSeedApplied('initial-defaults-v1');
|
final remaining = targetCount - combined.length;
|
||||||
|
final excludeUrls = {
|
||||||
|
...persistedUrls,
|
||||||
|
...defaultItems.map((s) => s.url.normalized.toString()),
|
||||||
|
};
|
||||||
|
final historyItems = await _getHistoryItems(
|
||||||
|
limit: remaining,
|
||||||
|
excludeUrls: excludeUrls,
|
||||||
|
);
|
||||||
|
|
||||||
|
return [...combined, ...historyItems];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<TopSiteItem>> getTopSites({int limit = 8}) async {
|
Future<List<TopSiteItem>> getTopSites({int limit = 8}) async {
|
||||||
final persisted = await _getPersistedItems();
|
final db = ref.read(topSiteDatabaseProvider);
|
||||||
final targetCount = limit < 0 ? 0 : limit;
|
final rows = await db.topSiteDao.getAllTopSites();
|
||||||
|
final hiddenUrls = await db.hiddenTopSiteDao.getHiddenUrls();
|
||||||
|
|
||||||
// Always keep all persisted items. The limit is only used as a history
|
final persistedItems = rows.map(_mapRow).toList();
|
||||||
// padding target.
|
final persistedUrls = persistedItems
|
||||||
if (persisted.length >= targetCount) {
|
.map((s) => s.url.normalized.toString())
|
||||||
return persisted;
|
.toSet();
|
||||||
}
|
|
||||||
|
|
||||||
final remaining = targetCount - persisted.length;
|
final defaultItems = _getVisibleDefaults(
|
||||||
final historyItems = await _getHistoryItems(
|
persistedUrls: persistedUrls,
|
||||||
limit: remaining,
|
hiddenUrls: hiddenUrls,
|
||||||
excludeUrls: persisted.map((s) => s.url.normalized.toString()).toSet(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return [...persisted, ...historyItems];
|
final combined = [...persistedItems, ...defaultItems];
|
||||||
|
final targetCount = limit < 0 ? 0 : limit;
|
||||||
|
|
||||||
|
if (combined.length >= targetCount) {
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
final remaining = targetCount - combined.length;
|
||||||
|
final excludeUrls = {
|
||||||
|
...persistedUrls,
|
||||||
|
...defaultItems.map((s) => s.url.normalized.toString()),
|
||||||
|
};
|
||||||
|
final historyItems = await _getHistoryItems(
|
||||||
|
limit: remaining,
|
||||||
|
excludeUrls: excludeUrls,
|
||||||
|
);
|
||||||
|
|
||||||
|
return [...combined, ...historyItems];
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<List<TopSiteItem>> watchTopSites({int limit = 8}) {
|
Stream<List<TopSiteItem>> watchPinnedTopSites() {
|
||||||
final db = ref.read(topSiteDatabaseProvider);
|
final db = ref.read(topSiteDatabaseProvider);
|
||||||
return db.topSiteDao.selectPersistedTopSites().watch().asyncMap((
|
return db.topSiteDao.selectAllTopSites().watch().map(
|
||||||
persistedRows,
|
(rows) => rows
|
||||||
) async {
|
.where((r) => r.source == StoredTopSiteSource.pinned)
|
||||||
final persistedItems = persistedRows.map(_mapPersistedRow).toList();
|
.map(_mapRow)
|
||||||
final targetCount = limit < 0 ? 0 : limit;
|
.toList(),
|
||||||
|
|
||||||
// Always keep all persisted items. The limit is only used as a history
|
|
||||||
// padding target.
|
|
||||||
if (persistedItems.length >= targetCount) {
|
|
||||||
return persistedItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
final remaining = targetCount - persistedItems.length;
|
|
||||||
final historyItems = await _getHistoryItems(
|
|
||||||
limit: remaining,
|
|
||||||
excludeUrls: persistedItems
|
|
||||||
.map((s) => s.url.normalized.toString())
|
|
||||||
.toSet(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return [...persistedItems, ...historyItems];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<TopSiteItem>> getPersistedTopSites() {
|
|
||||||
return _getPersistedItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream<List<TopSiteItem>> watchPersistedTopSites() {
|
|
||||||
final db = ref.read(topSiteDatabaseProvider);
|
|
||||||
return db.topSiteDao.selectPersistedTopSites().watch().map(
|
|
||||||
(rows) => rows.map(_mapPersistedRow).toList(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +133,39 @@ class TopSiteRepository extends _$TopSiteRepository {
|
|||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Persists a default site to the database so it can be reordered.
|
||||||
|
/// Returns the database ID.
|
||||||
|
Future<String> _persistDefault({
|
||||||
|
required String title,
|
||||||
|
required Uri url,
|
||||||
|
required String orderKey,
|
||||||
|
}) async {
|
||||||
|
final db = ref.read(topSiteDatabaseProvider);
|
||||||
|
final id = uuid.v7();
|
||||||
|
await db.topSiteDao.insertSite(
|
||||||
|
id: id,
|
||||||
|
title: title,
|
||||||
|
url: url,
|
||||||
|
source: StoredTopSiteSource.defaultSite,
|
||||||
|
orderKey: orderKey,
|
||||||
|
);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensures a default site is persisted in the database. If it already exists,
|
||||||
|
/// returns its existing ID. Otherwise inserts it with a trailing order key.
|
||||||
|
Future<String> ensureDefaultPersisted({
|
||||||
|
required String title,
|
||||||
|
required Uri url,
|
||||||
|
}) async {
|
||||||
|
final db = ref.read(topSiteDatabaseProvider);
|
||||||
|
final existing = await db.topSiteDao.getTopSiteByUrl(url);
|
||||||
|
if (existing != null) return existing.id;
|
||||||
|
|
||||||
|
final orderKey = await db.topSiteDao.generateTrailingOrderKey().getSingle();
|
||||||
|
return _persistDefault(title: title, url: url, orderKey: orderKey);
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> addPinnedSite({
|
Future<String> addPinnedSite({
|
||||||
required String title,
|
required String title,
|
||||||
required Uri url,
|
required Uri url,
|
||||||
@@ -144,8 +173,11 @@ class TopSiteRepository extends _$TopSiteRepository {
|
|||||||
_validateUrl(url);
|
_validateUrl(url);
|
||||||
final db = ref.read(topSiteDatabaseProvider);
|
final db = ref.read(topSiteDatabaseProvider);
|
||||||
|
|
||||||
// Check if URL already exists as a persisted site
|
// If it was a hidden default, unhide it
|
||||||
final existing = await db.topSiteDao.getPersistedTopSiteByUrl(url);
|
await db.hiddenTopSiteDao.unhideUrl(url);
|
||||||
|
|
||||||
|
// Check if URL already exists
|
||||||
|
final existing = await db.topSiteDao.getTopSiteByUrl(url);
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
final leadingKey = await db.topSiteDao
|
final leadingKey = await db.topSiteDao
|
||||||
.generateLeadingOrderKey()
|
.generateLeadingOrderKey()
|
||||||
@@ -161,16 +193,17 @@ class TopSiteRepository extends _$TopSiteRepository {
|
|||||||
|
|
||||||
final id = uuid.v7();
|
final id = uuid.v7();
|
||||||
final orderKey = await db.topSiteDao.generateLeadingOrderKey().getSingle();
|
final orderKey = await db.topSiteDao.generateLeadingOrderKey().getSingle();
|
||||||
await db.topSiteDao.insertPinnedSite(
|
await db.topSiteDao.insertSite(
|
||||||
id: id,
|
id: id,
|
||||||
title: title,
|
title: title,
|
||||||
url: url,
|
url: url,
|
||||||
|
source: StoredTopSiteSource.pinned,
|
||||||
orderKey: orderKey,
|
orderKey: orderKey,
|
||||||
);
|
);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updatePersistedSite({
|
Future<void> updateSite({
|
||||||
required String id,
|
required String id,
|
||||||
required String title,
|
required String title,
|
||||||
required Uri url,
|
required Uri url,
|
||||||
@@ -179,39 +212,47 @@ class TopSiteRepository extends _$TopSiteRepository {
|
|||||||
return ref
|
return ref
|
||||||
.read(topSiteDatabaseProvider)
|
.read(topSiteDatabaseProvider)
|
||||||
.topSiteDao
|
.topSiteDao
|
||||||
.updatePersistedSite(id, title: title, url: url);
|
.updateSite(id, title: title, url: url);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> removePersistedSite(String id) {
|
Future<void> removeSite(String id) {
|
||||||
return ref.read(topSiteDatabaseProvider).topSiteDao.deletePersistedSite(id);
|
return ref.read(topSiteDatabaseProvider).topSiteDao.deleteSite(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<TopSiteItem?> getPersistedTopSiteByUrl(Uri url) async {
|
Future<void> hideDefaultSite(Uri url) {
|
||||||
|
return ref.read(topSiteDatabaseProvider).hiddenTopSiteDao.hideUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> isPinnedTopSiteUrl(Uri url) async {
|
||||||
final row = await ref
|
final row = await ref
|
||||||
.read(topSiteDatabaseProvider)
|
.read(topSiteDatabaseProvider)
|
||||||
.topSiteDao
|
.topSiteDao
|
||||||
.getPersistedTopSiteByUrl(url);
|
.getTopSiteByUrl(url);
|
||||||
return row != null ? _mapPersistedRow(row) : null;
|
return row != null && row.source == StoredTopSiteSource.pinned;
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> isPersistedTopSiteUrl(Uri url) async {
|
|
||||||
final row = await ref
|
|
||||||
.read(topSiteDatabaseProvider)
|
|
||||||
.topSiteDao
|
|
||||||
.getPersistedTopSiteByUrl(url);
|
|
||||||
return row != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> unpinSiteByUrl(Uri url) async {
|
Future<bool> unpinSiteByUrl(Uri url) async {
|
||||||
final row = await ref
|
final db = ref.read(topSiteDatabaseProvider);
|
||||||
.read(topSiteDatabaseProvider)
|
final row = await db.topSiteDao.getTopSiteByUrl(url);
|
||||||
.topSiteDao
|
|
||||||
.getPersistedTopSiteByUrl(url);
|
|
||||||
if (row == null) return false;
|
if (row == null) return false;
|
||||||
await ref
|
|
||||||
.read(topSiteDatabaseProvider)
|
// If it was a pinned default, demote back to defaultSite source
|
||||||
.topSiteDao
|
final isDefaultUrl = defaultTopSites.any(
|
||||||
.deletePersistedSite(row.id);
|
(d) => Uri.parse(d.url).normalized == url.normalized,
|
||||||
|
);
|
||||||
|
if (isDefaultUrl) {
|
||||||
|
final trailingKey = await db.topSiteDao
|
||||||
|
.generateTrailingOrderKey()
|
||||||
|
.getSingle();
|
||||||
|
await db.topSiteDao.promoteToSource(
|
||||||
|
row.id,
|
||||||
|
source: StoredTopSiteSource.defaultSite,
|
||||||
|
title: row.title,
|
||||||
|
orderKey: trailingKey,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await db.topSiteDao.deleteSite(row.id);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,12 +295,24 @@ class TopSiteRepository extends _$TopSiteRepository {
|
|||||||
.getSingle();
|
.getSingle();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<TopSiteItem>> _getPersistedItems() async {
|
List<TopSiteItem> _getVisibleDefaults({
|
||||||
final rows = await ref
|
required Set<String> persistedUrls,
|
||||||
.read(topSiteDatabaseProvider)
|
required Set<String> hiddenUrls,
|
||||||
.topSiteDao
|
}) {
|
||||||
.getPersistedTopSites();
|
return defaultTopSites
|
||||||
return rows.map(_mapPersistedRow).toList();
|
.where((seed) {
|
||||||
|
final normalized = Uri.parse(seed.url).normalized.toString();
|
||||||
|
return !persistedUrls.contains(normalized) &&
|
||||||
|
!hiddenUrls.contains(normalized);
|
||||||
|
})
|
||||||
|
.map(
|
||||||
|
(seed) => TopSiteItem(
|
||||||
|
title: seed.title,
|
||||||
|
url: Uri.parse(seed.url),
|
||||||
|
source: TopSiteSource.defaultSite,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<TopSiteItem>> _getHistoryItems({
|
Future<List<TopSiteItem>> _getHistoryItems({
|
||||||
@@ -291,21 +344,19 @@ class TopSiteRepository extends _$TopSiteRepository {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
TopSiteItem _mapPersistedRow(TopSiteData row) {
|
TopSiteItem _mapRow(TopSiteData row) {
|
||||||
return TopSiteItem(
|
return TopSiteItem(
|
||||||
id: row.id,
|
id: row.id,
|
||||||
title: row.title,
|
title: row.title,
|
||||||
url: row.url,
|
url: row.url,
|
||||||
source: row.source == StoredTopSiteSource.seeded
|
source: row.source == StoredTopSiteSource.pinned
|
||||||
? TopSiteSource.seeded
|
? TopSiteSource.pinned
|
||||||
: TopSiteSource.pinned,
|
: TopSiteSource.defaultSite,
|
||||||
orderKey: row.orderKey,
|
orderKey: row.orderKey,
|
||||||
createdAt: row.createdAt,
|
createdAt: row.createdAt,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void build() {
|
void build() {}
|
||||||
unawaited(ensureSeeded());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ final class TopSiteRepositoryProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$topSiteRepositoryHash() => r'6e954c84ed5916ac0b5a9e251d43cbe1e9ed15c3';
|
String _$topSiteRepositoryHash() => r'43c0495dfb3044dc9bb2f420524b45afb5735a0b';
|
||||||
|
|
||||||
abstract class _$TopSiteRepository extends $Notifier<void> {
|
abstract class _$TopSiteRepository extends $Notifier<void> {
|
||||||
void build();
|
void build();
|
||||||
|
|||||||
Reference in New Issue
Block a user