fix new tab assignments
This commit is contained in:
@@ -21,12 +21,14 @@ import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:synchronized/synchronized.dart';
|
||||
import 'package:weblibre/core/logger.dart';
|
||||
import 'package:weblibre/core/routing/routes.dart';
|
||||
import 'package:weblibre/extensions/uri.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/entities/tab_container_selection.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers.dart';
|
||||
@@ -50,6 +52,20 @@ import 'package:weblibre/utils/debouncer.dart';
|
||||
|
||||
part 'tab.g.dart';
|
||||
|
||||
@visibleForTesting
|
||||
ContainerData? resolveAssignedContainerForTabOpen({
|
||||
required TabContainerSelection containerSelection,
|
||||
required ContainerData? requestedContainer,
|
||||
required ContainerData? siteAssignedContainer,
|
||||
}) {
|
||||
return switch (containerSelection) {
|
||||
UseSelectedContainerTabSelection() =>
|
||||
siteAssignedContainer ?? requestedContainer,
|
||||
UnassignedContainerTabSelection() ||
|
||||
SpecificContainerTabSelection() => requestedContainer,
|
||||
};
|
||||
}
|
||||
|
||||
sealed class TabBackPromptBehavior {
|
||||
const TabBackPromptBehavior();
|
||||
}
|
||||
@@ -124,13 +140,32 @@ class TabRepository extends _$TabRepository {
|
||||
}) async {
|
||||
final tabDao = ref.read(tabDatabaseProvider).tabDao;
|
||||
|
||||
final assignedContainer = switch (containerSelection) {
|
||||
var assignedContainer = switch (containerSelection) {
|
||||
UseSelectedContainerTabSelection() =>
|
||||
await ref.read(selectedContainerProvider.notifier).fetchData(),
|
||||
UnassignedContainerTabSelection() => null,
|
||||
SpecificContainerTabSelection(:final container) => container,
|
||||
};
|
||||
|
||||
if (tabMode is RegularTabMode &&
|
||||
url != null &&
|
||||
url.hasAuthority &&
|
||||
url.isHttpOrHttps) {
|
||||
final siteAssignedContainerId = await ref
|
||||
.read(containerRepositoryProvider.notifier)
|
||||
.siteAssignedContainerId(url);
|
||||
final siteAssignedContainer = await siteAssignedContainerId.mapNotNull(
|
||||
(id) =>
|
||||
ref.read(containerRepositoryProvider.notifier).getContainerData(id),
|
||||
);
|
||||
|
||||
assignedContainer = resolveAssignedContainerForTabOpen(
|
||||
containerSelection: containerSelection,
|
||||
requestedContainer: assignedContainer,
|
||||
siteAssignedContainer: siteAssignedContainer,
|
||||
);
|
||||
}
|
||||
|
||||
// For isolated tabs, skip parent context validation since
|
||||
// isolated tabs use their own immutable context ID.
|
||||
final validatedParentId = tabMode is IsolatedTabMode
|
||||
@@ -869,7 +904,7 @@ class TabRepository extends _$TabRepository {
|
||||
currentTabState.historyState.items.isEmpty;
|
||||
|
||||
if (event.blocked || tabIsEmpty) {
|
||||
await addTab(
|
||||
final newTabId = await addTab(
|
||||
url: uri,
|
||||
tabMode: currentTabState.tabMode,
|
||||
containerSelection: TabContainerSelection.specific(
|
||||
@@ -885,6 +920,10 @@ class TabRepository extends _$TabRepository {
|
||||
|
||||
if (currentTabState.historyState.items.isEmpty) {
|
||||
await closeTab(currentTabState.id);
|
||||
if (!ref.mounted) {
|
||||
return;
|
||||
}
|
||||
await selectTab(newTabId);
|
||||
}
|
||||
} else {
|
||||
final tabContainerId = await ref
|
||||
|
||||
@@ -65,11 +65,17 @@ _buildSharingIntentTransformer(
|
||||
final shortcutContextId = intent.action == 'android.intent.action.VIEW'
|
||||
? intent.extra['pwa_context_id'] as String?
|
||||
: null;
|
||||
final shortcutContainerMode =
|
||||
intent.extra['shortcut_container_mode'] as String?;
|
||||
final hasShortcutContainerMetadata =
|
||||
shortcutContextId != null || shortcutContainerMode != null;
|
||||
final containerMode = intent.action == 'android.intent.action.VIEW'
|
||||
? IntentContainerMode.fromWireValue(
|
||||
intent.extra['shortcut_container_mode'] as String?,
|
||||
contextId: shortcutContextId,
|
||||
)
|
||||
? hasShortcutContainerMetadata
|
||||
? IntentContainerMode.fromWireValue(
|
||||
shortcutContainerMode,
|
||||
contextId: shortcutContextId,
|
||||
)
|
||||
: IntentContainerMode.unassigned
|
||||
: IntentContainerMode.useSelected;
|
||||
|
||||
final allowed = await gatekeeper.shouldAllow(
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/entities/tab_container_selection.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart';
|
||||
|
||||
void main() {
|
||||
group('resolveAssignedContainerForTabOpen', () {
|
||||
final selectedContainer = _container('selected', 'selected-context');
|
||||
final siteAssignedContainer = _container('assigned', 'assigned-context');
|
||||
|
||||
test('prefers the site-assigned container for useSelected', () {
|
||||
final resolved = resolveAssignedContainerForTabOpen(
|
||||
containerSelection: const TabContainerSelection.useSelected(),
|
||||
requestedContainer: selectedContainer,
|
||||
siteAssignedContainer: siteAssignedContainer,
|
||||
);
|
||||
|
||||
expect(resolved, siteAssignedContainer);
|
||||
});
|
||||
|
||||
test(
|
||||
'falls back to the requested container when no site assignment exists',
|
||||
() {
|
||||
final resolved = resolveAssignedContainerForTabOpen(
|
||||
containerSelection: const TabContainerSelection.useSelected(),
|
||||
requestedContainer: selectedContainer,
|
||||
siteAssignedContainer: null,
|
||||
);
|
||||
|
||||
expect(resolved, selectedContainer);
|
||||
},
|
||||
);
|
||||
|
||||
test('preserves an explicit specific container selection', () {
|
||||
final explicitContainer = _container('explicit', 'explicit-context');
|
||||
|
||||
final resolved = resolveAssignedContainerForTabOpen(
|
||||
containerSelection: TabContainerSelection.specific(explicitContainer),
|
||||
requestedContainer: explicitContainer,
|
||||
siteAssignedContainer: siteAssignedContainer,
|
||||
);
|
||||
|
||||
expect(resolved, explicitContainer);
|
||||
});
|
||||
|
||||
test('preserves an explicit unassigned selection', () {
|
||||
final resolved = resolveAssignedContainerForTabOpen(
|
||||
containerSelection: const TabContainerSelection.unassigned(),
|
||||
requestedContainer: null,
|
||||
siteAssignedContainer: siteAssignedContainer,
|
||||
);
|
||||
|
||||
expect(resolved, isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ContainerData _container(String id, String contextId) {
|
||||
return ContainerData(
|
||||
id: id,
|
||||
name: id,
|
||||
color: Colors.blue,
|
||||
orderKey: id,
|
||||
metadata: ContainerMetadata.withDefaults(contextualIdentity: contextId),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user