container pinning
This commit is contained in:
+10
-1
@@ -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/features/web_search/domain/controllers/sandbox_capture_controller.dart';
|
||||||
import 'package:weblibre/presentation/widgets/selectable_chips.dart';
|
import 'package:weblibre/presentation/widgets/selectable_chips.dart';
|
||||||
import 'package:weblibre/presentation/widgets/url_icon.dart';
|
import 'package:weblibre/presentation/widgets/url_icon.dart';
|
||||||
|
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
||||||
|
|
||||||
class BrowserTopAppBar extends StatelessWidget {
|
class BrowserTopAppBar extends StatelessWidget {
|
||||||
final bool showMainToolbar;
|
final bool showMainToolbar;
|
||||||
@@ -705,7 +706,15 @@ class QuickTabSwitcher extends HookConsumerWidget {
|
|||||||
hierarchical: false,
|
hierarchical: false,
|
||||||
sortPinnedFirst: sortPinnedFirst,
|
sortPinnedFirst: sortPinnedFirst,
|
||||||
);
|
);
|
||||||
if (result == null) return;
|
if (result == null) {
|
||||||
|
if (context.mounted) {
|
||||||
|
ui_helper.showInfoMessage(
|
||||||
|
context,
|
||||||
|
'Tab cannot be moved here',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
await ref
|
await ref
|
||||||
.read(tabDataRepositoryProvider.notifier)
|
.read(tabDataRepositoryProvider.notifier)
|
||||||
.reorderTabs(
|
.reorderTabs(
|
||||||
|
|||||||
+36
-6
@@ -97,6 +97,7 @@ class ContainerEditScreen extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
final clearDataOnExit = useState(initialContainer.metadata.clearDataOnExit);
|
final clearDataOnExit = useState(initialContainer.metadata.clearDataOnExit);
|
||||||
final assignedSites = useState(initialContainer.metadata.assignedSites);
|
final assignedSites = useState(initialContainer.metadata.assignedSites);
|
||||||
|
final isPinned = useState(initialContainer.isPinned);
|
||||||
|
|
||||||
final textController = useTextEditingController(
|
final textController = useTextEditingController(
|
||||||
text: initialContainer.name,
|
text: initialContainer.name,
|
||||||
@@ -108,6 +109,7 @@ class ContainerEditScreen extends HookConsumerWidget {
|
|||||||
return initialContainer.copyWith(
|
return initialContainer.copyWith(
|
||||||
name: name.isNotEmpty ? name : null,
|
name: name.isNotEmpty ? name : null,
|
||||||
color: selectedColor.value,
|
color: selectedColor.value,
|
||||||
|
isPinned: isPinned.value,
|
||||||
metadata: initialContainer.metadata.copyWith(
|
metadata: initialContainer.metadata.copyWith(
|
||||||
contextualIdentity: contextualIdentity.value,
|
contextualIdentity: contextualIdentity.value,
|
||||||
iconData: selectedIcon.value,
|
iconData: selectedIcon.value,
|
||||||
@@ -123,15 +125,18 @@ class ContainerEditScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
Future<ContainerData> saveContainer() async {
|
Future<ContainerData> saveContainer() async {
|
||||||
final container = buildContainer();
|
final container = buildContainer();
|
||||||
|
final repository = ref.read(containerRepositoryProvider.notifier);
|
||||||
switch (_mode) {
|
switch (_mode) {
|
||||||
case _DialogMode.create:
|
case _DialogMode.create:
|
||||||
await ref
|
await repository.addContainer(container);
|
||||||
.read(containerRepositoryProvider.notifier)
|
|
||||||
.addContainer(container);
|
|
||||||
case _DialogMode.edit:
|
case _DialogMode.edit:
|
||||||
await ref
|
await repository.replaceContainer(container);
|
||||||
.read(containerRepositoryProvider.notifier)
|
}
|
||||||
.replaceContainer(container);
|
if (isPinned.value != initialContainer.isPinned) {
|
||||||
|
await repository.setContainerPinned(
|
||||||
|
container.id,
|
||||||
|
isPinned: isPinned.value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
@@ -341,6 +346,31 @@ class ContainerEditScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 28),
|
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(
|
Text(
|
||||||
'Privacy & Security',
|
'Privacy & Security',
|
||||||
style: theme.textTheme.titleSmall?.copyWith(
|
style: theme.textTheme.titleSmall?.copyWith(
|
||||||
|
|||||||
+6
@@ -21,6 +21,7 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
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:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:skeletonizer/skeletonizer.dart';
|
import 'package:skeletonizer/skeletonizer.dart';
|
||||||
import 'package:weblibre/core/routing/routes.dart';
|
import 'package:weblibre/core/routing/routes.dart';
|
||||||
@@ -246,6 +247,11 @@ class _ContainerCard extends HookConsumerWidget {
|
|||||||
label:
|
label:
|
||||||
'$tabCount ${tabCount == 1 ? 'tab' : 'tabs'}',
|
'$tabCount ${tabCount == 1 ? 'tab' : 'tabs'}',
|
||||||
),
|
),
|
||||||
|
if (container.isPinned)
|
||||||
|
const _ContainerInfoChip(
|
||||||
|
icon: MdiIcons.pin,
|
||||||
|
label: 'Pinned',
|
||||||
|
),
|
||||||
if (container.metadata.contextualIdentity != null)
|
if (container.metadata.contextualIdentity != null)
|
||||||
const _ContainerInfoChip(
|
const _ContainerInfoChip(
|
||||||
icon: Icons.cookie_outlined,
|
icon: Icons.cookie_outlined,
|
||||||
|
|||||||
+5
@@ -18,6 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
import 'package:nullability/nullability.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/data/models/container_data.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_title.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_title.dart';
|
||||||
@@ -62,6 +63,10 @@ Widget buildContainerChipLabel(
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
if (container.isPinned) ...[
|
||||||
|
Icon(MdiIcons.pin, size: 14, color: foregroundColor),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
],
|
||||||
Flexible(child: ContainerTitle(container: container)),
|
Flexible(child: ContainerTitle(container: container)),
|
||||||
if (trailing != null) ...[const SizedBox(width: 6), trailing],
|
if (trailing != null) ...[const SizedBox(width: 6), trailing],
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user