new setting to define tab bar swipe action

This commit is contained in:
Fabian Freund
2025-08-27 10:46:45 +02:00
parent 9a8e9c228b
commit 2b163f2cbb
12 changed files with 234 additions and 36 deletions
@@ -7,7 +7,7 @@ part of 'providers.dart';
// **************************************************************************
String _$selectionActionServiceHash() =>
r'b1deac5e0566443b4729656c7082903b529bc269';
r'c89d981c2ba253ed940887fa59c11ad93d8589a8';
/// See also [selectionActionService].
@ProviderFor(selectionActionService)
@@ -48,7 +48,6 @@ part 'tab.g.dart';
class TabRepository extends _$TabRepository {
final _tabsService = GeckoTabService();
String? _previousTabId;
final _tabFromIntent = <String>{};
bool hasLaunchedFromIntent(String? tabId) {
@@ -124,9 +123,40 @@ class TabRepository extends _$TabRepository {
);
}
Future<bool> selectPreviousTab() async {
if (_previousTabId != null) {
return selectTab(_previousTabId!);
Future<bool> selectPreviouslyOpenedTab(String tabId) async {
final previousTabId = await ref
.read(tabDatabaseProvider)
.previousTabByTimestamp(tabId: tabId)
.getSingleOrNull();
if (previousTabId != null) {
return selectTab(previousTabId);
}
return false;
}
Future<bool> selectPreviousTab(String tabId) async {
final previousTabId = await ref
.read(tabDatabaseProvider)
.previousTabByOrderKey(tabId: tabId)
.getSingleOrNull();
if (previousTabId != null) {
return selectTab(previousTabId);
}
return false;
}
Future<bool> selectNextTab(String tabId) async {
final previousTabId = await ref
.read(tabDatabaseProvider)
.nextTabByOrderKey(tabId: tabId)
.getSingleOrNull();
if (previousTabId != null) {
return selectTab(previousTabId);
}
return false;
@@ -283,7 +313,6 @@ class TabRepository extends _$TabRepository {
selectedTabProvider,
(previous, tabId) async {
if (tabId != null) {
_previousTabId = previous;
await db.tabDao.touchTab(tabId, timestamp: DateTime.now());
}
},
@@ -303,10 +332,6 @@ class TabRepository extends _$TabRepository {
final syncTabs =
next.value.isNotEmpty || (previous?.value.isNotEmpty ?? false);
if (_previousTabId != null && !next.value.contains(_previousTabId)) {
_previousTabId = null;
}
if (syncTabs) {
await db.tabDao.syncTabs(retainTabIds: next.value);
}
@@ -6,7 +6,7 @@ part of 'tab.dart';
// RiverpodGenerator
// **************************************************************************
String _$tabRepositoryHash() => r'3465f351f1d36e0f21b4e8ef4ebe7fdc4fbc0b75';
String _$tabRepositoryHash() => r'4f562c1456eadcda7986ea2048667dd083f37618';
/// See also [TabRepository].
@ProviderFor(TabRepository)
@@ -42,6 +42,7 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/widget
import 'package:weblibre/features/geckoview/features/find_in_page/presentation/controllers/find_in_page.dart';
import 'package:weblibre/features/geckoview/features/readerview/presentation/controllers/readerable.dart';
import 'package:weblibre/features/geckoview/features/readerview/presentation/widgets/reader_button.dart';
import 'package:weblibre/features/user/data/models/general_settings.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
import 'package:weblibre/presentation/hooks/menu_controller.dart';
import 'package:weblibre/presentation/icons/tor_icons.dart';
@@ -93,7 +94,29 @@ class BrowserBottomAppBar extends HookConsumerWidget {
final distance = dragStartPosition.value - details.globalPosition;
if (distance.dx.abs() > 50) {
await ref.read(tabRepositoryProvider.notifier).selectPreviousTab();
final selectedTab = ref.read(selectedTabProvider);
final setting = await ref
.read(generalSettingsRepositoryProvider.notifier)
.fetchSettings();
if (selectedTab != null) {
switch (setting.tabBarSwipeAction) {
case TabBarSwipeAction.switchLastOpened:
await ref
.read(tabRepositoryProvider.notifier)
.selectPreviouslyOpenedTab(selectedTab);
case TabBarSwipeAction.navigateOrderedTabs:
if (distance.dx < 0) {
await ref
.read(tabRepositoryProvider.notifier)
.selectPreviousTab(selectedTab);
} else {
await ref
.read(tabRepositoryProvider.notifier)
.selectNextTab(selectedTab);
}
}
}
}
},
child: AppBar(
@@ -240,4 +240,34 @@ unorderedTabDescendants:
JOIN descendants d ON t.parent_id = d.id
)
SELECT id, parent_id
FROM descendants;
FROM descendants;
previousTabByTimestamp:
WITH ranked_tabs AS (
SELECT id, timestamp,
LAG(id) OVER (ORDER BY timestamp) as prev_tab_id
FROM tab
)
SELECT prev_tab_id
FROM ranked_tabs
WHERE id = :tab_id;
previousTabByOrderKey:
WITH ranked_tabs AS (
SELECT id, order_key,
LAG(id) OVER (ORDER BY order_key) as prev_tab_id
FROM tab
)
SELECT prev_tab_id
FROM ranked_tabs
WHERE id = :tab_id;
nextTabByOrderKey:
WITH ranked_tabs AS (
SELECT id, order_key,
LEAD(id) OVER (ORDER BY order_key) as next_tab_id
FROM tab
)
SELECT next_tab_id
FROM ranked_tabs
WHERE id = :tab_id;
@@ -1256,6 +1256,30 @@ abstract class _$TabDatabase extends GeneratedDatabase {
);
}
Selectable<String> previousTabByTimestamp({required String tabId}) {
return customSelect(
'WITH ranked_tabs AS (SELECT id, timestamp, LAG(id)OVER (ORDER BY timestamp RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE NO OTHERS) AS prev_tab_id FROM tab) SELECT prev_tab_id FROM ranked_tabs WHERE id = ?1',
variables: [Variable<String>(tabId)],
readsFrom: {tab},
).map((QueryRow row) => row.read<String>('prev_tab_id'));
}
Selectable<String> previousTabByOrderKey({required String tabId}) {
return customSelect(
'WITH ranked_tabs AS (SELECT id, order_key, LAG(id)OVER (ORDER BY order_key RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE NO OTHERS) AS prev_tab_id FROM tab) SELECT prev_tab_id FROM ranked_tabs WHERE id = ?1',
variables: [Variable<String>(tabId)],
readsFrom: {tab},
).map((QueryRow row) => row.read<String>('prev_tab_id'));
}
Selectable<String> nextTabByOrderKey({required String tabId}) {
return customSelect(
'WITH ranked_tabs AS (SELECT id, order_key, LEAD(id)OVER (ORDER BY order_key RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE NO OTHERS) AS next_tab_id FROM tab) SELECT next_tab_id FROM ranked_tabs WHERE id = ?1',
variables: [Variable<String>(tabId)],
readsFrom: {tab},
).map((QueryRow row) => row.read<String>('next_tab_id'));
}
@override
Iterable<TableInfo<Table, Object?>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
@@ -6,7 +6,7 @@ part of 'tab.dart';
// RiverpodGenerator
// **************************************************************************
String _$tabDataRepositoryHash() => r'be1bb8a8118c7bfd90d0f1ac89a04c0a2149a0b0';
String _$tabDataRepositoryHash() => r'295c1718ecf41202709517fb2c5b31527e885dfa';
/// See also [TabDataRepository].
@ProviderFor(TabDataRepository)