container pinning

This commit is contained in:
Fabian Freund
2026-05-26 11:20:33 +02:00
parent a1e2680c48
commit 1ac4b20469
4 changed files with 57 additions and 7 deletions
@@ -59,6 +59,7 @@ import 'package:weblibre/features/user/domain/repositories/general_settings.dart
import 'package:weblibre/features/web_search/domain/controllers/sandbox_capture_controller.dart';
import 'package:weblibre/presentation/widgets/selectable_chips.dart';
import 'package:weblibre/presentation/widgets/url_icon.dart';
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
class BrowserTopAppBar extends StatelessWidget {
final bool showMainToolbar;
@@ -705,7 +706,15 @@ class QuickTabSwitcher extends HookConsumerWidget {
hierarchical: false,
sortPinnedFirst: sortPinnedFirst,
);
if (result == null) return;
if (result == null) {
if (context.mounted) {
ui_helper.showInfoMessage(
context,
'Tab cannot be moved here',
);
}
return;
}
await ref
.read(tabDataRepositoryProvider.notifier)
.reorderTabs(
@@ -97,6 +97,7 @@ class ContainerEditScreen extends HookConsumerWidget {
);
final clearDataOnExit = useState(initialContainer.metadata.clearDataOnExit);
final assignedSites = useState(initialContainer.metadata.assignedSites);
final isPinned = useState(initialContainer.isPinned);
final textController = useTextEditingController(
text: initialContainer.name,
@@ -108,6 +109,7 @@ class ContainerEditScreen extends HookConsumerWidget {
return initialContainer.copyWith(
name: name.isNotEmpty ? name : null,
color: selectedColor.value,
isPinned: isPinned.value,
metadata: initialContainer.metadata.copyWith(
contextualIdentity: contextualIdentity.value,
iconData: selectedIcon.value,
@@ -123,15 +125,18 @@ class ContainerEditScreen extends HookConsumerWidget {
Future<ContainerData> saveContainer() async {
final container = buildContainer();
final repository = ref.read(containerRepositoryProvider.notifier);
switch (_mode) {
case _DialogMode.create:
await ref
.read(containerRepositoryProvider.notifier)
.addContainer(container);
await repository.addContainer(container);
case _DialogMode.edit:
await ref
.read(containerRepositoryProvider.notifier)
.replaceContainer(container);
await repository.replaceContainer(container);
}
if (isPinned.value != initialContainer.isPinned) {
await repository.setContainerPinned(
container.id,
isPinned: isPinned.value,
);
}
return container;
}
@@ -341,6 +346,31 @@ class ContainerEditScreen extends HookConsumerWidget {
),
),
const SizedBox(height: 28),
Text(
'Display',
style: theme.textTheme.titleSmall?.copyWith(
color: colorScheme.primary,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 12),
Card.filled(
margin: EdgeInsets.zero,
color: colorScheme.surfaceContainer,
clipBehavior: Clip.antiAlias,
child: SwitchListTile.adaptive(
value: isPinned.value,
title: const Text('Pin Container'),
subtitle: const Text(
'Keep this container at the top of the list',
),
secondary: const Icon(MdiIcons.pin),
onChanged: (value) {
isPinned.value = value;
},
),
),
const SizedBox(height: 24),
Text(
'Privacy & Security',
style: theme.textTheme.titleSmall?.copyWith(
@@ -21,6 +21,7 @@ import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:skeletonizer/skeletonizer.dart';
import 'package:weblibre/core/routing/routes.dart';
@@ -246,6 +247,11 @@ class _ContainerCard extends HookConsumerWidget {
label:
'$tabCount ${tabCount == 1 ? 'tab' : 'tabs'}',
),
if (container.isPinned)
const _ContainerInfoChip(
icon: MdiIcons.pin,
label: 'Pinned',
),
if (container.metadata.contextualIdentity != null)
const _ContainerInfoChip(
icon: Icons.cookie_outlined,
@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter/material.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:nullability/nullability.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart';
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_title.dart';
@@ -62,6 +63,10 @@ Widget buildContainerChipLabel(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (container.isPinned) ...[
Icon(MdiIcons.pin, size: 14, color: foregroundColor),
const SizedBox(width: 4),
],
Flexible(child: ContainerTitle(container: container)),
if (trailing != null) ...[const SizedBox(width: 6), trailing],
],