fix tab navigation order
This commit is contained in:
@@ -39,6 +39,7 @@ import 'package:weblibre/features/geckoview/domain/providers/tab_detail_state.da
|
||||
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/browser/domain/controllers/home_target_controller.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/domain/providers.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/domain/services/browser_data.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/database/database.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/entities/isolation_context.dart';
|
||||
@@ -446,35 +447,83 @@ class TabRepository extends _$TabRepository {
|
||||
String tabId, {
|
||||
String? containerId,
|
||||
bool skipContainerCheck = true,
|
||||
}) async {
|
||||
final previousTabId = await _adjacentVisibleTabByOrder(
|
||||
tabId,
|
||||
containerId: containerId,
|
||||
skipContainerCheck: skipContainerCheck,
|
||||
selectPrevious: true,
|
||||
);
|
||||
|
||||
if (ref.mounted && previousTabId != null) {
|
||||
return selectTab(previousTabId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}) => _selectAdjacentTab(
|
||||
tabId,
|
||||
containerId: containerId,
|
||||
skipContainerCheck: skipContainerCheck,
|
||||
selectPrevious: true,
|
||||
);
|
||||
|
||||
Future<bool> selectNextTab(
|
||||
String tabId, {
|
||||
String? containerId,
|
||||
bool skipContainerCheck = true,
|
||||
}) => _selectAdjacentTab(
|
||||
tabId,
|
||||
containerId: containerId,
|
||||
skipContainerCheck: skipContainerCheck,
|
||||
selectPrevious: false,
|
||||
);
|
||||
|
||||
/// Moves the selection one step through the tab sequence.
|
||||
///
|
||||
/// Unscoped calls — the tab bar swipe and the next/previous tab gestures —
|
||||
/// step through the *rendered* order
|
||||
/// ([sequentialTabNavigationOrderProvider]) so navigation matches the tabs the
|
||||
/// user sees, including the tray's sort type, grouping, filters and
|
||||
/// pinned-first handling. That order is authoritative once it exists, and
|
||||
/// every outcome stays inside it:
|
||||
///
|
||||
/// - current tab in the order: step one row, stopping at either end;
|
||||
/// - current tab outside it — hidden by the active filter, or folded into a
|
||||
/// collapsed group — enter the visible sequence from the end the step comes
|
||||
/// from, rather than jumping to a tab the filter excludes;
|
||||
/// - nothing visible at all: do nothing.
|
||||
///
|
||||
/// The storage-order path is left for calls that scope navigation to a
|
||||
/// container (which the rendered order, tied to the selected container, cannot
|
||||
/// answer) and for the brief window before the tree data has loaded.
|
||||
Future<bool> _selectAdjacentTab(
|
||||
String tabId, {
|
||||
required String? containerId,
|
||||
required bool skipContainerCheck,
|
||||
required bool selectPrevious,
|
||||
}) async {
|
||||
final previousTabId = await _adjacentVisibleTabByOrder(
|
||||
if (containerId == null && skipContainerCheck) {
|
||||
final visibleOrder = ref.read(sequentialTabNavigationOrderProvider).value;
|
||||
|
||||
if (visibleOrder != null) {
|
||||
if (visibleOrder.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final index = visibleOrder.indexOf(tabId);
|
||||
|
||||
if (index < 0) {
|
||||
return selectTab(
|
||||
selectPrevious ? visibleOrder.last : visibleOrder.first,
|
||||
);
|
||||
}
|
||||
|
||||
final targetIndex = selectPrevious ? index - 1 : index + 1;
|
||||
|
||||
if (targetIndex < 0 || targetIndex >= visibleOrder.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return selectTab(visibleOrder[targetIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
final adjacentTabId = await _adjacentVisibleTabByOrder(
|
||||
tabId,
|
||||
containerId: containerId,
|
||||
skipContainerCheck: skipContainerCheck,
|
||||
selectPrevious: false,
|
||||
selectPrevious: selectPrevious,
|
||||
);
|
||||
|
||||
if (ref.mounted && previousTabId != null) {
|
||||
return selectTab(previousTabId);
|
||||
if (ref.mounted && adjacentTabId != null) {
|
||||
return selectTab(adjacentTabId);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -546,12 +595,14 @@ class TabRepository extends _$TabRepository {
|
||||
required bool skipContainerCheck,
|
||||
required bool selectPrevious,
|
||||
}) {
|
||||
// "Previous/next" here is interpreted relative to the *tab bar*
|
||||
// direction, even when the user triggered the navigation from the tab
|
||||
// tray (which has its own `tabListDirection`). If the two settings
|
||||
// disagree, "next tab" while looking at the tray flows by tab-bar
|
||||
// direction. Treat as intentional — keyboard / gesture navigation is
|
||||
// anchored to the bar's mental model.
|
||||
// Storage-order walk: neighbours by `order_key` only, so it sees neither
|
||||
// the tray's sort and filters nor its grouping. User-facing sequential
|
||||
// navigation goes through the rendered order in [_selectAdjacentTab] and
|
||||
// reaches this only as a fallback; what remains here is picking a tab
|
||||
// after a close and container-scoped stepping.
|
||||
//
|
||||
// "Previous/next" is interpreted relative to the *tab bar* direction,
|
||||
// which is the only direction this path has to go by.
|
||||
final newestFirst =
|
||||
ref.read(generalSettingsWithDefaultsProvider).tabBarDirection ==
|
||||
TabDirection.newestFirst;
|
||||
@@ -946,6 +997,18 @@ class TabRepository extends _$TabRepository {
|
||||
|
||||
@override
|
||||
void build() {
|
||||
// Hold an active listener on the rendered navigation order: swipes and
|
||||
// gestures read it synchronously, and Riverpod pauses a provider nothing is
|
||||
// listening to — a one-off read would neither keep it current nor guarantee
|
||||
// it has data when the first swipe arrives. Listened rather than watched
|
||||
// because it changes with every tab update, which must not rebuild this
|
||||
// repository; the callback is intentionally empty.
|
||||
ref.listen(
|
||||
sequentialTabNavigationOrderProvider,
|
||||
(_, _) {},
|
||||
fireImmediately: true,
|
||||
);
|
||||
|
||||
final eventSerivce = ref.watch(eventServiceProvider);
|
||||
final tabContentService = ref.watch(tabContentServiceProvider);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ final class TabRepositoryProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$tabRepositoryHash() => r'c94ccf85da3fee36ebac3521f51f265a5f8d34d3';
|
||||
String _$tabRepositoryHash() => r'797520166026d1f0272cf713aa1c25ecf129c236';
|
||||
|
||||
abstract class _$TabRepository extends $Notifier<void> {
|
||||
void build();
|
||||
|
||||
@@ -1211,6 +1211,88 @@ EquatableValue<List<TabListItemEntity>> groupedTabListItems(
|
||||
return EquatableValue(result);
|
||||
}
|
||||
|
||||
/// The final row order the tab tray renders, i.e.
|
||||
/// [groupedTabListItemsProvider] plus the flat-mode post-processing: with
|
||||
/// hierarchy display turned off there are no groups to keep together, so
|
||||
/// pinned tabs move ahead of unpinned ones across the whole list.
|
||||
///
|
||||
/// Shared by the list view, the grid view and sequential tab navigation so all
|
||||
/// three agree on what "the tab after this one" means.
|
||||
@Riverpod()
|
||||
EquatableValue<List<TabListItemEntity>> visibleTabListItems(
|
||||
Ref ref, {
|
||||
required String? containerId,
|
||||
}) {
|
||||
final groupedItems = ref
|
||||
.watch(groupedTabListItemsProvider(containerId: containerId))
|
||||
.value;
|
||||
|
||||
final filterOptions = ref.watch(tabViewFilterControllerProvider);
|
||||
if (filterOptions.showHierarchicalTabs || !filterOptions.sortPinnedFirst) {
|
||||
return EquatableValue(groupedItems);
|
||||
}
|
||||
|
||||
final pinnedTabIds = ref.watch(
|
||||
watchPinnedTabIdsProvider.select(
|
||||
(value) => value.value ?? const <String>{},
|
||||
),
|
||||
);
|
||||
|
||||
return EquatableValue([
|
||||
...groupedItems.where((item) => pinnedTabIds.contains(item.tabId)),
|
||||
...groupedItems.where((item) => !pinnedTabIds.contains(item.tabId)),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Flat tab id order used by sequential tab navigation: the tab bar swipe
|
||||
/// action and the next/previous tab gestures.
|
||||
///
|
||||
/// Navigation follows the rendered tray order instead of the raw storage
|
||||
/// `order_key`, so it carries the active sort type, tree grouping, collapsed
|
||||
/// groups, pinned-first handling and the tab-type/date filter — stepping to the
|
||||
/// tab the user sees next to the current one rather than to an unrelated
|
||||
/// `order_key` neighbour.
|
||||
///
|
||||
/// "Previous" is a step towards the top of that order and "next" a step
|
||||
/// towards its end, so direction follows `tabListDirection` (baked into the
|
||||
/// order) rather than `tabBarDirection`. The two only disagree when the user
|
||||
/// sets them apart, and the tray order is the one the sequence is built from.
|
||||
///
|
||||
/// The tray's own search results are deliberately not part of this: the swipe
|
||||
/// and the gestures are only reachable with the tray closed.
|
||||
///
|
||||
/// `null` means the underlying tree data has not arrived yet — the only state
|
||||
/// in which the caller may fall back to storage order. An empty list is a real
|
||||
/// answer ("the filter leaves nothing to move to") and must not be mistaken for
|
||||
/// a missing one, or the filter the user set would be bypassed.
|
||||
///
|
||||
/// Kept alive and actively listened to by [TabRepository]: it is consumed by a
|
||||
/// synchronous `ref.read` at the moment of the swipe/gesture, from outside the
|
||||
/// widget tree. Without a listener Riverpod pauses the chain when nothing is on
|
||||
/// screen watching it, so the order could go stale — or be created empty on the
|
||||
/// read, with its tree stream still loading, and silently drop navigation back
|
||||
/// to storage order. It is alive anyway whenever the quick tab switcher or the
|
||||
/// tray is on screen — both watch the same [groupedTabListItemsProvider] chain.
|
||||
@Riverpod(keepAlive: true)
|
||||
EquatableValue<List<String>?> sequentialTabNavigationOrder(Ref ref) {
|
||||
final containerId = ref.watch(selectedContainerProvider);
|
||||
|
||||
final hasTreeData = ref.watch(
|
||||
watchTabsWithRootAndDepthProvider(
|
||||
containerId,
|
||||
).select((value) => value.hasValue),
|
||||
);
|
||||
if (!hasTreeData) {
|
||||
return EquatableValue(null);
|
||||
}
|
||||
|
||||
final visibleItems = ref
|
||||
.watch(visibleTabListItemsProvider(containerId: containerId))
|
||||
.value;
|
||||
|
||||
return EquatableValue([for (final item in visibleItems) item.tabId]);
|
||||
}
|
||||
|
||||
String _nearestVisibleParentId(
|
||||
TabsWithRootAndDepthResult row,
|
||||
String rootId,
|
||||
|
||||
@@ -1253,3 +1253,271 @@ final class GroupedTabListItemsFamily extends $Family
|
||||
@override
|
||||
String toString() => r'groupedTabListItemsProvider';
|
||||
}
|
||||
|
||||
/// The final row order the tab tray renders, i.e.
|
||||
/// [groupedTabListItemsProvider] plus the flat-mode post-processing: with
|
||||
/// hierarchy display turned off there are no groups to keep together, so
|
||||
/// pinned tabs move ahead of unpinned ones across the whole list.
|
||||
///
|
||||
/// Shared by the list view, the grid view and sequential tab navigation so all
|
||||
/// three agree on what "the tab after this one" means.
|
||||
|
||||
@ProviderFor(visibleTabListItems)
|
||||
final visibleTabListItemsProvider = VisibleTabListItemsFamily._();
|
||||
|
||||
/// The final row order the tab tray renders, i.e.
|
||||
/// [groupedTabListItemsProvider] plus the flat-mode post-processing: with
|
||||
/// hierarchy display turned off there are no groups to keep together, so
|
||||
/// pinned tabs move ahead of unpinned ones across the whole list.
|
||||
///
|
||||
/// Shared by the list view, the grid view and sequential tab navigation so all
|
||||
/// three agree on what "the tab after this one" means.
|
||||
|
||||
final class VisibleTabListItemsProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
EquatableValue<List<TabListItemEntity>>,
|
||||
EquatableValue<List<TabListItemEntity>>,
|
||||
EquatableValue<List<TabListItemEntity>>
|
||||
>
|
||||
with $Provider<EquatableValue<List<TabListItemEntity>>> {
|
||||
/// The final row order the tab tray renders, i.e.
|
||||
/// [groupedTabListItemsProvider] plus the flat-mode post-processing: with
|
||||
/// hierarchy display turned off there are no groups to keep together, so
|
||||
/// pinned tabs move ahead of unpinned ones across the whole list.
|
||||
///
|
||||
/// Shared by the list view, the grid view and sequential tab navigation so all
|
||||
/// three agree on what "the tab after this one" means.
|
||||
VisibleTabListItemsProvider._({
|
||||
required VisibleTabListItemsFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'visibleTabListItemsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$visibleTabListItemsHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'visibleTabListItemsProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<EquatableValue<List<TabListItemEntity>>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
EquatableValue<List<TabListItemEntity>> create(Ref ref) {
|
||||
final argument = this.argument as String?;
|
||||
return visibleTabListItems(ref, containerId: argument);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(EquatableValue<List<TabListItemEntity>> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride:
|
||||
$SyncValueProvider<EquatableValue<List<TabListItemEntity>>>(value),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is VisibleTabListItemsProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$visibleTabListItemsHash() =>
|
||||
r'5249a3e7e1f0b24e408987956856926d0958b0db';
|
||||
|
||||
/// The final row order the tab tray renders, i.e.
|
||||
/// [groupedTabListItemsProvider] plus the flat-mode post-processing: with
|
||||
/// hierarchy display turned off there are no groups to keep together, so
|
||||
/// pinned tabs move ahead of unpinned ones across the whole list.
|
||||
///
|
||||
/// Shared by the list view, the grid view and sequential tab navigation so all
|
||||
/// three agree on what "the tab after this one" means.
|
||||
|
||||
final class VisibleTabListItemsFamily extends $Family
|
||||
with
|
||||
$FunctionalFamilyOverride<
|
||||
EquatableValue<List<TabListItemEntity>>,
|
||||
String?
|
||||
> {
|
||||
VisibleTabListItemsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'visibleTabListItemsProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
/// The final row order the tab tray renders, i.e.
|
||||
/// [groupedTabListItemsProvider] plus the flat-mode post-processing: with
|
||||
/// hierarchy display turned off there are no groups to keep together, so
|
||||
/// pinned tabs move ahead of unpinned ones across the whole list.
|
||||
///
|
||||
/// Shared by the list view, the grid view and sequential tab navigation so all
|
||||
/// three agree on what "the tab after this one" means.
|
||||
|
||||
VisibleTabListItemsProvider call({required String? containerId}) =>
|
||||
VisibleTabListItemsProvider._(argument: containerId, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'visibleTabListItemsProvider';
|
||||
}
|
||||
|
||||
/// Flat tab id order used by sequential tab navigation: the tab bar swipe
|
||||
/// action and the next/previous tab gestures.
|
||||
///
|
||||
/// Navigation follows the rendered tray order instead of the raw storage
|
||||
/// `order_key`, so it carries the active sort type, tree grouping, collapsed
|
||||
/// groups, pinned-first handling and the tab-type/date filter — stepping to the
|
||||
/// tab the user sees next to the current one rather than to an unrelated
|
||||
/// `order_key` neighbour.
|
||||
///
|
||||
/// "Previous" is a step towards the top of that order and "next" a step
|
||||
/// towards its end, so direction follows `tabListDirection` (baked into the
|
||||
/// order) rather than `tabBarDirection`. The two only disagree when the user
|
||||
/// sets them apart, and the tray order is the one the sequence is built from.
|
||||
///
|
||||
/// The tray's own search results are deliberately not part of this: the swipe
|
||||
/// and the gestures are only reachable with the tray closed.
|
||||
///
|
||||
/// `null` means the underlying tree data has not arrived yet — the only state
|
||||
/// in which the caller may fall back to storage order. An empty list is a real
|
||||
/// answer ("the filter leaves nothing to move to") and must not be mistaken for
|
||||
/// a missing one, or the filter the user set would be bypassed.
|
||||
///
|
||||
/// Kept alive and actively listened to by [TabRepository]: it is consumed by a
|
||||
/// synchronous `ref.read` at the moment of the swipe/gesture, from outside the
|
||||
/// widget tree. Without a listener Riverpod pauses the chain when nothing is on
|
||||
/// screen watching it, so the order could go stale — or be created empty on the
|
||||
/// read, with its tree stream still loading, and silently drop navigation back
|
||||
/// to storage order. It is alive anyway whenever the quick tab switcher or the
|
||||
/// tray is on screen — both watch the same [groupedTabListItemsProvider] chain.
|
||||
|
||||
@ProviderFor(sequentialTabNavigationOrder)
|
||||
final sequentialTabNavigationOrderProvider =
|
||||
SequentialTabNavigationOrderProvider._();
|
||||
|
||||
/// Flat tab id order used by sequential tab navigation: the tab bar swipe
|
||||
/// action and the next/previous tab gestures.
|
||||
///
|
||||
/// Navigation follows the rendered tray order instead of the raw storage
|
||||
/// `order_key`, so it carries the active sort type, tree grouping, collapsed
|
||||
/// groups, pinned-first handling and the tab-type/date filter — stepping to the
|
||||
/// tab the user sees next to the current one rather than to an unrelated
|
||||
/// `order_key` neighbour.
|
||||
///
|
||||
/// "Previous" is a step towards the top of that order and "next" a step
|
||||
/// towards its end, so direction follows `tabListDirection` (baked into the
|
||||
/// order) rather than `tabBarDirection`. The two only disagree when the user
|
||||
/// sets them apart, and the tray order is the one the sequence is built from.
|
||||
///
|
||||
/// The tray's own search results are deliberately not part of this: the swipe
|
||||
/// and the gestures are only reachable with the tray closed.
|
||||
///
|
||||
/// `null` means the underlying tree data has not arrived yet — the only state
|
||||
/// in which the caller may fall back to storage order. An empty list is a real
|
||||
/// answer ("the filter leaves nothing to move to") and must not be mistaken for
|
||||
/// a missing one, or the filter the user set would be bypassed.
|
||||
///
|
||||
/// Kept alive and actively listened to by [TabRepository]: it is consumed by a
|
||||
/// synchronous `ref.read` at the moment of the swipe/gesture, from outside the
|
||||
/// widget tree. Without a listener Riverpod pauses the chain when nothing is on
|
||||
/// screen watching it, so the order could go stale — or be created empty on the
|
||||
/// read, with its tree stream still loading, and silently drop navigation back
|
||||
/// to storage order. It is alive anyway whenever the quick tab switcher or the
|
||||
/// tray is on screen — both watch the same [groupedTabListItemsProvider] chain.
|
||||
|
||||
final class SequentialTabNavigationOrderProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
EquatableValue<List<String>?>,
|
||||
EquatableValue<List<String>?>,
|
||||
EquatableValue<List<String>?>
|
||||
>
|
||||
with $Provider<EquatableValue<List<String>?>> {
|
||||
/// Flat tab id order used by sequential tab navigation: the tab bar swipe
|
||||
/// action and the next/previous tab gestures.
|
||||
///
|
||||
/// Navigation follows the rendered tray order instead of the raw storage
|
||||
/// `order_key`, so it carries the active sort type, tree grouping, collapsed
|
||||
/// groups, pinned-first handling and the tab-type/date filter — stepping to the
|
||||
/// tab the user sees next to the current one rather than to an unrelated
|
||||
/// `order_key` neighbour.
|
||||
///
|
||||
/// "Previous" is a step towards the top of that order and "next" a step
|
||||
/// towards its end, so direction follows `tabListDirection` (baked into the
|
||||
/// order) rather than `tabBarDirection`. The two only disagree when the user
|
||||
/// sets them apart, and the tray order is the one the sequence is built from.
|
||||
///
|
||||
/// The tray's own search results are deliberately not part of this: the swipe
|
||||
/// and the gestures are only reachable with the tray closed.
|
||||
///
|
||||
/// `null` means the underlying tree data has not arrived yet — the only state
|
||||
/// in which the caller may fall back to storage order. An empty list is a real
|
||||
/// answer ("the filter leaves nothing to move to") and must not be mistaken for
|
||||
/// a missing one, or the filter the user set would be bypassed.
|
||||
///
|
||||
/// Kept alive and actively listened to by [TabRepository]: it is consumed by a
|
||||
/// synchronous `ref.read` at the moment of the swipe/gesture, from outside the
|
||||
/// widget tree. Without a listener Riverpod pauses the chain when nothing is on
|
||||
/// screen watching it, so the order could go stale — or be created empty on the
|
||||
/// read, with its tree stream still loading, and silently drop navigation back
|
||||
/// to storage order. It is alive anyway whenever the quick tab switcher or the
|
||||
/// tray is on screen — both watch the same [groupedTabListItemsProvider] chain.
|
||||
SequentialTabNavigationOrderProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'sequentialTabNavigationOrderProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$sequentialTabNavigationOrderHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<EquatableValue<List<String>?>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
EquatableValue<List<String>?> create(Ref ref) {
|
||||
return sequentialTabNavigationOrder(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(EquatableValue<List<String>?> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<EquatableValue<List<String>?>>(
|
||||
value,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$sequentialTabNavigationOrderHash() =>
|
||||
r'2a6b1965657942524e8e514cd4deb0ce77667fe1';
|
||||
|
||||
+5
-2
@@ -380,7 +380,10 @@ class BrowserTabBar extends HookConsumerWidget {
|
||||
final dragStartPosition = useRef(Offset.zero);
|
||||
|
||||
// Swipe along the primary switch axis moves between tabs. [delta] is
|
||||
// (dragStart - dragEnd) along that axis; its sign chooses prev/next.
|
||||
// (dragStart - dragEnd) along that axis, so a right-to-left (or upward)
|
||||
// swipe is positive and moves *up* the visible tab order, a rightward (or
|
||||
// downward) swipe moves down it — the swipe drags the list under the
|
||||
// finger.
|
||||
Future<void> switchTabsBy(double delta) async {
|
||||
final selectedTab = ref.read(selectedTabProvider);
|
||||
final setting = await ref
|
||||
@@ -395,7 +398,7 @@ class BrowserTabBar extends HookConsumerWidget {
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectPreviouslyOpenedTab(selectedTab);
|
||||
case TabBarSwipeAction.navigateOrderedTabs:
|
||||
if (delta < 0) {
|
||||
if (delta > 0) {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectPreviousTab(selectedTab);
|
||||
|
||||
+3
-12
@@ -222,11 +222,11 @@ class _TabGridView extends HookConsumerWidget {
|
||||
),
|
||||
];
|
||||
} else {
|
||||
final grouped = ref.watch(
|
||||
groupedTabListItemsProvider(containerId: containerId),
|
||||
final visibleItems = ref.watch(
|
||||
visibleTabListItemsProvider(containerId: containerId),
|
||||
);
|
||||
primaryRows = [
|
||||
for (final item in grouped.value)
|
||||
for (final item in visibleItems.value)
|
||||
switch (item) {
|
||||
TabListStandaloneItem(:final tabId) => TabViewItem.standalone(
|
||||
tabId: tabId,
|
||||
@@ -241,15 +241,6 @@ class _TabGridView extends HookConsumerWidget {
|
||||
: TabViewItem.standalone(tabId: c.tabId),
|
||||
},
|
||||
];
|
||||
if (!showHierarchicalTabs && filterOptions.sortPinnedFirst) {
|
||||
final pinned = primaryRows
|
||||
.where((r) => pinnedTabIds.contains(r.tabId))
|
||||
.toList();
|
||||
final unpinned = primaryRows
|
||||
.where((r) => !pinnedTabIds.contains(r.tabId))
|
||||
.toList();
|
||||
primaryRows = [...pinned, ...unpinned];
|
||||
}
|
||||
}
|
||||
|
||||
final tabSuggestionsEnabled = ref.watch(
|
||||
|
||||
+3
-12
@@ -283,11 +283,11 @@ class _TabListView extends HookConsumerWidget {
|
||||
),
|
||||
];
|
||||
} else {
|
||||
final grouped = ref.watch(
|
||||
groupedTabListItemsProvider(containerId: containerId),
|
||||
final visibleItems = ref.watch(
|
||||
visibleTabListItemsProvider(containerId: containerId),
|
||||
);
|
||||
primaryRows = [
|
||||
for (final item in grouped.value)
|
||||
for (final item in visibleItems.value)
|
||||
switch (item) {
|
||||
TabListStandaloneItem(:final tabId) => TabViewItem.standalone(
|
||||
tabId: tabId,
|
||||
@@ -302,15 +302,6 @@ class _TabListView extends HookConsumerWidget {
|
||||
: TabViewItem.standalone(tabId: c.tabId),
|
||||
},
|
||||
];
|
||||
if (!showHierarchicalTabs && filterOptions.sortPinnedFirst) {
|
||||
final pinned = primaryRows
|
||||
.where((r) => pinnedTabIds.contains(r.tabId))
|
||||
.toList();
|
||||
final unpinned = primaryRows
|
||||
.where((r) => !pinnedTabIds.contains(r.tabId))
|
||||
.toList();
|
||||
primaryRows = [...pinned, ...unpinned];
|
||||
}
|
||||
}
|
||||
|
||||
final tabSuggestionsEnabled = ref.watch(
|
||||
|
||||
Reference in New Issue
Block a user