diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml
index f6526aec..cde94816 100644
--- a/app/android/app/src/main/AndroidManifest.xml
+++ b/app/android/app/src/main/AndroidManifest.xml
@@ -169,7 +169,8 @@
+ android:foregroundServiceType="dataSync"
+ android:exported="false" />
r'e7538b9f0dd43ea64953164c5402e76fde96f5e9';
+String _$chatModelHash() => r'9e44e8fa1d688968841933aac8e13212cf41f4ed';
/// See also [chatModel].
@ProviderFor(chatModel)
@@ -22,7 +22,7 @@ final chatModelProvider = Provider.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef ChatModelRef = ProviderRef;
-String _$embeddingModelHash() => r'5d65c75df195a26adefac5a75f0e8f6b0f1b8590';
+String _$embeddingModelHash() => r'40111a5f08b43afe6edd399ff0e6c022b3387265';
/// See also [embeddingModel].
@ProviderFor(embeddingModel)
diff --git a/app/lib/core/providers.dart b/app/lib/core/providers.dart
index 9a70f4ff..6b878ce7 100644
--- a/app/lib/core/providers.dart
+++ b/app/lib/core/providers.dart
@@ -1,5 +1,6 @@
import 'package:go_router/go_router.dart';
import 'package:lensai/core/routing/routes.dart';
+import 'package:lensai/data/models/drag_data.dart';
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -12,3 +13,19 @@ GoRouter router(Ref ref) {
routes: $appRoutes,
);
}
+
+@Riverpod()
+class WillAcceptDrop extends _$WillAcceptDrop {
+ void setData(DropTargetData data) {
+ state = data;
+ }
+
+ void clear() {
+ state = null;
+ }
+
+ @override
+ DropTargetData? build() {
+ return null;
+ }
+}
diff --git a/app/lib/core/providers.g.dart b/app/lib/core/providers.g.dart
index a00bc133..9ba8ea2a 100644
--- a/app/lib/core/providers.g.dart
+++ b/app/lib/core/providers.g.dart
@@ -22,5 +22,21 @@ final routerProvider = Provider.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef RouterRef = ProviderRef;
+String _$willAcceptDropHash() => r'97b47784ef9101757602b4408d1f545ef2308830';
+
+/// See also [WillAcceptDrop].
+@ProviderFor(WillAcceptDrop)
+final willAcceptDropProvider =
+ AutoDisposeNotifierProvider.internal(
+ WillAcceptDrop.new,
+ name: r'willAcceptDropProvider',
+ debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+ ? null
+ : _$willAcceptDropHash,
+ dependencies: null,
+ allTransitiveDependencies: null,
+);
+
+typedef _$WillAcceptDrop = AutoDisposeNotifier;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
diff --git a/app/lib/core/routing/routes.dart b/app/lib/core/routing/routes.dart
index 846ad260..4619c5d0 100644
--- a/app/lib/core/routing/routes.dart
+++ b/app/lib/core/routing/routes.dart
@@ -13,6 +13,8 @@ import 'package:lensai/features/geckoview/features/browser/presentation/dialogs/
import 'package:lensai/features/geckoview/features/browser/presentation/screens/browser.dart';
import 'package:lensai/features/geckoview/features/tabs/presentation/screens/container_list.dart';
import 'package:lensai/features/search/presentation/screens/search.dart';
+import 'package:lensai/features/settings/presentation/screens/browser_hardening.dart';
+import 'package:lensai/features/settings/presentation/screens/browser_hardening_group.dart';
import 'package:lensai/features/settings/presentation/screens/settings.dart';
import 'package:lensai/features/user/presentation/screens/auth.dart';
@@ -180,6 +182,18 @@ class ContainerListRoute extends GoRouteData {
@TypedGoRoute(
name: 'SettingsRoute',
path: '/settings',
+ routes: [
+ TypedGoRoute(
+ name: 'BrowserHardeningRoute',
+ path: 'hardening',
+ routes: [
+ TypedGoRoute(
+ name: 'BrowserHardeningGroupRoute',
+ path: 'group/:group',
+ ),
+ ],
+ ),
+ ],
)
class SettingsRoute extends GoRouteData {
@override
@@ -188,6 +202,24 @@ class SettingsRoute extends GoRouteData {
}
}
+class BrowserHardeningRoute extends GoRouteData {
+ @override
+ Widget build(BuildContext context, GoRouterState state) {
+ return const BrowserHardeningScreen();
+ }
+}
+
+class BrowserHardeningGroupRoute extends GoRouteData {
+ final String group;
+
+ const BrowserHardeningGroupRoute({required this.group});
+
+ @override
+ Widget build(BuildContext context, GoRouterState state) {
+ return BrowserHardeningGroupScreen(groupName: group);
+ }
+}
+
@TypedGoRoute(
name: 'ChatArchiveListRoute',
path: '/chat_archive',
diff --git a/app/lib/core/routing/routes.g.dart b/app/lib/core/routing/routes.g.dart
index 1f6b417a..91b3a7c0 100644
--- a/app/lib/core/routing/routes.g.dart
+++ b/app/lib/core/routing/routes.g.dart
@@ -259,6 +259,20 @@ RouteBase get $settingsRoute => GoRouteData.$route(
path: '/settings',
name: 'SettingsRoute',
factory: $SettingsRouteExtension._fromState,
+ routes: [
+ GoRouteData.$route(
+ path: 'hardening',
+ name: 'BrowserHardeningRoute',
+ factory: $BrowserHardeningRouteExtension._fromState,
+ routes: [
+ GoRouteData.$route(
+ path: 'group/:group',
+ name: 'BrowserHardeningGroupRoute',
+ factory: $BrowserHardeningGroupRouteExtension._fromState,
+ ),
+ ],
+ ),
+ ],
);
extension $SettingsRouteExtension on SettingsRoute {
@@ -278,6 +292,44 @@ extension $SettingsRouteExtension on SettingsRoute {
void replace(BuildContext context) => context.replace(location);
}
+extension $BrowserHardeningRouteExtension on BrowserHardeningRoute {
+ static BrowserHardeningRoute _fromState(GoRouterState state) =>
+ BrowserHardeningRoute();
+
+ String get location => GoRouteData.$location(
+ '/settings/hardening',
+ );
+
+ void go(BuildContext context) => context.go(location);
+
+ Future push(BuildContext context) => context.push(location);
+
+ void pushReplacement(BuildContext context) =>
+ context.pushReplacement(location);
+
+ void replace(BuildContext context) => context.replace(location);
+}
+
+extension $BrowserHardeningGroupRouteExtension on BrowserHardeningGroupRoute {
+ static BrowserHardeningGroupRoute _fromState(GoRouterState state) =>
+ BrowserHardeningGroupRoute(
+ group: state.pathParameters['group']!,
+ );
+
+ String get location => GoRouteData.$location(
+ '/settings/hardening/group/${Uri.encodeComponent(group)}',
+ );
+
+ void go(BuildContext context) => context.go(location);
+
+ Future push(BuildContext context) => context.push(location);
+
+ void pushReplacement(BuildContext context) =>
+ context.pushReplacement(location);
+
+ void replace(BuildContext context) => context.replace(location);
+}
+
RouteBase get $chatArchiveListRoute => GoRouteData.$route(
path: '/chat_archive',
name: 'ChatArchiveListRoute',
diff --git a/app/lib/data/models/drag_data.dart b/app/lib/data/models/drag_data.dart
new file mode 100644
index 00000000..559dfb89
--- /dev/null
+++ b/app/lib/data/models/drag_data.dart
@@ -0,0 +1,41 @@
+import 'package:fast_equatable/fast_equatable.dart';
+
+sealed class DropTargetData with FastEquatable {}
+
+final class ContainerDropData extends DropTargetData {
+ final String tabId;
+
+ ContainerDropData(this.tabId);
+
+ @override
+ bool get cacheHash => true;
+
+ @override
+ List