improve tab reorder logic
This commit is contained in:
@@ -15,6 +15,7 @@ targets:
|
|||||||
lexo_rank_next: "text (int, text null)"
|
lexo_rank_next: "text (int, text null)"
|
||||||
lexo_rank_previous: "text (int, text null)"
|
lexo_rank_previous: "text (int, text null)"
|
||||||
lexo_rank_reorder_after: "text (text null, text null)"
|
lexo_rank_reorder_after: "text (text null, text null)"
|
||||||
|
lexo_rank_reorder_before: "text (text null, text null)"
|
||||||
modules:
|
modules:
|
||||||
- json1
|
- json1
|
||||||
- fts5
|
- fts5
|
||||||
|
|||||||
@@ -40,6 +40,19 @@ String _reorderAfter(List<Object?> args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _reorderBefore(List<Object?> args) {
|
||||||
|
final first = args[0].mapNotNull((arg) => LexoRank.parse(arg as String));
|
||||||
|
final last = args[1].mapNotNull((arg) => LexoRank.parse(arg as String));
|
||||||
|
|
||||||
|
if (first == null) {
|
||||||
|
throw Exception('Tab not found');
|
||||||
|
} else if (last == null) {
|
||||||
|
return first.genPrev().value;
|
||||||
|
} else {
|
||||||
|
return last.genBetween(first).value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void registerLexorankFunctions(CommonDatabase database) {
|
void registerLexorankFunctions(CommonDatabase database) {
|
||||||
database.createFunction(
|
database.createFunction(
|
||||||
functionName: 'lexo_rank_next',
|
functionName: 'lexo_rank_next',
|
||||||
@@ -56,4 +69,9 @@ void registerLexorankFunctions(CommonDatabase database) {
|
|||||||
argumentCount: const AllowedArgumentCount(2),
|
argumentCount: const AllowedArgumentCount(2),
|
||||||
function: _reorderAfter,
|
function: _reorderAfter,
|
||||||
);
|
);
|
||||||
|
database.createFunction(
|
||||||
|
functionName: 'lexo_rank_reorder_before',
|
||||||
|
argumentCount: const AllowedArgumentCount(2),
|
||||||
|
function: _reorderBefore,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-10
@@ -300,6 +300,8 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: HookConsumer(
|
child: HookConsumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
|
final gridViewKey = useMemoized(() => GlobalKey());
|
||||||
|
|
||||||
final container = ref.watch(selectedContainerProvider);
|
final container = ref.watch(selectedContainerProvider);
|
||||||
|
|
||||||
final filteredTabEntities = ref.watch(
|
final filteredTabEntities = ref.watch(
|
||||||
@@ -387,10 +389,11 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
|
|||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
child: ReorderableBuilder(
|
child: ReorderableBuilder.builder(
|
||||||
//Rebuild when cross axis count changes
|
//Rebuild when cross axis count changes
|
||||||
key: ValueKey(crossAxisCount),
|
key: ValueKey(crossAxisCount),
|
||||||
scrollController: sheetScrollController,
|
scrollController: sheetScrollController,
|
||||||
|
itemCount: tabs.length,
|
||||||
onDragStarted: (index) {
|
onDragStarted: (index) {
|
||||||
ref.read(willAcceptDropProvider.notifier).clear();
|
ref.read(willAcceptDropProvider.notifier).clear();
|
||||||
},
|
},
|
||||||
@@ -423,19 +426,27 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
|
|||||||
containerId,
|
containerId,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final orderAfterIndex = newIndex;
|
if (newIndex < oldIndex) {
|
||||||
key = await containerRepository.getOrderKeyAfterTab(
|
key = await containerRepository.getOrderKeyAfterTab(
|
||||||
filteredTabEntities.value[orderAfterIndex].tabId,
|
filteredTabEntities.value[newIndex - 1].tabId,
|
||||||
containerId,
|
containerId,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
key = await containerRepository
|
||||||
|
.getOrderKeyBeforeTab(
|
||||||
|
filteredTabEntities.value[newIndex + 1].tabId,
|
||||||
|
containerId,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await ref
|
await ref
|
||||||
.read(tabDataRepositoryProvider.notifier)
|
.read(tabDataRepositoryProvider.notifier)
|
||||||
.assignOrderKey(tabId, key);
|
.assignOrderKey(tabId, key);
|
||||||
},
|
},
|
||||||
builder: (children) {
|
childBuilder: (itemBuilder) {
|
||||||
return GridView.builder(
|
return GridView.builder(
|
||||||
|
key: gridViewKey,
|
||||||
controller: sheetScrollController,
|
controller: sheetScrollController,
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
//Sync values for itemHeight calculation _calculateItemHeight
|
//Sync values for itemHeight calculation _calculateItemHeight
|
||||||
@@ -444,11 +455,11 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
|
|||||||
crossAxisSpacing: 8.0,
|
crossAxisSpacing: 8.0,
|
||||||
crossAxisCount: crossAxisCount,
|
crossAxisCount: crossAxisCount,
|
||||||
),
|
),
|
||||||
itemCount: children.length,
|
itemCount: tabs.length,
|
||||||
itemBuilder: (context, index) => children[index],
|
itemBuilder: (context, index) =>
|
||||||
|
itemBuilder(tabs[index], index),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
children: tabs,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -96,4 +96,11 @@ class ContainerDao extends DatabaseAccessor<TabDatabase>
|
|||||||
) {
|
) {
|
||||||
return db.orderKeyAfterTab(containerId: containerId, tabId: tabId);
|
return db.orderKeyAfterTab(containerId: containerId, tabId: tabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SingleSelectable<String> generateOrderKeyBeforeTabId(
|
||||||
|
String? containerId,
|
||||||
|
String tabId,
|
||||||
|
) {
|
||||||
|
return db.orderKeyBeforeTab(containerId: containerId, tabId: tabId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,6 +118,18 @@ orderKeyAfterTab(:tab_id AS TEXT, :container_id AS TEXT OR NULL):
|
|||||||
FROM ordered_table
|
FROM ordered_table
|
||||||
WHERE id = :tab_id;
|
WHERE id = :tab_id;
|
||||||
|
|
||||||
|
orderKeyBeforeTab(:tab_id AS TEXT, :container_id AS TEXT OR NULL):
|
||||||
|
WITH ordered_table AS (
|
||||||
|
SELECT id,
|
||||||
|
order_key,
|
||||||
|
LAG(order_key) OVER (ORDER BY order_key) AS prev_order_key
|
||||||
|
FROM tab
|
||||||
|
WHERE container_id IS :container_id
|
||||||
|
)
|
||||||
|
SELECT lexo_rank_reorder_before(order_key, prev_order_key)
|
||||||
|
FROM ordered_table
|
||||||
|
WHERE id = :tab_id;
|
||||||
|
|
||||||
queryTabsBasic WITH TabQueryResult:
|
queryTabsBasic WITH TabQueryResult:
|
||||||
WITH weights AS (
|
WITH weights AS (
|
||||||
SELECT
|
SELECT
|
||||||
|
|||||||
@@ -1165,6 +1165,17 @@ abstract class _$TabDatabase extends GeneratedDatabase {
|
|||||||
).map((QueryRow row) => row.read<String>('_c0'));
|
).map((QueryRow row) => row.read<String>('_c0'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Selectable<String> orderKeyBeforeTab({
|
||||||
|
String? containerId,
|
||||||
|
required String tabId,
|
||||||
|
}) {
|
||||||
|
return customSelect(
|
||||||
|
'WITH ordered_table AS (SELECT id, order_key, LAG(order_key)OVER (ORDER BY order_key RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE NO OTHERS) AS prev_order_key FROM tab WHERE container_id IS ?1) SELECT lexo_rank_reorder_before(order_key, prev_order_key) AS _c0 FROM ordered_table WHERE id = ?2',
|
||||||
|
variables: [Variable<String>(containerId), Variable<String>(tabId)],
|
||||||
|
readsFrom: {tab},
|
||||||
|
).map((QueryRow row) => row.read<String>('_c0'));
|
||||||
|
}
|
||||||
|
|
||||||
Selectable<TabQueryResult> queryTabsBasic({required String query}) {
|
Selectable<TabQueryResult> queryTabsBasic({required String query}) {
|
||||||
return customSelect(
|
return customSelect(
|
||||||
'WITH weights AS (SELECT 10.0 AS title_weight, 5.0 AS url_weight) SELECT t.id, 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',
|
'WITH weights AS (SELECT 10.0 AS title_weight, 5.0 AS url_weight) SELECT t.id, 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',
|
||||||
|
|||||||
@@ -83,6 +83,14 @@ class ContainerRepository extends _$ContainerRepository {
|
|||||||
.getSingle();
|
.getSingle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String> getOrderKeyBeforeTab(String tabId, String? containerId) {
|
||||||
|
return ref
|
||||||
|
.read(tabDatabaseProvider)
|
||||||
|
.containerDao
|
||||||
|
.generateOrderKeyBeforeTabId(containerId, tabId)
|
||||||
|
.getSingle();
|
||||||
|
}
|
||||||
|
|
||||||
Future<Color> unusedRandomContainerColor() async {
|
Future<Color> unusedRandomContainerColor() async {
|
||||||
final allColors = colorTypes.flattened.toList();
|
final allColors = colorTypes.flattened.toList();
|
||||||
final usedColors = await getDistinctColors();
|
final usedColors = await getDistinctColors();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'container.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$containerRepositoryHash() =>
|
String _$containerRepositoryHash() =>
|
||||||
r'5344ecde33c1c80c1fa2bc8383faca181da91593';
|
r'af4ccf6cc12eebae2313df6c8f9ca63db842ffe5';
|
||||||
|
|
||||||
/// See also [ContainerRepository].
|
/// See also [ContainerRepository].
|
||||||
@ProviderFor(ContainerRepository)
|
@ProviderFor(ContainerRepository)
|
||||||
|
|||||||
+4
-1
@@ -24,7 +24,10 @@ dependencies:
|
|||||||
flutter_material_design_icons: ^1.1.7447
|
flutter_material_design_icons: ^1.1.7447
|
||||||
flutter_mozilla_components:
|
flutter_mozilla_components:
|
||||||
path: ../packages/flutter_mozilla_components
|
path: ../packages/flutter_mozilla_components
|
||||||
flutter_reorderable_grid_view: ^5.5.0
|
flutter_reorderable_grid_view:
|
||||||
|
git:
|
||||||
|
url: https://github.com/FaFre/flutter-reorderable-grid-view.git
|
||||||
|
ref: fix_builder_assert
|
||||||
flutter_secure_storage: ^10.0.0-beta.4
|
flutter_secure_storage: ^10.0.0-beta.4
|
||||||
flutter_slidable: ^4.0.0
|
flutter_slidable: ^4.0.0
|
||||||
flutter_svg: ^2.2.0
|
flutter_svg: ^2.2.0
|
||||||
|
|||||||
Reference in New Issue
Block a user