mainly refactoring & addons
This commit is contained in:
@@ -41,7 +41,7 @@
|
|||||||
android:icon="@mipmap/launcher_icon"
|
android:icon="@mipmap/launcher_icon"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
android:enableOnBackInvokedCallback="true">
|
android:enableOnBackInvokedCallback="true">
|
||||||
<activity android:name="eu.lensai.flutter_mozilla_components.NotificationActivity" android:theme="@style/Theme.AppCompat.Translucent" />
|
<activity android:name="eu.lensai.flutter_mozilla_components.activities.NotificationActivity" android:theme="@style/Theme.AppCompat.Translucent" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
@@ -85,6 +85,42 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:theme="@style/Theme.AppCompat.Light"
|
||||||
|
android:name="eu.lensai.flutter_mozilla_components.addons.AddonsActivity"
|
||||||
|
android:label="@string/mozac_feature_addons_addons"
|
||||||
|
android:exported="false"
|
||||||
|
android:parentActivityName=".MainActivity" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:theme="@style/Theme.AppCompat.Light"
|
||||||
|
android:name="eu.lensai.flutter_mozilla_components.addons.AddonDetailsActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/mozac_feature_addons_addons" />
|
||||||
|
|
||||||
|
<activity android:name="eu.lensai.flutter_mozilla_components.addons.InstalledAddonDetailsActivity"
|
||||||
|
android:label="@string/mozac_feature_addons_addons"
|
||||||
|
android:parentActivityName="eu.lensai.flutter_mozilla_components.addons.AddonsActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:theme="@style/Theme.AppCompat.Light" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="eu.lensai.flutter_mozilla_components.addons.PermissionsDetailsActivity"
|
||||||
|
android:label="@string/mozac_feature_addons_addons"
|
||||||
|
android:exported="false"
|
||||||
|
android:theme="@style/Theme.AppCompat.Light" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="eu.lensai.flutter_mozilla_components.addons.AddonSettingsActivity"
|
||||||
|
android:label="@string/mozac_feature_addons_addons"
|
||||||
|
android:exported="false"
|
||||||
|
android:theme="@style/Theme.AppCompat.Light" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="eu.lensai.flutter_mozilla_components.addons.WebExtensionActionPopupActivity"
|
||||||
|
android:label="@string/mozac_feature_addons_addons"
|
||||||
|
android:theme="@style/Theme.AppCompat.Light"/>
|
||||||
|
|
||||||
<receiver android:name="FullWidgetProvider" android:exported="true">
|
<receiver android:name="FullWidgetProvider" android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
@@ -113,10 +149,10 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name="eu.lensai.flutter_mozilla_components.DownloadService"
|
android:name="eu.lensai.flutter_mozilla_components.services.DownloadService"
|
||||||
android:foregroundServiceType="dataSync" />
|
android:foregroundServiceType="dataSync" />
|
||||||
|
|
||||||
<service android:name="eu.lensai.flutter_mozilla_components.MediaSessionService"
|
<service android:name="eu.lensai.flutter_mozilla_components.services.MediaSessionService"
|
||||||
android:foregroundServiceType="mediaPlayback"
|
android:foregroundServiceType="mediaPlayback"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,6 @@
|
|||||||
@import file_picker;
|
@import file_picker;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<flutter_inappwebview_ios/InAppWebViewFlutterPlugin.h>)
|
|
||||||
#import <flutter_inappwebview_ios/InAppWebViewFlutterPlugin.h>
|
|
||||||
#else
|
|
||||||
@import flutter_inappwebview_ios;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<flutter_pdf_text/PdfTextPlugin.h>)
|
#if __has_include(<flutter_pdf_text/PdfTextPlugin.h>)
|
||||||
#import <flutter_pdf_text/PdfTextPlugin.h>
|
#import <flutter_pdf_text/PdfTextPlugin.h>
|
||||||
#else
|
#else
|
||||||
@@ -82,7 +76,6 @@
|
|||||||
|
|
||||||
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
|
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
|
||||||
[FilePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FilePickerPlugin"]];
|
[FilePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FilePickerPlugin"]];
|
||||||
[InAppWebViewFlutterPlugin registerWithRegistrar:[registry registrarForPlugin:@"InAppWebViewFlutterPlugin"]];
|
|
||||||
[PdfTextPlugin registerWithRegistrar:[registry registrarForPlugin:@"PdfTextPlugin"]];
|
[PdfTextPlugin registerWithRegistrar:[registry registrarForPlugin:@"PdfTextPlugin"]];
|
||||||
[FlutterSecureStoragePlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterSecureStoragePlugin"]];
|
[FlutterSecureStoragePlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterSecureStoragePlugin"]];
|
||||||
[FlutterSharingIntentPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterSharingIntentPlugin"]];
|
[FlutterSharingIntentPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterSharingIntentPlugin"]];
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:lensai/core/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
GoRouter router(RouterRef ref) => GoRouter(
|
GoRouter router(Ref ref) => GoRouter(
|
||||||
debugLogDiagnostics: true,
|
debugLogDiagnostics: true,
|
||||||
routes: $appRoutes,
|
routes: $appRoutes,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'providers.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$routerHash() => r'4ad45f430b1f43e427e21122d16bd761ca04ae0e';
|
String _$routerHash() => r'dcafae2924a2ad3d5d836c6756d2e4a4ead36b4e';
|
||||||
|
|
||||||
/// See also [router].
|
/// See also [router].
|
||||||
@ProviderFor(router)
|
@ProviderFor(router)
|
||||||
@@ -19,6 +19,8 @@ final routerProvider = Provider<GoRouter>.internal(
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef RouterRef = ProviderRef<GoRouter>;
|
typedef RouterRef = ProviderRef<GoRouter>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import 'package:lensai/extensions/image.dart';
|
|||||||
|
|
||||||
class EquatableImage {
|
class EquatableImage {
|
||||||
final Image value;
|
final Image value;
|
||||||
final String? _imageHash;
|
final int? _imageHash;
|
||||||
|
|
||||||
EquatableImage(
|
EquatableImage(
|
||||||
this.value, {
|
this.value, {
|
||||||
required String? hash,
|
required int? hash,
|
||||||
}) : _imageHash = hash;
|
}) : _imageHash = hash;
|
||||||
|
|
||||||
static Future<EquatableImage> calculate(Image image) async {
|
static Future<EquatableImage> calculate(Image image) async {
|
||||||
|
|||||||
@@ -31,4 +31,4 @@ final appInitializationServiceProvider = NotifierProvider<
|
|||||||
typedef _$AppInitializationService = Notifier<
|
typedef _$AppInitializationService = Notifier<
|
||||||
Result<({bool initialized, String? stage, List<ErrorMessage> errors})>>;
|
Result<({bool initialized, String? stage, List<ErrorMessage> errors})>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final genericWebsiteServiceProvider =
|
|||||||
|
|
||||||
typedef _$GenericWebsiteService = Notifier<void>;
|
typedef _$GenericWebsiteService = Notifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:crypto/crypto.dart';
|
|
||||||
import 'package:lensai/domain/entities/equatable_image.dart';
|
import 'package:lensai/domain/entities/equatable_image.dart';
|
||||||
|
import 'package:xxh3/xxh3.dart';
|
||||||
|
|
||||||
extension ImageHash on Image {
|
extension ImageHash on Image {
|
||||||
Future<String?> calculateHash() async {
|
Future<int?> calculateHash() async {
|
||||||
final bytes = await toByteData();
|
final bytes = await toByteData();
|
||||||
if (bytes != null) {
|
if (bytes != null) {
|
||||||
final digest = sha1.convert(bytes.buffer.asUint8List());
|
final digest = xxh3(bytes.buffer.asUint8List());
|
||||||
return digest.toString();
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'package_info_repository.g.dart';
|
part 'package_info_repository.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
Future<PackageInfo> packageInfo(PackageInfoRef ref) {
|
Future<PackageInfo> packageInfo(Ref ref) {
|
||||||
return PackageInfo.fromPlatform();
|
return PackageInfo.fromPlatform();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'package_info_repository.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$packageInfoHash() => r'f7bd90882137aac7a9f28e9d10eae6efeee8c9d0';
|
String _$packageInfoHash() => r'cc57db7b4684ab0d5df0f050b8ea045a3658e89a';
|
||||||
|
|
||||||
/// See also [packageInfo].
|
/// See also [packageInfo].
|
||||||
@ProviderFor(packageInfo)
|
@ProviderFor(packageInfo)
|
||||||
@@ -19,6 +19,8 @@ final packageInfoProvider = FutureProvider<PackageInfo>.internal(
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef PackageInfoRef = FutureProviderRef<PackageInfo>;
|
typedef PackageInfoRef = FutureProviderRef<PackageInfo>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
import 'package:home_widget/home_widget.dart';
|
import 'package:home_widget/home_widget.dart';
|
||||||
import 'package:lensai/data/models/received_parameter.dart';
|
import 'package:lensai/data/models/received_parameter.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
|
|
||||||
part 'home_widget.g.dart';
|
part 'home_widget.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
FutureOr<bool> widgetPinnable(WidgetPinnableRef ref) async {
|
FutureOr<bool> widgetPinnable(Ref ref) async {
|
||||||
return await HomeWidget.isRequestPinWidgetSupported() ?? false;
|
return await HomeWidget.isRequestPinWidgetSupported() ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Raw<Stream<ReceivedParameter>> appWidgetLaunchStream(
|
Raw<Stream<ReceivedParameter>> appWidgetLaunchStream(
|
||||||
AppWidgetLaunchStreamRef ref,
|
Ref ref,
|
||||||
) {
|
) {
|
||||||
// ignore: discarded_futures
|
// ignore: discarded_futures
|
||||||
final initialStream = HomeWidget.initiallyLaunchedFromHomeWidget().asStream();
|
final initialStream = HomeWidget.initiallyLaunchedFromHomeWidget().asStream();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'home_widget.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$widgetPinnableHash() => r'c39a8b473a92ff81fa772d7c235b10736e4a49bd';
|
String _$widgetPinnableHash() => r'f91041f0f051ad0f00dd765cafea5571ca8c8088';
|
||||||
|
|
||||||
/// See also [widgetPinnable].
|
/// See also [widgetPinnable].
|
||||||
@ProviderFor(widgetPinnable)
|
@ProviderFor(widgetPinnable)
|
||||||
@@ -20,9 +20,11 @@ final widgetPinnableProvider = FutureProvider<bool>.internal(
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef WidgetPinnableRef = FutureProviderRef<bool>;
|
typedef WidgetPinnableRef = FutureProviderRef<bool>;
|
||||||
String _$appWidgetLaunchStreamHash() =>
|
String _$appWidgetLaunchStreamHash() =>
|
||||||
r'8c5e21346d492f89f546b4e32135a283719e70e1';
|
r'8eb98d88e74cc4f7573968563c106b8e6beee289';
|
||||||
|
|
||||||
/// See also [appWidgetLaunchStream].
|
/// See also [appWidgetLaunchStream].
|
||||||
@ProviderFor(appWidgetLaunchStream)
|
@ProviderFor(appWidgetLaunchStream)
|
||||||
@@ -37,7 +39,9 @@ final appWidgetLaunchStreamProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef AppWidgetLaunchStreamRef
|
typedef AppWidgetLaunchStreamRef
|
||||||
= AutoDisposeProviderRef<Raw<Stream<ReceivedParameter>>>;
|
= AutoDisposeProviderRef<Raw<Stream<ReceivedParameter>>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:drift/native.dart';
|
|||||||
import 'package:lensai/features/bangs/data/database/database.dart';
|
import 'package:lensai/features/bangs/data/database/database.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:path_provider/path_provider.dart' as path_provider;
|
import 'package:path_provider/path_provider.dart' as path_provider;
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:sqlite3/sqlite3.dart';
|
import 'package:sqlite3/sqlite3.dart';
|
||||||
import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
|
import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
|
||||||
@@ -11,7 +12,7 @@ import 'package:universal_io/io.dart';
|
|||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
BangDatabase bangDatabase(BangDatabaseRef ref) {
|
BangDatabase bangDatabase(Ref ref) {
|
||||||
return BangDatabase(
|
return BangDatabase(
|
||||||
LazyDatabase(() async {
|
LazyDatabase(() async {
|
||||||
// put the database file, called db.sqlite here, into the documents folder
|
// put the database file, called db.sqlite here, into the documents folder
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'providers.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$bangDatabaseHash() => r'bbca2edf32faa378dcb6270b12019758d5156662';
|
String _$bangDatabaseHash() => r'd7964e9cdbb6e60fb6d2a78f07bfd4fa34bcb236';
|
||||||
|
|
||||||
/// See also [bangDatabase].
|
/// See also [bangDatabase].
|
||||||
@ProviderFor(bangDatabase)
|
@ProviderFor(bangDatabase)
|
||||||
@@ -19,6 +19,8 @@ final bangDatabaseProvider = Provider<BangDatabase>.internal(
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef BangDatabaseRef = ProviderRef<BangDatabase>;
|
typedef BangDatabaseRef = ProviderRef<BangDatabase>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ final bangSourceServiceProvider =
|
|||||||
|
|
||||||
typedef _$BangSourceService = AutoDisposeNotifier<void>;
|
typedef _$BangSourceService = AutoDisposeNotifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -2,31 +2,32 @@ import 'package:lensai/features/bangs/data/models/bang.dart';
|
|||||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||||
import 'package:lensai/features/bangs/domain/repositories/data.dart';
|
import 'package:lensai/features/bangs/domain/repositories/data.dart';
|
||||||
import 'package:lensai/features/bangs/domain/repositories/sync.dart';
|
import 'package:lensai/features/bangs/domain/repositories/sync.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<BangData?> bangData(BangDataRef ref, String? trigger) {
|
Stream<BangData?> bangData(Ref ref, String? trigger) {
|
||||||
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
||||||
return repository.watchBang(trigger);
|
return repository.watchBang(trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
Stream<BangData?> kagiSearchBangData(KagiSearchBangDataRef ref) {
|
Stream<BangData?> kagiSearchBangData(Ref ref) {
|
||||||
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
||||||
return repository.watchBang('kagi');
|
return repository.watchBang('kagi');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<Map<String, List<String>>> bangCategories(BangCategoriesRef ref) {
|
Stream<Map<String, List<String>>> bangCategories(Ref ref) {
|
||||||
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
||||||
return repository.watchCategories();
|
return repository.watchCategories();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<List<BangData>> bangDataList(
|
Stream<List<BangData>> bangDataList(
|
||||||
BangDataListRef ref, {
|
Ref ref, {
|
||||||
({
|
({
|
||||||
Iterable<BangGroup>? groups,
|
Iterable<BangGroup>? groups,
|
||||||
String? domain,
|
String? domain,
|
||||||
@@ -44,14 +45,14 @@ Stream<List<BangData>> bangDataList(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<List<BangData>> frequentBangDataList(FrequentBangDataListRef ref) {
|
Stream<List<BangData>> frequentBangDataList(Ref ref) {
|
||||||
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
||||||
return repository.watchFrequentBangs();
|
return repository.watchFrequentBangs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Future<BangData> bangDataEnsureIcon(
|
Future<BangData> bangDataEnsureIcon(
|
||||||
BangDataEnsureIconRef ref,
|
Ref ref,
|
||||||
BangData bang,
|
BangData bang,
|
||||||
) {
|
) {
|
||||||
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
||||||
@@ -62,7 +63,7 @@ Future<BangData> bangDataEnsureIcon(
|
|||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<DateTime?> lastSyncOfGroup(
|
Stream<DateTime?> lastSyncOfGroup(
|
||||||
LastSyncOfGroupRef ref,
|
Ref ref,
|
||||||
BangGroup group,
|
BangGroup group,
|
||||||
) {
|
) {
|
||||||
final repository = ref.watch(bangSyncRepositoryProvider.notifier);
|
final repository = ref.watch(bangSyncRepositoryProvider.notifier);
|
||||||
@@ -71,7 +72,7 @@ Stream<DateTime?> lastSyncOfGroup(
|
|||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<int> bangCountOfGroup(
|
Stream<int> bangCountOfGroup(
|
||||||
BangCountOfGroupRef ref,
|
Ref ref,
|
||||||
BangGroup group,
|
BangGroup group,
|
||||||
) {
|
) {
|
||||||
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
||||||
@@ -79,7 +80,7 @@ Stream<int> bangCountOfGroup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<double> bangIconCacheSizeMegabytes(BangIconCacheSizeMegabytesRef ref) {
|
Stream<double> bangIconCacheSizeMegabytes(Ref ref) {
|
||||||
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
||||||
return repository.watchIconCacheSize();
|
return repository.watchIconCacheSize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'providers.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$bangDataHash() => r'd0e96885458be8893c6b19735b8792bdd1b9bcb8';
|
String _$bangDataHash() => r'057a002de9789ab74c8f3b337a43faa26b788d8d';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -141,6 +141,8 @@ class BangDataProvider extends AutoDisposeStreamProvider<BangData?> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin BangDataRef on AutoDisposeStreamProviderRef<BangData?> {
|
mixin BangDataRef on AutoDisposeStreamProviderRef<BangData?> {
|
||||||
/// The parameter `trigger` of this provider.
|
/// The parameter `trigger` of this provider.
|
||||||
String? get trigger;
|
String? get trigger;
|
||||||
@@ -155,7 +157,7 @@ class _BangDataProviderElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$kagiSearchBangDataHash() =>
|
String _$kagiSearchBangDataHash() =>
|
||||||
r'4dbeaab0541d7c8214d097523d139eede2e3f975';
|
r'0bb5014a7af73ef6f5a36b0545d7a73e7ad0580a';
|
||||||
|
|
||||||
/// See also [kagiSearchBangData].
|
/// See also [kagiSearchBangData].
|
||||||
@ProviderFor(kagiSearchBangData)
|
@ProviderFor(kagiSearchBangData)
|
||||||
@@ -169,8 +171,10 @@ final kagiSearchBangDataProvider = StreamProvider<BangData?>.internal(
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef KagiSearchBangDataRef = StreamProviderRef<BangData?>;
|
typedef KagiSearchBangDataRef = StreamProviderRef<BangData?>;
|
||||||
String _$bangCategoriesHash() => r'dbc63b78208be90c2aa3c3d61b08f98818f4b89d';
|
String _$bangCategoriesHash() => r'947fcfd2dffcc7f585c6ed7379d319f4fe72293a';
|
||||||
|
|
||||||
/// See also [bangCategories].
|
/// See also [bangCategories].
|
||||||
@ProviderFor(bangCategories)
|
@ProviderFor(bangCategories)
|
||||||
@@ -185,9 +189,11 @@ final bangCategoriesProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef BangCategoriesRef
|
typedef BangCategoriesRef
|
||||||
= AutoDisposeStreamProviderRef<Map<String, List<String>>>;
|
= AutoDisposeStreamProviderRef<Map<String, List<String>>>;
|
||||||
String _$bangDataListHash() => r'c4fbc1676be933b29ec88f503110c119fe8b6d86';
|
String _$bangDataListHash() => r'cd034fdf046b156ac452edd0857ac054ab477917';
|
||||||
|
|
||||||
/// See also [bangDataList].
|
/// See also [bangDataList].
|
||||||
@ProviderFor(bangDataList)
|
@ProviderFor(bangDataList)
|
||||||
@@ -317,6 +323,8 @@ class BangDataListProvider extends AutoDisposeStreamProvider<List<BangData>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin BangDataListRef on AutoDisposeStreamProviderRef<List<BangData>> {
|
mixin BangDataListRef on AutoDisposeStreamProviderRef<List<BangData>> {
|
||||||
/// The parameter `filter` of this provider.
|
/// The parameter `filter` of this provider.
|
||||||
({
|
({
|
||||||
@@ -342,7 +350,7 @@ class _BangDataListProviderElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$frequentBangDataListHash() =>
|
String _$frequentBangDataListHash() =>
|
||||||
r'adf8d0b72adfa8faffadd7f1a294ce3945e22fec';
|
r'27bc10ddf502266458af3910fff09bc8282a8e5c';
|
||||||
|
|
||||||
/// See also [frequentBangDataList].
|
/// See also [frequentBangDataList].
|
||||||
@ProviderFor(frequentBangDataList)
|
@ProviderFor(frequentBangDataList)
|
||||||
@@ -357,9 +365,11 @@ final frequentBangDataListProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef FrequentBangDataListRef = AutoDisposeStreamProviderRef<List<BangData>>;
|
typedef FrequentBangDataListRef = AutoDisposeStreamProviderRef<List<BangData>>;
|
||||||
String _$bangDataEnsureIconHash() =>
|
String _$bangDataEnsureIconHash() =>
|
||||||
r'69b59b582a7b165b8076a1478d0d433ec0846ccb';
|
r'423b8e92fd89ec328c2fcc8f9e55365c30633fd2';
|
||||||
|
|
||||||
/// See also [bangDataEnsureIcon].
|
/// See also [bangDataEnsureIcon].
|
||||||
@ProviderFor(bangDataEnsureIcon)
|
@ProviderFor(bangDataEnsureIcon)
|
||||||
@@ -474,6 +484,8 @@ class BangDataEnsureIconProvider extends AutoDisposeFutureProvider<BangData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin BangDataEnsureIconRef on AutoDisposeFutureProviderRef<BangData> {
|
mixin BangDataEnsureIconRef on AutoDisposeFutureProviderRef<BangData> {
|
||||||
/// The parameter `bang` of this provider.
|
/// The parameter `bang` of this provider.
|
||||||
BangData get bang;
|
BangData get bang;
|
||||||
@@ -488,7 +500,7 @@ class _BangDataEnsureIconProviderElement
|
|||||||
BangData get bang => (origin as BangDataEnsureIconProvider).bang;
|
BangData get bang => (origin as BangDataEnsureIconProvider).bang;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$lastSyncOfGroupHash() => r'4906dc24970eccda89d94697f98cf70e241ea4ec';
|
String _$lastSyncOfGroupHash() => r'23d07f3132ba9bb35a31f74e3a69698d31d4c569';
|
||||||
|
|
||||||
/// See also [lastSyncOfGroup].
|
/// See also [lastSyncOfGroup].
|
||||||
@ProviderFor(lastSyncOfGroup)
|
@ProviderFor(lastSyncOfGroup)
|
||||||
@@ -603,6 +615,8 @@ class LastSyncOfGroupProvider extends AutoDisposeStreamProvider<DateTime?> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin LastSyncOfGroupRef on AutoDisposeStreamProviderRef<DateTime?> {
|
mixin LastSyncOfGroupRef on AutoDisposeStreamProviderRef<DateTime?> {
|
||||||
/// The parameter `group` of this provider.
|
/// The parameter `group` of this provider.
|
||||||
BangGroup get group;
|
BangGroup get group;
|
||||||
@@ -617,7 +631,7 @@ class _LastSyncOfGroupProviderElement
|
|||||||
BangGroup get group => (origin as LastSyncOfGroupProvider).group;
|
BangGroup get group => (origin as LastSyncOfGroupProvider).group;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$bangCountOfGroupHash() => r'10b363679230c0abf6a6ba7d0be2d0367a7ed215';
|
String _$bangCountOfGroupHash() => r'211ffcd7f49b637a7953f913dc5eafda344423f3';
|
||||||
|
|
||||||
/// See also [bangCountOfGroup].
|
/// See also [bangCountOfGroup].
|
||||||
@ProviderFor(bangCountOfGroup)
|
@ProviderFor(bangCountOfGroup)
|
||||||
@@ -732,6 +746,8 @@ class BangCountOfGroupProvider extends AutoDisposeStreamProvider<int> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin BangCountOfGroupRef on AutoDisposeStreamProviderRef<int> {
|
mixin BangCountOfGroupRef on AutoDisposeStreamProviderRef<int> {
|
||||||
/// The parameter `group` of this provider.
|
/// The parameter `group` of this provider.
|
||||||
BangGroup get group;
|
BangGroup get group;
|
||||||
@@ -746,7 +762,7 @@ class _BangCountOfGroupProviderElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$bangIconCacheSizeMegabytesHash() =>
|
String _$bangIconCacheSizeMegabytesHash() =>
|
||||||
r'2199439f1b8a2692607231836769a10a24405181';
|
r'e08bfdc7bb47a56c079464478f0b8b5516b2effe';
|
||||||
|
|
||||||
/// See also [bangIconCacheSizeMegabytes].
|
/// See also [bangIconCacheSizeMegabytes].
|
||||||
@ProviderFor(bangIconCacheSizeMegabytes)
|
@ProviderFor(bangIconCacheSizeMegabytes)
|
||||||
@@ -761,6 +777,8 @@ final bangIconCacheSizeMegabytesProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef BangIconCacheSizeMegabytesRef = AutoDisposeStreamProviderRef<double>;
|
typedef BangIconCacheSizeMegabytesRef = AutoDisposeStreamProviderRef<double>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final bangDataRepositoryProvider =
|
|||||||
|
|
||||||
typedef _$BangDataRepository = Notifier<void>;
|
typedef _$BangDataRepository = Notifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ final bangSearchProvider =
|
|||||||
|
|
||||||
typedef _$BangSearch = AutoDisposeStreamNotifier<List<BangData>>;
|
typedef _$BangSearch = AutoDisposeStreamNotifier<List<BangData>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final bangSyncRepositoryProvider =
|
|||||||
|
|
||||||
typedef _$BangSyncRepository = Notifier<void>;
|
typedef _$BangSyncRepository = Notifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:drift/drift.dart';
|
|||||||
import 'package:drift/native.dart';
|
import 'package:drift/native.dart';
|
||||||
import 'package:lensai/features/chat_archive/data/database/database.dart';
|
import 'package:lensai/features/chat_archive/data/database/database.dart';
|
||||||
import 'package:path_provider/path_provider.dart' as path_provider;
|
import 'package:path_provider/path_provider.dart' as path_provider;
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:sqlite3/sqlite3.dart';
|
import 'package:sqlite3/sqlite3.dart';
|
||||||
import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
|
import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
|
||||||
@@ -10,7 +11,7 @@ import 'package:universal_io/io.dart';
|
|||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
ChatSearchDatabase chatSearchDatabase(ChatSearchDatabaseRef ref) {
|
ChatSearchDatabase chatSearchDatabase(Ref ref) {
|
||||||
return ChatSearchDatabase(
|
return ChatSearchDatabase(
|
||||||
LazyDatabase(() async {
|
LazyDatabase(() async {
|
||||||
// Also work around limitations on old Android versions
|
// Also work around limitations on old Android versions
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'providers.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$chatSearchDatabaseHash() =>
|
String _$chatSearchDatabaseHash() =>
|
||||||
r'd7d2ad34264201d9196b28140b9b0ce0be6b7e1c';
|
r'99700f1a2c25b24742c60fa8dd91fe744dcf21be';
|
||||||
|
|
||||||
/// See also [chatSearchDatabase].
|
/// See also [chatSearchDatabase].
|
||||||
@ProviderFor(chatSearchDatabase)
|
@ProviderFor(chatSearchDatabase)
|
||||||
@@ -22,6 +22,8 @@ final chatSearchDatabaseProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef ChatSearchDatabaseRef = AutoDisposeProviderRef<ChatSearchDatabase>;
|
typedef ChatSearchDatabaseRef = AutoDisposeProviderRef<ChatSearchDatabase>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final chatArchiveFileServiceProvider = AutoDisposeNotifierProvider<
|
|||||||
|
|
||||||
typedef _$ChatArchiveFileService = AutoDisposeNotifier<Raw<Stream<WatchEvent>>>;
|
typedef _$ChatArchiveFileService = AutoDisposeNotifier<Raw<Stream<WatchEvent>>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:lensai/features/chat_archive/data/services/file.dart';
|
|||||||
import 'package:lensai/features/chat_archive/domain/entities/chat_entity.dart';
|
import 'package:lensai/features/chat_archive/domain/entities/chat_entity.dart';
|
||||||
import 'package:lensai/features/kagi/data/services/chat.dart';
|
import 'package:lensai/features/kagi/data/services/chat.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
|
|
||||||
@@ -62,10 +63,7 @@ class ChatArchiveRepository extends _$ChatArchiveRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Future<String> readArchivedChat(
|
Future<String> readArchivedChat(Ref ref, String fileName) async {
|
||||||
ReadArchivedChatRef ref,
|
|
||||||
String fileName,
|
|
||||||
) async {
|
|
||||||
final result =
|
final result =
|
||||||
await ref.read(chatArchiveRepositoryProvider.notifier).readChat(fileName);
|
await ref.read(chatArchiveRepositoryProvider.notifier).readChat(fileName);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'archive.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$readArchivedChatHash() => r'e7d646a0ea22fe24d96e97f86c1d46fe83818508';
|
String _$readArchivedChatHash() => r'beeadc38cf71f7dfb77a33a1202c685543a72b24';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -142,6 +142,8 @@ class ReadArchivedChatProvider extends AutoDisposeFutureProvider<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin ReadArchivedChatRef on AutoDisposeFutureProviderRef<String> {
|
mixin ReadArchivedChatRef on AutoDisposeFutureProviderRef<String> {
|
||||||
/// The parameter `fileName` of this provider.
|
/// The parameter `fileName` of this provider.
|
||||||
String get fileName;
|
String get fileName;
|
||||||
@@ -173,4 +175,4 @@ final chatArchiveRepositoryProvider = AutoDisposeStreamNotifierProvider<
|
|||||||
|
|
||||||
typedef _$ChatArchiveRepository = AutoDisposeStreamNotifier<List<ChatEntity>>;
|
typedef _$ChatArchiveRepository = AutoDisposeStreamNotifier<List<ChatEntity>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ final chatArchiveSearchRepositoryProvider = AutoDisposeStreamNotifierProvider<
|
|||||||
typedef _$ChatArchiveSearchRepository
|
typedef _$ChatArchiveSearchRepository
|
||||||
= AutoDisposeStreamNotifier<List<ChatQueryResult>>;
|
= AutoDisposeStreamNotifier<List<ChatQueryResult>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:copy_with_extension/copy_with_extension.dart';
|
||||||
|
import 'package:fast_equatable/fast_equatable.dart';
|
||||||
|
import 'package:lensai/domain/entities/equatable_image.dart';
|
||||||
|
|
||||||
|
part 'web_extension_state.g.dart';
|
||||||
|
|
||||||
|
@CopyWith()
|
||||||
|
class WebExtensionState with FastEquatable {
|
||||||
|
String extensionId;
|
||||||
|
|
||||||
|
String? title;
|
||||||
|
bool enabled;
|
||||||
|
String? badgeText;
|
||||||
|
Color? badgeTextColor;
|
||||||
|
Color? badgeBackgroundColor;
|
||||||
|
|
||||||
|
final EquatableImage? icon;
|
||||||
|
|
||||||
|
WebExtensionState({
|
||||||
|
required this.extensionId,
|
||||||
|
required this.enabled,
|
||||||
|
this.title,
|
||||||
|
this.badgeText,
|
||||||
|
this.badgeTextColor,
|
||||||
|
this.badgeBackgroundColor,
|
||||||
|
this.icon,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get cacheHash => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get hashParameters => [
|
||||||
|
extensionId,
|
||||||
|
title,
|
||||||
|
enabled,
|
||||||
|
badgeText,
|
||||||
|
badgeTextColor,
|
||||||
|
badgeBackgroundColor,
|
||||||
|
icon,
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'web_extension_state.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// CopyWithGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
abstract class _$WebExtensionStateCWProxy {
|
||||||
|
WebExtensionState extensionId(String extensionId);
|
||||||
|
|
||||||
|
WebExtensionState enabled(bool enabled);
|
||||||
|
|
||||||
|
WebExtensionState title(String? title);
|
||||||
|
|
||||||
|
WebExtensionState badgeText(String? badgeText);
|
||||||
|
|
||||||
|
WebExtensionState badgeTextColor(Color? badgeTextColor);
|
||||||
|
|
||||||
|
WebExtensionState badgeBackgroundColor(Color? badgeBackgroundColor);
|
||||||
|
|
||||||
|
WebExtensionState icon(EquatableImage? icon);
|
||||||
|
|
||||||
|
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `WebExtensionState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||||
|
///
|
||||||
|
/// Usage
|
||||||
|
/// ```dart
|
||||||
|
/// WebExtensionState(...).copyWith(id: 12, name: "My name")
|
||||||
|
/// ````
|
||||||
|
WebExtensionState call({
|
||||||
|
String? extensionId,
|
||||||
|
bool? enabled,
|
||||||
|
String? title,
|
||||||
|
String? badgeText,
|
||||||
|
Color? badgeTextColor,
|
||||||
|
Color? badgeBackgroundColor,
|
||||||
|
EquatableImage? icon,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfWebExtensionState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfWebExtensionState.copyWith.fieldName(...)`
|
||||||
|
class _$WebExtensionStateCWProxyImpl implements _$WebExtensionStateCWProxy {
|
||||||
|
const _$WebExtensionStateCWProxyImpl(this._value);
|
||||||
|
|
||||||
|
final WebExtensionState _value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebExtensionState extensionId(String extensionId) =>
|
||||||
|
this(extensionId: extensionId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebExtensionState enabled(bool enabled) => this(enabled: enabled);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebExtensionState title(String? title) => this(title: title);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebExtensionState badgeText(String? badgeText) => this(badgeText: badgeText);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebExtensionState badgeTextColor(Color? badgeTextColor) =>
|
||||||
|
this(badgeTextColor: badgeTextColor);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebExtensionState badgeBackgroundColor(Color? badgeBackgroundColor) =>
|
||||||
|
this(badgeBackgroundColor: badgeBackgroundColor);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebExtensionState icon(EquatableImage? icon) => this(icon: icon);
|
||||||
|
|
||||||
|
@override
|
||||||
|
|
||||||
|
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `WebExtensionState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||||
|
///
|
||||||
|
/// Usage
|
||||||
|
/// ```dart
|
||||||
|
/// WebExtensionState(...).copyWith(id: 12, name: "My name")
|
||||||
|
/// ````
|
||||||
|
WebExtensionState call({
|
||||||
|
Object? extensionId = const $CopyWithPlaceholder(),
|
||||||
|
Object? enabled = const $CopyWithPlaceholder(),
|
||||||
|
Object? title = const $CopyWithPlaceholder(),
|
||||||
|
Object? badgeText = const $CopyWithPlaceholder(),
|
||||||
|
Object? badgeTextColor = const $CopyWithPlaceholder(),
|
||||||
|
Object? badgeBackgroundColor = const $CopyWithPlaceholder(),
|
||||||
|
Object? icon = const $CopyWithPlaceholder(),
|
||||||
|
}) {
|
||||||
|
return WebExtensionState(
|
||||||
|
extensionId:
|
||||||
|
extensionId == const $CopyWithPlaceholder() || extensionId == null
|
||||||
|
? _value.extensionId
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: extensionId as String,
|
||||||
|
enabled: enabled == const $CopyWithPlaceholder() || enabled == null
|
||||||
|
? _value.enabled
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: enabled as bool,
|
||||||
|
title: title == const $CopyWithPlaceholder()
|
||||||
|
? _value.title
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: title as String?,
|
||||||
|
badgeText: badgeText == const $CopyWithPlaceholder()
|
||||||
|
? _value.badgeText
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: badgeText as String?,
|
||||||
|
badgeTextColor: badgeTextColor == const $CopyWithPlaceholder()
|
||||||
|
? _value.badgeTextColor
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: badgeTextColor as Color?,
|
||||||
|
badgeBackgroundColor: badgeBackgroundColor == const $CopyWithPlaceholder()
|
||||||
|
? _value.badgeBackgroundColor
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: badgeBackgroundColor as Color?,
|
||||||
|
icon: icon == const $CopyWithPlaceholder()
|
||||||
|
? _value.icon
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: icon as EquatableImage?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension $WebExtensionStateCopyWith on WebExtensionState {
|
||||||
|
/// Returns a callable class that can be used as follows: `instanceOfWebExtensionState.copyWith(...)` or like so:`instanceOfWebExtensionState.copyWith.fieldName(...)`.
|
||||||
|
// ignore: library_private_types_in_public_api
|
||||||
|
_$WebExtensionStateCWProxy get copyWith =>
|
||||||
|
_$WebExtensionStateCWProxyImpl(this);
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import 'package:lensai/core/logger.dart';
|
|||||||
import 'package:lensai/features/bangs/domain/providers.dart';
|
import 'package:lensai/features/bangs/domain/providers.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
@@ -13,7 +14,7 @@ part 'providers.g.dart';
|
|||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
GeckoSelectionActionService selectionActionService(
|
GeckoSelectionActionService selectionActionService(
|
||||||
SelectionActionServiceRef ref,
|
Ref ref,
|
||||||
) {
|
) {
|
||||||
final service = GeckoSelectionActionService.setUp();
|
final service = GeckoSelectionActionService.setUp();
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ GeckoSelectionActionService selectionActionService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
GeckoEventService eventService(EventServiceRef ref) {
|
GeckoEventService eventService(Ref ref) {
|
||||||
final service = GeckoEventService.setUp();
|
final service = GeckoEventService.setUp();
|
||||||
|
|
||||||
ref.onDispose(() {
|
ref.onDispose(() {
|
||||||
@@ -84,6 +85,17 @@ GeckoEventService eventService(EventServiceRef ref) {
|
|||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
GeckoAddonService addonService(Ref ref) {
|
||||||
|
final service = GeckoAddonService.setUp();
|
||||||
|
|
||||||
|
ref.onDispose(() {
|
||||||
|
service.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
class EngineReadyState extends _$EngineReadyState {
|
class EngineReadyState extends _$EngineReadyState {
|
||||||
@override
|
@override
|
||||||
@@ -120,6 +132,6 @@ class EngineReadyState extends _$EngineReadyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Raw<TabSession> selectedTabSessionNotifier(SelectedTabSessionNotifierRef ref) {
|
Raw<TabSession> selectedTabSessionNotifier(Ref ref) {
|
||||||
return ref.watch(tabSessionProvider(null).notifier);
|
return ref.watch(tabSessionProvider(null).notifier);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'providers.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$selectionActionServiceHash() =>
|
String _$selectionActionServiceHash() =>
|
||||||
r'c150f6003dcea80b18fc063dd998ab45ce27d1a1';
|
r'b5bc6b2bc5496ae84d61a74cc6ff052b55d2a3d3';
|
||||||
|
|
||||||
/// See also [selectionActionService].
|
/// See also [selectionActionService].
|
||||||
@ProviderFor(selectionActionService)
|
@ProviderFor(selectionActionService)
|
||||||
@@ -22,8 +22,10 @@ final selectionActionServiceProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef SelectionActionServiceRef = ProviderRef<GeckoSelectionActionService>;
|
typedef SelectionActionServiceRef = ProviderRef<GeckoSelectionActionService>;
|
||||||
String _$eventServiceHash() => r'5aa357fdf0d217677a9a66ecb50417ac18929cad';
|
String _$eventServiceHash() => r'166b01f636fbdd4355dbc55a18ca4f83e0006de8';
|
||||||
|
|
||||||
/// See also [eventService].
|
/// See also [eventService].
|
||||||
@ProviderFor(eventService)
|
@ProviderFor(eventService)
|
||||||
@@ -36,9 +38,27 @@ final eventServiceProvider = Provider<GeckoEventService>.internal(
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef EventServiceRef = ProviderRef<GeckoEventService>;
|
typedef EventServiceRef = ProviderRef<GeckoEventService>;
|
||||||
|
String _$addonServiceHash() => r'c7aca09b99c3810908176f3464f5f90a185aa5e7';
|
||||||
|
|
||||||
|
/// See also [addonService].
|
||||||
|
@ProviderFor(addonService)
|
||||||
|
final addonServiceProvider = Provider<GeckoAddonService>.internal(
|
||||||
|
addonService,
|
||||||
|
name: r'addonServiceProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product') ? null : _$addonServiceHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
typedef AddonServiceRef = ProviderRef<GeckoAddonService>;
|
||||||
String _$selectedTabSessionNotifierHash() =>
|
String _$selectedTabSessionNotifierHash() =>
|
||||||
r'ea9959e871dd0c3a8b80152eafe726c925094106';
|
r'62fcd98a915566d55b5bcb297d87d675fe12786d';
|
||||||
|
|
||||||
/// See also [selectedTabSessionNotifier].
|
/// See also [selectedTabSessionNotifier].
|
||||||
@ProviderFor(selectedTabSessionNotifier)
|
@ProviderFor(selectedTabSessionNotifier)
|
||||||
@@ -53,6 +73,8 @@ final selectedTabSessionNotifierProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef SelectedTabSessionNotifierRef = AutoDisposeProviderRef<Raw<TabSession>>;
|
typedef SelectedTabSessionNotifierRef = AutoDisposeProviderRef<Raw<TabSession>>;
|
||||||
String _$engineReadyStateHash() => r'c682333e2e07cf0635aa7ae793a2088ca648c950';
|
String _$engineReadyStateHash() => r'c682333e2e07cf0635aa7ae793a2088ca648c950';
|
||||||
|
|
||||||
@@ -71,4 +93,4 @@ final engineReadyStateProvider =
|
|||||||
|
|
||||||
typedef _$EngineReadyState = Notifier<bool>;
|
typedef _$EngineReadyState = Notifier<bool>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ final selectedTabProvider = NotifierProvider<SelectedTab, String?>.internal(
|
|||||||
|
|
||||||
typedef _$SelectedTab = Notifier<String?>;
|
typedef _$SelectedTab = Notifier<String?>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ part 'tab_list.g.dart';
|
|||||||
class TabList extends _$TabList {
|
class TabList extends _$TabList {
|
||||||
late TabDatabase _db;
|
late TabDatabase _db;
|
||||||
|
|
||||||
|
@override
|
||||||
List<String> build() {
|
List<String> build() {
|
||||||
final eventService = ref.watch(eventServiceProvider);
|
final eventService = ref.watch(eventServiceProvider);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'tab_list.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$tabListHash() => r'fd97d4692b1c74e91c5ebd4a75e6ff45ceb82ef9';
|
String _$tabListHash() => r'3c17372cc467736ce1cfba937999acf4de7345ef';
|
||||||
|
|
||||||
/// See also [TabList].
|
/// See also [TabList].
|
||||||
@ProviderFor(TabList)
|
@ProviderFor(TabList)
|
||||||
@@ -21,4 +21,4 @@ final tabListProvider = NotifierProvider<TabList, List<String>>.internal(
|
|||||||
|
|
||||||
typedef _$TabList = Notifier<List<String>>;
|
typedef _$TabList = Notifier<List<String>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ class TabSession extends _$TabSession {
|
|||||||
return _sessionService.exitFullscreen();
|
return _sessionService.exitFullscreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Uint8List?> requestScreenshot() {
|
Future<Uint8List?> requestScreenshot({bool requireImageResult = true}) {
|
||||||
return _sessionService.requestScreenshot();
|
return _sessionService.requestScreenshot(requireImageResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'tab_session.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$tabSessionHash() => r'29b20f40af01e599ef80e198aec5f093d74efc6a';
|
String _$tabSessionHash() => r'42b44a4d47b9a551d002fdbc6337c14b2c327dde';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -155,6 +155,8 @@ class TabSessionProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin TabSessionRef on AutoDisposeNotifierProviderRef<void> {
|
mixin TabSessionRef on AutoDisposeNotifierProviderRef<void> {
|
||||||
/// The parameter `tabId` of this provider.
|
/// The parameter `tabId` of this provider.
|
||||||
String? get tabId;
|
String? get tabId;
|
||||||
@@ -169,4 +171,4 @@ class _TabSessionProviderElement
|
|||||||
String? get tabId => (origin as TabSessionProvider).tabId;
|
String? get tabId => (origin as TabSessionProvider).tabId;
|
||||||
}
|
}
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:lensai/features/geckoview/domain/entities/tab_state.dart';
|
|||||||
import 'package:lensai/features/geckoview/domain/providers.dart';
|
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
|
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
|
||||||
import 'package:lensai/features/geckoview/utils/image_helper.dart';
|
import 'package:lensai/features/geckoview/utils/image_helper.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:synchronized/synchronized.dart';
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
@@ -190,7 +191,7 @@ class TabStates extends _$TabStates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
TabState? tabState(TabStateRef ref, String? tabId) {
|
TabState? tabState(Ref ref, String? tabId) {
|
||||||
if (tabId == null) {
|
if (tabId == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -201,7 +202,7 @@ TabState? tabState(TabStateRef ref, String? tabId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
TabState? selectedTabState(SelectedTabStateRef ref) {
|
TabState? selectedTabState(Ref ref) {
|
||||||
final tabId = ref.watch(selectedTabProvider);
|
final tabId = ref.watch(selectedTabProvider);
|
||||||
return ref.watch(tabStateProvider(tabId));
|
return ref.watch(tabStateProvider(tabId));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'tab_state.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$tabStateHash() => r'9fd7990804643fac180dd4fd50803bc7c9fa2827';
|
String _$tabStateHash() => r'f57b2353acc99ca73670d504b45ea5ff19df38c7';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -141,6 +141,8 @@ class TabStateProvider extends AutoDisposeProvider<TabState?> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin TabStateRef on AutoDisposeProviderRef<TabState?> {
|
mixin TabStateRef on AutoDisposeProviderRef<TabState?> {
|
||||||
/// The parameter `tabId` of this provider.
|
/// The parameter `tabId` of this provider.
|
||||||
String? get tabId;
|
String? get tabId;
|
||||||
@@ -154,7 +156,7 @@ class _TabStateProviderElement extends AutoDisposeProviderElement<TabState?>
|
|||||||
String? get tabId => (origin as TabStateProvider).tabId;
|
String? get tabId => (origin as TabStateProvider).tabId;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$selectedTabStateHash() => r'22172913554e14e67f692eff0777ea015175906e';
|
String _$selectedTabStateHash() => r'dbd36af7af286bd9d079f30e8e11bbda23bf7728';
|
||||||
|
|
||||||
/// See also [selectedTabState].
|
/// See also [selectedTabState].
|
||||||
@ProviderFor(selectedTabState)
|
@ProviderFor(selectedTabState)
|
||||||
@@ -168,6 +170,8 @@ final selectedTabStateProvider = AutoDisposeProvider<TabState?>.internal(
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef SelectedTabStateRef = AutoDisposeProviderRef<TabState?>;
|
typedef SelectedTabStateRef = AutoDisposeProviderRef<TabState?>;
|
||||||
String _$tabStatesHash() => r'dcd293279a901eeaab7728979e39e5ca3bee8c66';
|
String _$tabStatesHash() => r'dcd293279a901eeaab7728979e39e5ca3bee8c66';
|
||||||
|
|
||||||
@@ -185,4 +189,4 @@ final tabStatesProvider =
|
|||||||
|
|
||||||
typedef _$TabStates = Notifier<Map<String, TabState>>;
|
typedef _$TabStates = Notifier<Map<String, TabState>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:lensai/domain/entities/equatable_image.dart';
|
||||||
|
import 'package:lensai/extensions/image.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/entities/web_extension_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/utils/image_helper.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
|
part 'web_extensions_state.g.dart';
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class WebExtensionsState extends _$WebExtensionsState {
|
||||||
|
final _imageCache = <String, EquatableImage>{};
|
||||||
|
|
||||||
|
final _lock = Lock();
|
||||||
|
|
||||||
|
void _onExtensionUpdate(ExtensionDataEvent event) {
|
||||||
|
final ExtensionDataEvent(:extensionId, :data) = event;
|
||||||
|
|
||||||
|
if (data != null) {
|
||||||
|
final current = state[extensionId] ??
|
||||||
|
WebExtensionState(
|
||||||
|
extensionId: extensionId,
|
||||||
|
icon: _imageCache[extensionId],
|
||||||
|
enabled: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
state = {...state}..[extensionId] = current.copyWith(
|
||||||
|
title: data.title,
|
||||||
|
enabled: data.enabled,
|
||||||
|
badgeText: data.badgeText,
|
||||||
|
badgeTextColor: (data.badgeTextColor != null)
|
||||||
|
? Color(data.badgeTextColor!)
|
||||||
|
: null,
|
||||||
|
badgeBackgroundColor: (data.badgeBackgroundColor != null)
|
||||||
|
? Color(data.badgeBackgroundColor!)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (state.containsKey(extensionId)) {
|
||||||
|
state = {...state}..remove(extensionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onIconChange(ExtensionIconEvent event) async {
|
||||||
|
final ExtensionIconEvent(:extensionId, :bytes) = event;
|
||||||
|
|
||||||
|
final image =
|
||||||
|
await tryDecodeImage(bytes).then((image) async => image?.toEquatable());
|
||||||
|
|
||||||
|
if (image != null) {
|
||||||
|
if (_imageCache[extensionId] != image) {
|
||||||
|
_imageCache[extensionId] = image;
|
||||||
|
|
||||||
|
if (state.containsKey(extensionId)) {
|
||||||
|
state = {...state}..[extensionId] =
|
||||||
|
state[extensionId]!.copyWith.icon(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, WebExtensionState> build(WebExtensionActionType actionType) {
|
||||||
|
final addonService = ref.watch(addonServiceProvider);
|
||||||
|
|
||||||
|
final subscriptions = switch (actionType) {
|
||||||
|
WebExtensionActionType.browser => [
|
||||||
|
addonService.browserExtensionStream.listen(
|
||||||
|
(event) async {
|
||||||
|
await _lock.synchronized(() => _onExtensionUpdate(event));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
addonService.browserIconStream.listen(
|
||||||
|
(event) async {
|
||||||
|
await _lock.synchronized(() => _onIconChange(event));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
WebExtensionActionType.page => [
|
||||||
|
addonService.pageExtensionStream.listen(
|
||||||
|
(event) async {
|
||||||
|
await _lock.synchronized(() => _onExtensionUpdate(event));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
addonService.pageIconStream.listen(
|
||||||
|
(event) async {
|
||||||
|
await _lock.synchronized(() => _onIconChange(event));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
ref.onDispose(() {
|
||||||
|
for (final sub in subscriptions) {
|
||||||
|
unawaited(sub.cancel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'web_extensions_state.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$webExtensionsStateHash() =>
|
||||||
|
r'9ac102b1d1740d69f9b0de590f08ff0774064845';
|
||||||
|
|
||||||
|
/// Copied from Dart SDK
|
||||||
|
class _SystemHash {
|
||||||
|
_SystemHash._();
|
||||||
|
|
||||||
|
static int combine(int hash, int value) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + value);
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||||
|
return hash ^ (hash >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int finish(int hash) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = hash ^ (hash >> 11);
|
||||||
|
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _$WebExtensionsState
|
||||||
|
extends BuildlessNotifier<Map<String, WebExtensionState>> {
|
||||||
|
late final WebExtensionActionType actionType;
|
||||||
|
|
||||||
|
Map<String, WebExtensionState> build(
|
||||||
|
WebExtensionActionType actionType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [WebExtensionsState].
|
||||||
|
@ProviderFor(WebExtensionsState)
|
||||||
|
const webExtensionsStateProvider = WebExtensionsStateFamily();
|
||||||
|
|
||||||
|
/// See also [WebExtensionsState].
|
||||||
|
class WebExtensionsStateFamily extends Family<Map<String, WebExtensionState>> {
|
||||||
|
/// See also [WebExtensionsState].
|
||||||
|
const WebExtensionsStateFamily();
|
||||||
|
|
||||||
|
/// See also [WebExtensionsState].
|
||||||
|
WebExtensionsStateProvider call(
|
||||||
|
WebExtensionActionType actionType,
|
||||||
|
) {
|
||||||
|
return WebExtensionsStateProvider(
|
||||||
|
actionType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebExtensionsStateProvider getProviderOverride(
|
||||||
|
covariant WebExtensionsStateProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
provider.actionType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'webExtensionsStateProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [WebExtensionsState].
|
||||||
|
class WebExtensionsStateProvider extends NotifierProviderImpl<
|
||||||
|
WebExtensionsState, Map<String, WebExtensionState>> {
|
||||||
|
/// See also [WebExtensionsState].
|
||||||
|
WebExtensionsStateProvider(
|
||||||
|
WebExtensionActionType actionType,
|
||||||
|
) : this._internal(
|
||||||
|
() => WebExtensionsState()..actionType = actionType,
|
||||||
|
from: webExtensionsStateProvider,
|
||||||
|
name: r'webExtensionsStateProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$webExtensionsStateHash,
|
||||||
|
dependencies: WebExtensionsStateFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
WebExtensionsStateFamily._allTransitiveDependencies,
|
||||||
|
actionType: actionType,
|
||||||
|
);
|
||||||
|
|
||||||
|
WebExtensionsStateProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.actionType,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final WebExtensionActionType actionType;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, WebExtensionState> runNotifierBuild(
|
||||||
|
covariant WebExtensionsState notifier,
|
||||||
|
) {
|
||||||
|
return notifier.build(
|
||||||
|
actionType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(WebExtensionsState Function() create) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: WebExtensionsStateProvider._internal(
|
||||||
|
() => create()..actionType = actionType,
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
actionType: actionType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
NotifierProviderElement<WebExtensionsState, Map<String, WebExtensionState>>
|
||||||
|
createElement() {
|
||||||
|
return _WebExtensionsStateProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is WebExtensionsStateProvider &&
|
||||||
|
other.actionType == actionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, actionType.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin WebExtensionsStateRef
|
||||||
|
on NotifierProviderRef<Map<String, WebExtensionState>> {
|
||||||
|
/// The parameter `actionType` of this provider.
|
||||||
|
WebExtensionActionType get actionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WebExtensionsStateProviderElement extends NotifierProviderElement<
|
||||||
|
WebExtensionsState,
|
||||||
|
Map<String, WebExtensionState>> with WebExtensionsStateRef {
|
||||||
|
_WebExtensionsStateProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WebExtensionActionType get actionType =>
|
||||||
|
(origin as WebExtensionsStateProvider).actionType;
|
||||||
|
}
|
||||||
|
// 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
|
||||||
@@ -22,4 +22,4 @@ final tabRepositoryProvider = NotifierProvider<TabRepository, void>.internal(
|
|||||||
|
|
||||||
typedef _$TabRepository = Notifier<void>;
|
typedef _$TabRepository = Notifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:lensai/features/bangs/domain/repositories/data.dart';
|
|||||||
import 'package:lensai/features/geckoview/domain/providers/tab_list.dart';
|
import 'package:lensai/features/geckoview/domain/providers/tab_list.dart';
|
||||||
import 'package:lensai/features/geckoview/features/tabs/domain/providers.dart';
|
import 'package:lensai/features/geckoview/features/tabs/domain/providers.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
@@ -28,7 +29,7 @@ class SelectedBangTrigger extends _$SelectedBangTrigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<BangData?> selectedBangData(SelectedBangDataRef ref, {String? domain}) {
|
Stream<BangData?> selectedBangData(Ref ref, {String? domain}) {
|
||||||
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
final repository = ref.watch(bangDataRepositoryProvider.notifier);
|
||||||
final selectedBangTrigger =
|
final selectedBangTrigger =
|
||||||
ref.watch(selectedBangTriggerProvider(domain: domain));
|
ref.watch(selectedBangTriggerProvider(domain: domain));
|
||||||
@@ -85,7 +86,7 @@ class ShowFindInPage extends _$ShowFindInPage {
|
|||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
List<String> availableTabIds(
|
List<String> availableTabIds(
|
||||||
AvailableTabIdsRef ref,
|
Ref ref,
|
||||||
String? containerId,
|
String? containerId,
|
||||||
) {
|
) {
|
||||||
final containerTabs = ref.watch(
|
final containerTabs = ref.watch(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'providers.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$selectedBangDataHash() => r'40dd3c51694394909fe83659ff3e19d51a06ec55';
|
String _$selectedBangDataHash() => r'd43e679c40d35c4f4c692ee286dc21789d7287dd';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -142,6 +142,8 @@ class SelectedBangDataProvider extends AutoDisposeStreamProvider<BangData?> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin SelectedBangDataRef on AutoDisposeStreamProviderRef<BangData?> {
|
mixin SelectedBangDataRef on AutoDisposeStreamProviderRef<BangData?> {
|
||||||
/// The parameter `domain` of this provider.
|
/// The parameter `domain` of this provider.
|
||||||
String? get domain;
|
String? get domain;
|
||||||
@@ -156,7 +158,7 @@ class _SelectedBangDataProviderElement
|
|||||||
String? get domain => (origin as SelectedBangDataProvider).domain;
|
String? get domain => (origin as SelectedBangDataProvider).domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$availableTabIdsHash() => r'427ea2e58c6bc27e2f16cffb850dc6621875e247';
|
String _$availableTabIdsHash() => r'646d42c747d815496849c7342903caf48258a8ab';
|
||||||
|
|
||||||
/// See also [availableTabIds].
|
/// See also [availableTabIds].
|
||||||
@ProviderFor(availableTabIds)
|
@ProviderFor(availableTabIds)
|
||||||
@@ -271,6 +273,8 @@ class AvailableTabIdsProvider extends AutoDisposeProvider<List<String>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin AvailableTabIdsRef on AutoDisposeProviderRef<List<String>> {
|
mixin AvailableTabIdsRef on AutoDisposeProviderRef<List<String>> {
|
||||||
/// The parameter `containerId` of this provider.
|
/// The parameter `containerId` of this provider.
|
||||||
String? get containerId;
|
String? get containerId;
|
||||||
@@ -413,6 +417,8 @@ class SelectedBangTriggerProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin SelectedBangTriggerRef on NotifierProviderRef<String?> {
|
mixin SelectedBangTriggerRef on NotifierProviderRef<String?> {
|
||||||
/// The parameter `domain` of this provider.
|
/// The parameter `domain` of this provider.
|
||||||
String? get domain;
|
String? get domain;
|
||||||
@@ -493,4 +499,4 @@ final showFindInPageProvider = NotifierProvider<ShowFindInPage, bool>.internal(
|
|||||||
|
|
||||||
typedef _$ShowFindInPage = Notifier<bool>;
|
typedef _$ShowFindInPage = Notifier<bool>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ final createTabStreamProvider =
|
|||||||
|
|
||||||
typedef _$CreateTabStream = AutoDisposeStreamNotifier<CreateTabSheet>;
|
typedef _$CreateTabStream = AutoDisposeStreamNotifier<CreateTabSheet>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'engine_settings.g.dart';
|
part 'engine_settings.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
GeckoEngineSettingsService engineSettingsService(EngineSettingsServiceRef ref) {
|
GeckoEngineSettingsService engineSettingsService(Ref ref) {
|
||||||
return GeckoEngineSettingsService();
|
return GeckoEngineSettingsService();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'engine_settings.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$engineSettingsServiceHash() =>
|
String _$engineSettingsServiceHash() =>
|
||||||
r'9d9abb3601a3782f1f3ef91e31049db40acbf64a';
|
r'051d7b6f65eb5dcb07405b4af1bdadd8dd74fdc0';
|
||||||
|
|
||||||
/// See also [engineSettingsService].
|
/// See also [engineSettingsService].
|
||||||
@ProviderFor(engineSettingsService)
|
@ProviderFor(engineSettingsService)
|
||||||
@@ -22,6 +22,8 @@ final engineSettingsServiceProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef EngineSettingsServiceRef = ProviderRef<GeckoEngineSettingsService>;
|
typedef EngineSettingsServiceRef = ProviderRef<GeckoEngineSettingsService>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:lensai/core/logger.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers/web_extensions_state.dart';
|
||||||
|
|
||||||
|
class BrowserView extends StatefulHookConsumerWidget {
|
||||||
|
final Duration screenshotPeriod;
|
||||||
|
|
||||||
|
const BrowserView({this.screenshotPeriod = const Duration(seconds: 10)});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<ConsumerStatefulWidget> createState() => _BrowserViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BrowserViewState extends ConsumerState<BrowserView>
|
||||||
|
with WidgetsBindingObserver {
|
||||||
|
Timer? _periodicScreenshotUpdate;
|
||||||
|
|
||||||
|
//This is managed by widget state changes to resume a timer
|
||||||
|
bool _timerPaused = false;
|
||||||
|
|
||||||
|
Future<void> _timerTick(Timer timer) async {
|
||||||
|
await ref
|
||||||
|
.read(selectedTabSessionNotifierProvider)
|
||||||
|
.requestScreenshot(requireImageResult: false)
|
||||||
|
.onError((error, stackTrace) {
|
||||||
|
logger.e(error, stackTrace: stackTrace);
|
||||||
|
timer.cancel();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
ref.listen(
|
||||||
|
selectedTabStateProvider.select(
|
||||||
|
(state) => (tabId: state?.id, isLoading: state?.isLoading),
|
||||||
|
),
|
||||||
|
(previous, next) {
|
||||||
|
if (previous?.tabId != next.tabId || next.isLoading == true) {
|
||||||
|
_periodicScreenshotUpdate?.cancel();
|
||||||
|
_periodicScreenshotUpdate = null;
|
||||||
|
_timerPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next.isLoading == false &&
|
||||||
|
(_periodicScreenshotUpdate?.isActive ?? false) == false) {
|
||||||
|
_timerPaused = false;
|
||||||
|
_periodicScreenshotUpdate =
|
||||||
|
Timer.periodic(widget.screenshotPeriod, _timerTick);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return GeckoView(
|
||||||
|
preInitializationStep: () async {
|
||||||
|
await ref
|
||||||
|
.read(eventServiceProvider)
|
||||||
|
.viewReadyStateEvents
|
||||||
|
.firstWhere((state) => state == true)
|
||||||
|
.timeout(
|
||||||
|
const Duration(seconds: 3),
|
||||||
|
onTimeout: () {
|
||||||
|
logger.e(
|
||||||
|
'Browser fragement not reported ready, trying to intitialize anyways',
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
|
||||||
|
//Initialize and register dependencies
|
||||||
|
ref.listenManual(
|
||||||
|
selectionActionServiceProvider,
|
||||||
|
(previous, next) {},
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.listenManual(
|
||||||
|
webExtensionsStateProvider(WebExtensionActionType.browser),
|
||||||
|
(previous, next) {},
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.listenManual(
|
||||||
|
webExtensionsStateProvider(WebExtensionActionType.page),
|
||||||
|
(previous, next) {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
|
super.didChangeAppLifecycleState(state);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case AppLifecycleState.detached:
|
||||||
|
case AppLifecycleState.inactive:
|
||||||
|
case AppLifecycleState.hidden:
|
||||||
|
case AppLifecycleState.paused:
|
||||||
|
if (_periodicScreenshotUpdate?.isActive == true) {
|
||||||
|
_periodicScreenshotUpdate?.cancel();
|
||||||
|
_timerPaused = true;
|
||||||
|
}
|
||||||
|
case AppLifecycleState.resumed:
|
||||||
|
if (_timerPaused) {
|
||||||
|
_periodicScreenshotUpdate =
|
||||||
|
Timer.periodic(widget.screenshotPeriod, _timerTick);
|
||||||
|
_timerPaused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
|
||||||
|
_periodicScreenshotUpdate?.cancel();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,18 +6,19 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart
|
|||||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:lensai/core/logger.dart';
|
|
||||||
import 'package:lensai/core/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/providers.dart';
|
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/providers/tab_list.dart';
|
import 'package:lensai/features/geckoview/domain/providers/tab_list.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers/web_extensions_state.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||||
import 'package:lensai/features/geckoview/features/browser/domain/entities/sheet.dart';
|
import 'package:lensai/features/geckoview/features/browser/domain/entities/sheet.dart';
|
||||||
import 'package:lensai/features/geckoview/features/browser/domain/services/create_tab.dart';
|
import 'package:lensai/features/geckoview/features/browser/domain/services/create_tab.dart';
|
||||||
import 'package:lensai/features/geckoview/features/browser/domain/services/engine_settings.dart';
|
import 'package:lensai/features/geckoview/features/browser/domain/services/engine_settings.dart';
|
||||||
import 'package:lensai/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart';
|
import 'package:lensai/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart';
|
||||||
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/app_bar_title.dart';
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/app_bar_title.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/browser_view.dart';
|
||||||
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/sheets/create_tab.dart';
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/sheets/create_tab.dart';
|
||||||
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart';
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart';
|
||||||
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart';
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart';
|
||||||
@@ -219,7 +220,8 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
ref
|
ref
|
||||||
.read(
|
.read(
|
||||||
createTabStreamProvider.notifier)
|
createTabStreamProvider.notifier,
|
||||||
|
)
|
||||||
.createTab(
|
.createTab(
|
||||||
CreateTabSheet(
|
CreateTabSheet(
|
||||||
preferredTool: KagiTool.assistant,
|
preferredTool: KagiTool.assistant,
|
||||||
@@ -278,7 +280,8 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
horizontal: 8.0,
|
horizontal: 8.0,
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
quickActionVoice ? Icons.mic : quickAction.icon),
|
quickActionVoice ? Icons.mic : quickAction.icon,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TabsActionButton(
|
TabsActionButton(
|
||||||
@@ -310,13 +313,60 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
child: const Padding(
|
child: const Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
vertical: 15.0, horizontal: 8.0),
|
vertical: 15.0,
|
||||||
|
horizontal: 8.0,
|
||||||
|
),
|
||||||
child: Icon(Icons.more_vert),
|
child: Icon(Icons.more_vert),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
menuChildren: [
|
menuChildren: [
|
||||||
|
Consumer(
|
||||||
|
builder: (context, childRef, child) {
|
||||||
|
final pageExtensions = childRef.watch(
|
||||||
|
webExtensionsStateProvider(
|
||||||
|
WebExtensionActionType.page,
|
||||||
|
).select((value) => value.values.toList()),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Wrap(
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
children: [
|
||||||
|
...pageExtensions.map(
|
||||||
|
(extension) => IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
//Use parents .ref because after onPressed this consumer gets disposed already
|
||||||
|
await ref
|
||||||
|
.read(addonServiceProvider)
|
||||||
|
.invokeAddonAction(
|
||||||
|
extension.extensionId,
|
||||||
|
WebExtensionActionType.page,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: Badge(
|
||||||
|
isLabelVisible:
|
||||||
|
extension.badgeText?.isNotEmpty ??
|
||||||
|
false,
|
||||||
|
label: (extension.badgeText?.isNotEmpty ==
|
||||||
|
true)
|
||||||
|
? Text(extension.badgeText!)
|
||||||
|
: null,
|
||||||
|
textColor: extension.badgeTextColor,
|
||||||
|
backgroundColor:
|
||||||
|
extension.badgeBackgroundColor,
|
||||||
|
child: RawImage(
|
||||||
|
image: extension.icon?.value,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await context.push(AboutRoute().location);
|
await context.push(AboutRoute().location);
|
||||||
@@ -332,6 +382,50 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
leadingIcon: const Icon(Icons.settings),
|
leadingIcon: const Icon(Icons.settings),
|
||||||
child: const Text('Settings'),
|
child: const Text('Settings'),
|
||||||
),
|
),
|
||||||
|
Consumer(
|
||||||
|
builder: (context, childRef, child) {
|
||||||
|
final browserExtensions = childRef.watch(
|
||||||
|
webExtensionsStateProvider(
|
||||||
|
WebExtensionActionType.browser,
|
||||||
|
).select((value) => value.values.toList()),
|
||||||
|
);
|
||||||
|
|
||||||
|
return SubmenuButton(
|
||||||
|
menuChildren: [
|
||||||
|
...browserExtensions.map(
|
||||||
|
(extension) => MenuItemButton(
|
||||||
|
onPressed: () async {
|
||||||
|
//Use parents .ref because after onPressed this consumer gets disposed already
|
||||||
|
await ref
|
||||||
|
.read(addonServiceProvider)
|
||||||
|
.invokeAddonAction(
|
||||||
|
extension.extensionId,
|
||||||
|
WebExtensionActionType.browser,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
leadingIcon: RawImage(
|
||||||
|
image: extension.icon?.value,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
child: Text(extension.title ?? ''),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
MenuItemButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await childRef
|
||||||
|
.read(addonServiceProvider)
|
||||||
|
.startAddonManagerActivity();
|
||||||
|
},
|
||||||
|
leadingIcon: const Icon(MdiIcons.puzzleEdit),
|
||||||
|
child: const Text('Addon Manager'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
leadingIcon: const Icon(MdiIcons.puzzle),
|
||||||
|
child: const Text('Addons'),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
@@ -340,53 +434,56 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
leadingIcon: const Icon(MdiIcons.exclamationThick),
|
leadingIcon: const Icon(MdiIcons.exclamationThick),
|
||||||
child: const Text('Bangs'),
|
child: const Text('Bangs'),
|
||||||
),
|
),
|
||||||
if (showEarlyAccessFeatures)
|
// if (showEarlyAccessFeatures)
|
||||||
MenuItemButton(
|
// MenuItemButton(
|
||||||
onPressed: () async {
|
// onPressed: () async {
|
||||||
await context
|
// await context
|
||||||
.push(ChatArchiveListRoute().location);
|
// .push(ChatArchiveListRoute().location);
|
||||||
},
|
// },
|
||||||
leadingIcon: const Icon(MdiIcons.archive),
|
// leadingIcon: const Icon(MdiIcons.archive),
|
||||||
child: const Text('Chat Archive'),
|
// child: const Text('Chat Archive'),
|
||||||
),
|
// ),
|
||||||
const Divider(),
|
// const Divider(),
|
||||||
if (showEarlyAccessFeatures)
|
// if (showEarlyAccessFeatures)
|
||||||
MenuItemButton(
|
// MenuItemButton(
|
||||||
onPressed: () {
|
// onPressed: () {
|
||||||
ref
|
// ref
|
||||||
.read(createTabStreamProvider.notifier)
|
// .read(createTabStreamProvider.notifier)
|
||||||
.createTab(
|
// .createTab(
|
||||||
CreateTabSheet(
|
// CreateTabSheet(
|
||||||
preferredTool: KagiTool.assistant),
|
// preferredTool: KagiTool.assistant,
|
||||||
);
|
// ),
|
||||||
},
|
// );
|
||||||
leadingIcon: Icon(KagiTool.assistant.icon),
|
// },
|
||||||
child: const Text('Assistant'),
|
// leadingIcon: Icon(KagiTool.assistant.icon),
|
||||||
),
|
// child: const Text('Assistant'),
|
||||||
MenuItemButton(
|
// ),
|
||||||
onPressed: () {
|
// MenuItemButton(
|
||||||
ref
|
// onPressed: () {
|
||||||
.read(createTabStreamProvider.notifier)
|
// ref
|
||||||
.createTab(
|
// .read(createTabStreamProvider.notifier)
|
||||||
CreateTabSheet(
|
// .createTab(
|
||||||
preferredTool: KagiTool.summarizer),
|
// CreateTabSheet(
|
||||||
);
|
// preferredTool: KagiTool.summarizer,
|
||||||
},
|
// ),
|
||||||
leadingIcon: Icon(KagiTool.summarizer.icon),
|
// );
|
||||||
child: const Text('Summarizer'),
|
// },
|
||||||
),
|
// leadingIcon: Icon(KagiTool.summarizer.icon),
|
||||||
MenuItemButton(
|
// child: const Text('Summarizer'),
|
||||||
onPressed: () {
|
// ),
|
||||||
ref
|
// MenuItemButton(
|
||||||
.read(createTabStreamProvider.notifier)
|
// onPressed: () {
|
||||||
.createTab(
|
// ref
|
||||||
CreateTabSheet(
|
// .read(createTabStreamProvider.notifier)
|
||||||
preferredTool: KagiTool.search),
|
// .createTab(
|
||||||
);
|
// CreateTabSheet(
|
||||||
},
|
// preferredTool: KagiTool.search,
|
||||||
leadingIcon: Icon(KagiTool.search.icon),
|
// ),
|
||||||
child: const Text('Search'),
|
// );
|
||||||
),
|
// },
|
||||||
|
// leadingIcon: Icon(KagiTool.search.icon),
|
||||||
|
// child: const Text('Search'),
|
||||||
|
// ),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
if (selectedTabId != null)
|
if (selectedTabId != null)
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
@@ -419,8 +516,10 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ref
|
ref
|
||||||
.read(findInPageVisibilityControllerProvider
|
.read(
|
||||||
.notifier)
|
findInPageVisibilityControllerProvider
|
||||||
|
.notifier,
|
||||||
|
)
|
||||||
.show();
|
.show();
|
||||||
},
|
},
|
||||||
leadingIcon: const Icon(Icons.search),
|
leadingIcon: const Icon(Icons.search),
|
||||||
@@ -431,7 +530,8 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final controller = ref.read(
|
final controller = ref.read(
|
||||||
tabSessionProvider(selectedTabId).notifier);
|
tabSessionProvider(selectedTabId).notifier,
|
||||||
|
);
|
||||||
|
|
||||||
await controller.reload();
|
await controller.reload();
|
||||||
menuController.close();
|
menuController.close();
|
||||||
@@ -479,7 +579,9 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 48, child: VerticalDivider()),
|
height: 48,
|
||||||
|
child: VerticalDivider(),
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: (history?.canGoForward == true)
|
onPressed: (history?.canGoForward == true)
|
||||||
@@ -607,30 +709,7 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
SafeArea(
|
SafeArea(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Consumer(
|
const BrowserView(),
|
||||||
builder: (context, ref, child) {
|
|
||||||
//Initialize dependencies
|
|
||||||
ref.watch(selectionActionServiceProvider);
|
|
||||||
|
|
||||||
return GeckoView(
|
|
||||||
preInitializationStep: () async {
|
|
||||||
await ref
|
|
||||||
.read(eventServiceProvider)
|
|
||||||
.viewReadyStateEvents
|
|
||||||
.firstWhere((state) => state == true)
|
|
||||||
.timeout(
|
|
||||||
const Duration(seconds: 3),
|
|
||||||
onTimeout: () {
|
|
||||||
logger.e(
|
|
||||||
'Browser fragement not reported ready, trying to intitialize anyways',
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
|
|||||||
@@ -40,4 +40,4 @@ final bottomSheetExtendProvider =
|
|||||||
|
|
||||||
typedef _$BottomSheetExtend = StreamNotifier<double>;
|
typedef _$BottomSheetExtend = StreamNotifier<double>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final overlayDialogControllerProvider =
|
|||||||
|
|
||||||
typedef _$OverlayDialogController = AutoDisposeNotifier<Widget?>;
|
typedef _$OverlayDialogController = AutoDisposeNotifier<Widget?>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
+3
-1
@@ -158,6 +158,8 @@ class FindInPageRepositoryProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin FindInPageRepositoryRef on AutoDisposeNotifierProviderRef<void> {
|
mixin FindInPageRepositoryRef on AutoDisposeNotifierProviderRef<void> {
|
||||||
/// The parameter `tabId` of this provider.
|
/// The parameter `tabId` of this provider.
|
||||||
String? get tabId;
|
String? get tabId;
|
||||||
@@ -172,4 +174,4 @@ class _FindInPageRepositoryProviderElement
|
|||||||
String? get tabId => (origin as FindInPageRepositoryProvider).tabId;
|
String? get tabId => (origin as FindInPageRepositoryProvider).tabId;
|
||||||
}
|
}
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
+1
-1
@@ -24,4 +24,4 @@ final findInPageVisibilityControllerProvider =
|
|||||||
|
|
||||||
typedef _$FindInPageVisibilityController = AutoDisposeNotifier<bool>;
|
typedef _$FindInPageVisibilityController = AutoDisposeNotifier<bool>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'readerable.g.dart';
|
part 'readerable.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
GeckoReaderableService readerableService(ReaderableServiceRef ref) {
|
GeckoReaderableService readerableService(Ref ref) {
|
||||||
final service = GeckoReaderableService.setUp();
|
final service = GeckoReaderableService.setUp();
|
||||||
|
|
||||||
ref.onDispose(() {
|
ref.onDispose(() {
|
||||||
@@ -15,7 +16,7 @@ GeckoReaderableService readerableService(ReaderableServiceRef ref) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<bool> appearanceButtonVisibility(AppearanceButtonVisibilityRef ref) {
|
Stream<bool> appearanceButtonVisibility(Ref ref) {
|
||||||
final service = ref.watch(readerableServiceProvider);
|
final service = ref.watch(readerableServiceProvider);
|
||||||
return service.appearanceVisibility;
|
return service.appearanceVisibility;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'readerable.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$readerableServiceHash() => r'aad722c3869b4ce8dbe336fada733b7d102434c5';
|
String _$readerableServiceHash() => r'03182c8afc41f5184322a3206473cbfa96df5819';
|
||||||
|
|
||||||
/// See also [readerableService].
|
/// See also [readerableService].
|
||||||
@ProviderFor(readerableService)
|
@ProviderFor(readerableService)
|
||||||
@@ -20,9 +20,11 @@ final readerableServiceProvider = Provider<GeckoReaderableService>.internal(
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef ReaderableServiceRef = ProviderRef<GeckoReaderableService>;
|
typedef ReaderableServiceRef = ProviderRef<GeckoReaderableService>;
|
||||||
String _$appearanceButtonVisibilityHash() =>
|
String _$appearanceButtonVisibilityHash() =>
|
||||||
r'996ec32ee111cfa713230a50fea3ae3a9984df7c';
|
r'e7102b63113937dd5d17028a5ec8dac428c38bbb';
|
||||||
|
|
||||||
/// See also [appearanceButtonVisibility].
|
/// See also [appearanceButtonVisibility].
|
||||||
@ProviderFor(appearanceButtonVisibility)
|
@ProviderFor(appearanceButtonVisibility)
|
||||||
@@ -37,6 +39,8 @@ final appearanceButtonVisibilityProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef AppearanceButtonVisibilityRef = AutoDisposeStreamProviderRef<bool>;
|
typedef AppearanceButtonVisibilityRef = AutoDisposeStreamProviderRef<bool>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
+1
-1
@@ -24,4 +24,4 @@ final readerableScreenControllerProvider =
|
|||||||
|
|
||||||
typedef _$ReaderableScreenController = AsyncNotifier<void>;
|
typedef _$ReaderableScreenController = AsyncNotifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:lensai/data/database/functions/lexo_rank_functions.dart';
|
|||||||
import 'package:lensai/features/geckoview/features/tabs/data/database/database.dart';
|
import 'package:lensai/features/geckoview/features/tabs/data/database/database.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:path_provider/path_provider.dart' as path_provider;
|
import 'package:path_provider/path_provider.dart' as path_provider;
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:sqlite3/sqlite3.dart';
|
import 'package:sqlite3/sqlite3.dart';
|
||||||
import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
|
import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
|
||||||
@@ -12,7 +13,7 @@ import 'package:universal_io/io.dart';
|
|||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
TabDatabase tabDatabase(TabDatabaseRef ref) {
|
TabDatabase tabDatabase(Ref ref) {
|
||||||
return TabDatabase(
|
return TabDatabase(
|
||||||
LazyDatabase(() async {
|
LazyDatabase(() async {
|
||||||
// put the database file, called db.sqlite here, into the documents folder
|
// put the database file, called db.sqlite here, into the documents folder
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'providers.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$tabDatabaseHash() => r'567872961683d21156a9af463466f8ddbdd02f1f';
|
String _$tabDatabaseHash() => r'1379e222fe4d43c119a89ec89a779ef35fbe1563';
|
||||||
|
|
||||||
/// See also [tabDatabase].
|
/// See also [tabDatabase].
|
||||||
@ProviderFor(tabDatabase)
|
@ProviderFor(tabDatabase)
|
||||||
@@ -19,6 +19,8 @@ final tabDatabaseProvider = Provider<TabDatabase>.internal(
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef TabDatabaseRef = ProviderRef<TabDatabase>;
|
typedef TabDatabaseRef = ProviderRef<TabDatabase>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import 'package:lensai/features/geckoview/features/tabs/data/models/container_da
|
|||||||
import 'package:lensai/features/geckoview/features/tabs/data/providers.dart';
|
import 'package:lensai/features/geckoview/features/tabs/data/providers.dart';
|
||||||
import 'package:lensai/features/geckoview/features/tabs/domain/repositories/container.dart';
|
import 'package:lensai/features/geckoview/features/tabs/domain/repositories/container.dart';
|
||||||
import 'package:lensai/features/geckoview/features/tabs/utils/color_palette.dart';
|
import 'package:lensai/features/geckoview/features/tabs/utils/color_palette.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Future<Color> unusedRandomContainerColor(
|
Future<Color> unusedRandomContainerColor(
|
||||||
UnusedRandomContainerColorRef ref,
|
Ref ref,
|
||||||
) async {
|
) async {
|
||||||
final repository = ref.watch(containerRepositoryProvider.notifier);
|
final repository = ref.watch(containerRepositoryProvider.notifier);
|
||||||
|
|
||||||
@@ -28,21 +29,21 @@ Future<Color> unusedRandomContainerColor(
|
|||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<List<ContainerDataWithCount>> containersWithCount(
|
Stream<List<ContainerDataWithCount>> containersWithCount(
|
||||||
ContainersWithCountRef ref,
|
Ref ref,
|
||||||
) {
|
) {
|
||||||
final db = ref.watch(tabDatabaseProvider);
|
final db = ref.watch(tabDatabaseProvider);
|
||||||
return db.containersWithCount().watch();
|
return db.containersWithCount().watch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<String?> tabContainerId(TabContainerIdRef ref, String tabId) {
|
Stream<String?> tabContainerId(Ref ref, String tabId) {
|
||||||
final db = ref.watch(tabDatabaseProvider);
|
final db = ref.watch(tabDatabaseProvider);
|
||||||
return db.tabDao.tabContainerId(tabId).watchSingle();
|
return db.tabDao.tabContainerId(tabId).watchSingle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<List<String>> containerTabIds(
|
Stream<List<String>> containerTabIds(
|
||||||
ContainerTabIdsRef ref,
|
Ref ref,
|
||||||
String? containerId,
|
String? containerId,
|
||||||
) {
|
) {
|
||||||
final db = ref.watch(tabDatabaseProvider);
|
final db = ref.watch(tabDatabaseProvider);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'providers.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$unusedRandomContainerColorHash() =>
|
String _$unusedRandomContainerColorHash() =>
|
||||||
r'129cefaefa895012a6d7b35da69773e28e3289cc';
|
r'913499b3de281ea0020db97ed67121652f53ec08';
|
||||||
|
|
||||||
/// See also [unusedRandomContainerColor].
|
/// See also [unusedRandomContainerColor].
|
||||||
@ProviderFor(unusedRandomContainerColor)
|
@ProviderFor(unusedRandomContainerColor)
|
||||||
@@ -22,9 +22,11 @@ final unusedRandomContainerColorProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef UnusedRandomContainerColorRef = AutoDisposeFutureProviderRef<Color>;
|
typedef UnusedRandomContainerColorRef = AutoDisposeFutureProviderRef<Color>;
|
||||||
String _$containersWithCountHash() =>
|
String _$containersWithCountHash() =>
|
||||||
r'e1bab28091dd1b9ecfd7d76e6393f459604c803a';
|
r'ee0734e4b71472b79636816616a158f54fa6bc23';
|
||||||
|
|
||||||
/// See also [containersWithCount].
|
/// See also [containersWithCount].
|
||||||
@ProviderFor(containersWithCount)
|
@ProviderFor(containersWithCount)
|
||||||
@@ -39,9 +41,11 @@ final containersWithCountProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef ContainersWithCountRef
|
typedef ContainersWithCountRef
|
||||||
= AutoDisposeStreamProviderRef<List<ContainerDataWithCount>>;
|
= AutoDisposeStreamProviderRef<List<ContainerDataWithCount>>;
|
||||||
String _$tabContainerIdHash() => r'8adbfdc2ef46219569073fe9e58967f4935a45e5';
|
String _$tabContainerIdHash() => r'726ddd000d23935a2c8ae39c7957412fab16016d';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -177,6 +181,8 @@ class TabContainerIdProvider extends AutoDisposeStreamProvider<String?> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin TabContainerIdRef on AutoDisposeStreamProviderRef<String?> {
|
mixin TabContainerIdRef on AutoDisposeStreamProviderRef<String?> {
|
||||||
/// The parameter `tabId` of this provider.
|
/// The parameter `tabId` of this provider.
|
||||||
String get tabId;
|
String get tabId;
|
||||||
@@ -190,7 +196,7 @@ class _TabContainerIdProviderElement
|
|||||||
String get tabId => (origin as TabContainerIdProvider).tabId;
|
String get tabId => (origin as TabContainerIdProvider).tabId;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$containerTabIdsHash() => r'79e9bccfb17cf3ce802638c8b806c5a76fa8f732';
|
String _$containerTabIdsHash() => r'7545a6c500b1832bf81c0838e257dfe5e051463d';
|
||||||
|
|
||||||
/// See also [containerTabIds].
|
/// See also [containerTabIds].
|
||||||
@ProviderFor(containerTabIds)
|
@ProviderFor(containerTabIds)
|
||||||
@@ -305,6 +311,8 @@ class ContainerTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin ContainerTabIdsRef on AutoDisposeStreamProviderRef<List<String>> {
|
mixin ContainerTabIdsRef on AutoDisposeStreamProviderRef<List<String>> {
|
||||||
/// The parameter `containerId` of this provider.
|
/// The parameter `containerId` of this provider.
|
||||||
String? get containerId;
|
String? get containerId;
|
||||||
@@ -319,4 +327,4 @@ class _ContainerTabIdsProviderElement
|
|||||||
String? get containerId => (origin as ContainerTabIdsProvider).containerId;
|
String? get containerId => (origin as ContainerTabIdsProvider).containerId;
|
||||||
}
|
}
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:lensai/features/geckoview/features/tabs/data/models/container_data.dart';
|
import 'package:lensai/features/geckoview/features/tabs/data/models/container_data.dart';
|
||||||
import 'package:lensai/features/geckoview/features/tabs/data/providers.dart';
|
import 'package:lensai/features/geckoview/features/tabs/data/providers.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'selected_container.g.dart';
|
part 'selected_container.g.dart';
|
||||||
@@ -29,7 +30,7 @@ class SelectedContainer extends _$SelectedContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<ContainerData?> selectedContainerData(SelectedContainerDataRef ref) {
|
Stream<ContainerData?> selectedContainerData(Ref ref) {
|
||||||
final db = ref.watch(tabDatabaseProvider);
|
final db = ref.watch(tabDatabaseProvider);
|
||||||
final selectedContainer = ref.watch(selectedContainerProvider);
|
final selectedContainer = ref.watch(selectedContainerProvider);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'selected_container.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$selectedContainerDataHash() =>
|
String _$selectedContainerDataHash() =>
|
||||||
r'dc930d1bb47b3c7989c6c119b0459f37d687af84';
|
r'1ec86a82e1fc4823a867285f05036c903633a165';
|
||||||
|
|
||||||
/// See also [selectedContainerData].
|
/// See also [selectedContainerData].
|
||||||
@ProviderFor(selectedContainerData)
|
@ProviderFor(selectedContainerData)
|
||||||
@@ -22,6 +22,8 @@ final selectedContainerDataProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef SelectedContainerDataRef = AutoDisposeStreamProviderRef<ContainerData?>;
|
typedef SelectedContainerDataRef = AutoDisposeStreamProviderRef<ContainerData?>;
|
||||||
String _$selectedContainerHash() => r'e38e86db5bd0584af9561156c26ceaea3d23aebf';
|
String _$selectedContainerHash() => r'e38e86db5bd0584af9561156c26ceaea3d23aebf';
|
||||||
|
|
||||||
@@ -40,4 +42,4 @@ final selectedContainerProvider =
|
|||||||
|
|
||||||
typedef _$SelectedContainer = Notifier<String?>;
|
typedef _$SelectedContainer = Notifier<String?>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final containerRepositoryProvider =
|
|||||||
|
|
||||||
typedef _$ContainerRepository = Notifier<void>;
|
typedef _$ContainerRepository = Notifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ final tabDataRepositoryProvider =
|
|||||||
|
|
||||||
typedef _$TabDataRepository = Notifier<void>;
|
typedef _$TabDataRepository = Notifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final kagiAutosuggestServiceProvider =
|
|||||||
|
|
||||||
typedef _$KagiAutosuggestService = Notifier<void>;
|
typedef _$KagiAutosuggestService = Notifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ final kagiChatServiceProvider =
|
|||||||
|
|
||||||
typedef _$KagiChatService = Notifier<void>;
|
typedef _$KagiChatService = Notifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final kagiSessionServiceProvider =
|
|||||||
|
|
||||||
typedef _$KagiSessionService = AutoDisposeNotifier<void>;
|
typedef _$KagiSessionService = AutoDisposeNotifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final autosuggestRepositoryProvider =
|
|||||||
|
|
||||||
typedef _$AutosuggestRepository = Notifier<Raw<Stream<List<String>>>>;
|
typedef _$AutosuggestRepository = Notifier<Raw<Stream<List<String>>>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ class Settings with FastEquatable {
|
|||||||
bool? incognitoMode,
|
bool? incognitoMode,
|
||||||
bool? enableJavascript,
|
bool? enableJavascript,
|
||||||
bool? launchUrlExternal,
|
bool? launchUrlExternal,
|
||||||
bool? enableContentBlocking,
|
|
||||||
bool? blockHttpProtocol,
|
bool? blockHttpProtocol,
|
||||||
ThemeMode? themeMode,
|
ThemeMode? themeMode,
|
||||||
this.quickAction,
|
this.quickAction,
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final settingsRepositoryProvider =
|
|||||||
|
|
||||||
typedef _$SettingsRepository = AsyncNotifier<Settings>;
|
typedef _$SettingsRepository = AsyncNotifier<Settings>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ final saveSettingsControllerProvider =
|
|||||||
|
|
||||||
typedef _$SaveSettingsController = AsyncNotifier<void>;
|
typedef _$SaveSettingsController = AsyncNotifier<void>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:lensai/core/logger.dart';
|
|||||||
import 'package:lensai/data/models/received_parameter.dart';
|
import 'package:lensai/data/models/received_parameter.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:mime/mime.dart' as mime;
|
import 'package:mime/mime.dart' as mime;
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:uri_to_file/uri_to_file.dart' as uri_to_file;
|
import 'package:uri_to_file/uri_to_file.dart' as uri_to_file;
|
||||||
@@ -48,7 +49,7 @@ final _sharingIntentTransformer =
|
|||||||
);
|
);
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Raw<Stream<ReceivedParameter>> sharingIntentStream(SharingIntentStreamRef ref) {
|
Raw<Stream<ReceivedParameter>> sharingIntentStream(Ref ref) {
|
||||||
final initialStream = FlutterSharingIntent.instance
|
final initialStream = FlutterSharingIntent.instance
|
||||||
// ignore: discarded_futures
|
// ignore: discarded_futures
|
||||||
.getInitialSharing()
|
.getInitialSharing()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'sharing_intent.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$sharingIntentStreamHash() =>
|
String _$sharingIntentStreamHash() =>
|
||||||
r'ce060aadf885ab0a14d90acfe986447ecb05f4f9';
|
r'd0634c3cbff4760eb637663716970b6ad35ccf36';
|
||||||
|
|
||||||
/// See also [sharingIntentStream].
|
/// See also [sharingIntentStream].
|
||||||
@ProviderFor(sharingIntentStream)
|
@ProviderFor(sharingIntentStream)
|
||||||
@@ -22,7 +22,9 @@ final sharingIntentStreamProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
typedef SharingIntentStreamRef
|
typedef SharingIntentStreamRef
|
||||||
= AutoDisposeProviderRef<Raw<Stream<ReceivedParameter>>>;
|
= AutoDisposeProviderRef<Raw<Stream<ReceivedParameter>>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import 'package:lensai/data/models/web_page_info.dart';
|
import 'package:lensai/data/models/web_page_info.dart';
|
||||||
import 'package:lensai/domain/services/generic_website.dart';
|
import 'package:lensai/domain/services/generic_website.dart';
|
||||||
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'website_title.g.dart';
|
part 'website_title.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
Future<WebPageInfo> pageInfo(PageInfoRef ref, Uri url) {
|
Future<WebPageInfo> pageInfo(Ref ref, Uri url) {
|
||||||
final websiteService = ref.watch(genericWebsiteServiceProvider.notifier);
|
final websiteService = ref.watch(genericWebsiteServiceProvider.notifier);
|
||||||
return websiteService.getInfo(url).then((value) => value.value);
|
return websiteService.getInfo(url).then((value) => value.value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'website_title.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$pageInfoHash() => r'66800fc7e4863750fc9a3717a25e94ee95ec52a3';
|
String _$pageInfoHash() => r'f83bf4b19670abedf0fac5cfe59f190c37544123';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -141,6 +141,8 @@ class PageInfoProvider extends FutureProvider<WebPageInfo> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
mixin PageInfoRef on FutureProviderRef<WebPageInfo> {
|
mixin PageInfoRef on FutureProviderRef<WebPageInfo> {
|
||||||
/// The parameter `url` of this provider.
|
/// The parameter `url` of this provider.
|
||||||
Uri get url;
|
Uri get url;
|
||||||
@@ -154,4 +156,4 @@ class _PageInfoProviderElement extends FutureProviderElement<WebPageInfo>
|
|||||||
Uri get url => (origin as PageInfoProvider).url;
|
Uri get url => (origin as PageInfoProvider).url;
|
||||||
}
|
}
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// 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
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/home/fafre/.pub-cache/hosted/pub.dev/share_plus-10.1.0/
|
/home/fafre/.pub-cache/hosted/pub.dev/share_plus-10.1.1/
|
||||||
@@ -1 +1 @@
|
|||||||
/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.25/
|
/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.26/
|
||||||
@@ -6,7 +6,6 @@ import FlutterMacOS
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import dynamic_color
|
import dynamic_color
|
||||||
import flutter_inappwebview_macos
|
|
||||||
import flutter_secure_storage_macos
|
import flutter_secure_storage_macos
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
@@ -17,7 +16,6 @@ import url_launcher_macos
|
|||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
||||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
|
||||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
|||||||
+39
-103
@@ -30,14 +30,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.11.3"
|
version: "0.11.3"
|
||||||
animations:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: animations
|
|
||||||
sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.11"
|
|
||||||
archive:
|
archive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -231,7 +223,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.4+2"
|
version: "0.3.4+2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: crypto
|
name: crypto
|
||||||
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||||
@@ -298,10 +290,10 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: drift_dev
|
name: drift_dev
|
||||||
sha256: "27bab15e7869b69259663590381180117873b9b273a1ea9ebb21bb73133d1233"
|
sha256: "4592cea370f1dcd8afc67987c28402797d9ddb4aa3ae372cb675497c0741816c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.21.0"
|
version: "2.21.1"
|
||||||
dynamic_color:
|
dynamic_color:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -403,70 +395,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.20.5"
|
version: "0.20.5"
|
||||||
flutter_inappwebview:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_inappwebview
|
|
||||||
sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.1.5"
|
|
||||||
flutter_inappwebview_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_inappwebview_android
|
|
||||||
sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.3"
|
|
||||||
flutter_inappwebview_internal_annotations:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_inappwebview_internal_annotations
|
|
||||||
sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
flutter_inappwebview_ios:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_inappwebview_ios
|
|
||||||
sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.2"
|
|
||||||
flutter_inappwebview_macos:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_inappwebview_macos
|
|
||||||
sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.2"
|
|
||||||
flutter_inappwebview_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_inappwebview_platform_interface
|
|
||||||
sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.0+1"
|
|
||||||
flutter_inappwebview_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_inappwebview_web
|
|
||||||
sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.2"
|
|
||||||
flutter_inappwebview_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_inappwebview_windows
|
|
||||||
sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.6.0"
|
|
||||||
flutter_launcher_icons:
|
flutter_launcher_icons:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@@ -479,10 +407,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: bd9c475d9aae256369edacafc29d1e74c81f78a10cdcdacbbbc9e3c43d009e4a
|
sha256: f0e599ba89c9946c8e051780f0ec99aba4ba15895e0380a7ab68f420046fc44e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.4"
|
version: "0.7.4+1"
|
||||||
flutter_material_design_icons:
|
flutter_material_design_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -518,10 +446,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_riverpod
|
name: flutter_riverpod
|
||||||
sha256: "711d916456563f715bde1e139d7cfdca009f8264befab3ac9f8ded8b6ec26405"
|
sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.3"
|
version: "2.6.1"
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -656,10 +584,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: hooks_riverpod
|
name: hooks_riverpod
|
||||||
sha256: "534ca8af331235f700f3916a74e4579cdfdd708e2fbed342fc8aa969d41a7af0"
|
sha256: "70bba33cfc5670c84b796e6929c54b8bc5be7d0fe15bb28c2560500b9ad06966"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.4"
|
version: "2.6.1"
|
||||||
hotreloader:
|
hotreloader:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1001,42 +929,42 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: riverpod
|
name: riverpod
|
||||||
sha256: c86fedfb45dd1da98ee6493dd9374325cdf494e7d523ebfb0c387eecc5f7b5c9
|
sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.3"
|
version: "2.6.1"
|
||||||
riverpod_analyzer_utils:
|
riverpod_analyzer_utils:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: riverpod_analyzer_utils
|
name: riverpod_analyzer_utils
|
||||||
sha256: ac28d7bc678471ec986b42d88e5a0893513382ff7542c7ac9634463b044ac72c
|
sha256: "0dcb0af32d561f8fa000c6a6d95633c9fb08ea8a8df46e3f9daca59f11218167"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.4"
|
version: "0.5.6"
|
||||||
riverpod_annotation:
|
riverpod_annotation:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: riverpod_annotation
|
name: riverpod_annotation
|
||||||
sha256: "77fdedb87d09344809e8b514ab864d0537b1cb580a93d09bf579b0403aa6203a"
|
sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.3"
|
version: "2.6.1"
|
||||||
riverpod_generator:
|
riverpod_generator:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: riverpod_generator
|
name: riverpod_generator
|
||||||
sha256: "63311e361ffc578d655dfc31b48dfa4ed3bc76fd06f9be845e9bf97c5c11a429"
|
sha256: "851aedac7ad52693d12af3bf6d92b1626d516ed6b764eb61bf19e968b5e0b931"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.3"
|
version: "2.6.1"
|
||||||
riverpod_lint:
|
riverpod_lint:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: riverpod_lint
|
name: riverpod_lint
|
||||||
sha256: a35a92f2c2a4b7a5d95671c96c5432b42c20f26bb3e985e83d0b186471b61a85
|
sha256: "0684c21a9a4582c28c897d55c7b611fa59a351579061b43f8c92c005804e63a8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.13"
|
version: "2.6.1"
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1049,10 +977,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: share_plus
|
name: share_plus
|
||||||
sha256: "334fcdf0ef9c0df0e3b428faebcac9568f35c747d59831474b2fc56e156d244e"
|
sha256: "3af2cda1752e5c24f2fc04b6083b40f013ffe84fb90472f30c6499a9213d5442"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.1.0"
|
version: "10.1.1"
|
||||||
share_plus_platform_interface:
|
share_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1189,26 +1117,26 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqlite3
|
name: sqlite3
|
||||||
sha256: "45f168ae2213201b54e09429ed0c593dc2c88c924a1488d6f9c523a255d567cb"
|
sha256: bb174b3ec2527f9c5f680f73a89af8149dd99782fbb56ea88ad0807c5638f2ed
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.6"
|
version: "2.4.7"
|
||||||
sqlite3_flutter_libs:
|
sqlite3_flutter_libs:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqlite3_flutter_libs
|
name: sqlite3_flutter_libs
|
||||||
sha256: ccd29dd6cf6fb9351fa07cd6f92895809adbf0779c1d986acf5e3d53b3250e33
|
sha256: "7ae52b23366e5295005022e62fa093f64bfe190810223ea0ebf733a4cd140bce"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.25"
|
version: "0.5.26"
|
||||||
sqlparser:
|
sqlparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqlparser
|
name: sqlparser
|
||||||
sha256: c5f63dff8677407ddcddfa4744c176ea6dc44286c47ba9e69e76d8071398034d
|
sha256: d77749237609784e337ec36c979d41f6f38a7b279df98622ae23929c8eb954a4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.39.1"
|
version: "0.39.2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1332,10 +1260,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: "8fc3bae0b68c02c47c5c86fa8bfa74471d42687b0eded01b78de87872db745e2"
|
sha256: "0dea215895a4d254401730ca0ba8204b29109a34a99fb06ae559a2b60988d2de"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.12"
|
version: "6.3.13"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1444,10 +1372,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "2735daae5150e8b1dfeb3eb0544b4d3af0061e9e82cef063adcd583bdae4306a"
|
sha256: e1d0cc62e65dc2561f5071fcbccecf58ff20c344f8f3dc7d4922df372a11df1f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.7.0"
|
version: "5.7.1"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1464,6 +1392,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.5.0"
|
version: "6.5.0"
|
||||||
|
xxh3:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: xxh3
|
||||||
|
sha256: cbeb0e1d10f4c6bf67b650f395eac0cc689425b5efc2ba0cc3d3e069a0beaeec
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
+11
-13
@@ -7,10 +7,8 @@ environment:
|
|||||||
sdk: '>=3.4.1 <4.0.0'
|
sdk: '>=3.4.1 <4.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
animations: ^2.0.11
|
|
||||||
collection: ^1.19.0
|
collection: ^1.19.0
|
||||||
copy_with_extension: ^5.0.4
|
copy_with_extension: ^5.0.4
|
||||||
crypto: ^3.0.6
|
|
||||||
drift: ^2.21.0
|
drift: ^2.21.0
|
||||||
dynamic_color: ^1.7.0
|
dynamic_color: ^1.7.0
|
||||||
exceptions: ^0.6.1
|
exceptions: ^0.6.1
|
||||||
@@ -21,8 +19,7 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_hooks: ^0.20.5
|
flutter_hooks: ^0.20.5
|
||||||
flutter_inappwebview: ^6.1.5
|
flutter_markdown: ^0.7.4+1
|
||||||
flutter_markdown: ^0.7.4
|
|
||||||
flutter_material_design_icons: ^1.1.7447
|
flutter_material_design_icons: ^1.1.7447
|
||||||
flutter_mozilla_components:
|
flutter_mozilla_components:
|
||||||
path: ../packages/flutter_mozilla_components
|
path: ../packages/flutter_mozilla_components
|
||||||
@@ -32,7 +29,7 @@ dependencies:
|
|||||||
go_router: ^14.3.0
|
go_router: ^14.3.0
|
||||||
google_fonts: ^6.2.1
|
google_fonts: ^6.2.1
|
||||||
home_widget: ^0.7.0
|
home_widget: ^0.7.0
|
||||||
hooks_riverpod: ^2.5.4
|
hooks_riverpod: ^2.6.1
|
||||||
html: ^0.15.4
|
html: ^0.15.4
|
||||||
http: ^1.2.2
|
http: ^1.2.2
|
||||||
json_annotation: ^4.9.0
|
json_annotation: ^4.9.0
|
||||||
@@ -46,16 +43,16 @@ dependencies:
|
|||||||
path: ^1.9.0
|
path: ^1.9.0
|
||||||
path_provider: ^2.1.4
|
path_provider: ^2.1.4
|
||||||
reorderable_grid: ^1.0.10
|
reorderable_grid: ^1.0.10
|
||||||
riverpod: ^2.5.3
|
riverpod: ^2.6.1
|
||||||
riverpod_annotation: ^2.5.3
|
riverpod_annotation: ^2.6.1
|
||||||
rxdart: ^0.28.0
|
rxdart: ^0.28.0
|
||||||
share_plus: ^10.1.0
|
share_plus: ^10.1.1
|
||||||
shared_preferences: ^2.3.2
|
shared_preferences: ^2.3.2
|
||||||
skeletonizer: ^1.4.2
|
skeletonizer: ^1.4.2
|
||||||
speech_to_text_google_dialog:
|
speech_to_text_google_dialog:
|
||||||
path: ../../speech_to_text_google_dialog
|
path: ../../speech_to_text_google_dialog
|
||||||
sqlite3: ^2.4.6
|
sqlite3: ^2.4.7
|
||||||
sqlite3_flutter_libs: ^0.5.25
|
sqlite3_flutter_libs: ^0.5.26
|
||||||
synchronized: ^3.3.0+3
|
synchronized: ^3.3.0+3
|
||||||
text_scroll: ^0.2.0
|
text_scroll: ^0.2.0
|
||||||
timeago: ^3.7.0
|
timeago: ^3.7.0
|
||||||
@@ -65,20 +62,21 @@ dependencies:
|
|||||||
url_launcher: ^6.3.1
|
url_launcher: ^6.3.1
|
||||||
uuid: ^4.5.1
|
uuid: ^4.5.1
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
xxh3: ^1.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.13
|
build_runner: ^2.4.13
|
||||||
copy_with_extension_gen: ^5.0.4
|
copy_with_extension_gen: ^5.0.4
|
||||||
custom_lint: ^0.6.8
|
custom_lint: ^0.6.8
|
||||||
dependency_validator: ^4.1.1
|
dependency_validator: ^4.1.1
|
||||||
drift_dev: ^2.21.0
|
drift_dev: ^2.21.1
|
||||||
fast_equatable_lint: ^0.3.0
|
fast_equatable_lint: ^0.3.0
|
||||||
flutter_launcher_icons: ^0.14.1
|
flutter_launcher_icons: ^0.14.1
|
||||||
go_router_builder: ^2.7.1
|
go_router_builder: ^2.7.1
|
||||||
json_serializable: ^6.8.0
|
json_serializable: ^6.8.0
|
||||||
lint: ^2.3.0
|
lint: ^2.3.0
|
||||||
riverpod_generator: ^2.4.3
|
riverpod_generator: ^2.6.1
|
||||||
riverpod_lint: ^2.3.13
|
riverpod_lint: ^2.6.1
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|||||||
@@ -128,3 +128,7 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'androidx.preference:preference-ktx:1.2.1'
|
||||||
|
}
|
||||||
|
|||||||
+176
-122
@@ -8,18 +8,23 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import eu.lensai.flutter_mozilla_components.addons.WebExtensionActionPopupActivity
|
|
||||||
import eu.lensai.flutter_mozilla_components.addons.WebExtensionPromptFeature
|
import eu.lensai.flutter_mozilla_components.addons.WebExtensionPromptFeature
|
||||||
import eu.lensai.flutter_mozilla_components.databinding.FragmentBrowserBinding
|
import eu.lensai.flutter_mozilla_components.databinding.FragmentBrowserBinding
|
||||||
import mozilla.components.browser.state.state.WebExtensionState
|
import eu.lensai.flutter_mozilla_components.ext.getPreferenceKey
|
||||||
|
import eu.lensai.flutter_mozilla_components.services.DownloadService
|
||||||
import mozilla.components.concept.engine.EngineView
|
import mozilla.components.concept.engine.EngineView
|
||||||
import mozilla.components.feature.app.links.AppLinksFeature
|
import mozilla.components.feature.app.links.AppLinksFeature
|
||||||
import mozilla.components.feature.downloads.DownloadsFeature
|
import mozilla.components.feature.downloads.DownloadsFeature
|
||||||
import mozilla.components.feature.downloads.manager.FetchDownloadManager
|
import mozilla.components.feature.downloads.manager.FetchDownloadManager
|
||||||
|
import mozilla.components.feature.downloads.temporary.ShareDownloadFeature
|
||||||
|
import mozilla.components.feature.media.fullscreen.MediaSessionFullscreenFeature
|
||||||
import mozilla.components.feature.privatemode.feature.SecureWindowFeature
|
import mozilla.components.feature.privatemode.feature.SecureWindowFeature
|
||||||
import mozilla.components.feature.prompts.PromptFeature
|
import mozilla.components.feature.prompts.PromptFeature
|
||||||
|
import mozilla.components.feature.session.FullScreenFeature
|
||||||
import mozilla.components.feature.session.SessionFeature
|
import mozilla.components.feature.session.SessionFeature
|
||||||
import mozilla.components.feature.session.SwipeRefreshFeature
|
import mozilla.components.feature.session.SwipeRefreshFeature
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsFeature
|
import mozilla.components.feature.sitepermissions.SitePermissionsFeature
|
||||||
@@ -29,10 +34,9 @@ import mozilla.components.support.base.feature.ActivityResultHandler
|
|||||||
import mozilla.components.support.base.feature.UserInteractionHandler
|
import mozilla.components.support.base.feature.UserInteractionHandler
|
||||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
||||||
import mozilla.components.support.base.log.logger.Logger
|
import mozilla.components.support.base.log.logger.Logger
|
||||||
import mozilla.components.support.ktx.android.arch.lifecycle.addObservers
|
import mozilla.components.support.ktx.android.view.enterImmersiveMode
|
||||||
|
import mozilla.components.support.ktx.android.view.exitImmersiveMode
|
||||||
import mozilla.components.support.locale.ActivityContextWrapper
|
import mozilla.components.support.locale.ActivityContextWrapper
|
||||||
import mozilla.components.support.utils.ext.requestInPlacePermissions
|
|
||||||
import mozilla.components.support.webextensions.WebExtensionPopupObserver
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base fragment extended by [BrowserFragment] and [ExternalAppBrowserFragment].
|
* Base fragment extended by [BrowserFragment] and [ExternalAppBrowserFragment].
|
||||||
@@ -42,153 +46,177 @@ import mozilla.components.support.webextensions.WebExtensionPopupObserver
|
|||||||
@SuppressWarnings("LargeClass")
|
@SuppressWarnings("LargeClass")
|
||||||
abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, ActivityResultHandler {
|
abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, ActivityResultHandler {
|
||||||
private val sessionFeature = ViewBoundFeatureWrapper<SessionFeature>()
|
private val sessionFeature = ViewBoundFeatureWrapper<SessionFeature>()
|
||||||
|
private val shareDownloadsFeature = ViewBoundFeatureWrapper<ShareDownloadFeature>()
|
||||||
private val downloadsFeature = ViewBoundFeatureWrapper<DownloadsFeature>()
|
private val downloadsFeature = ViewBoundFeatureWrapper<DownloadsFeature>()
|
||||||
private val appLinksFeature = ViewBoundFeatureWrapper<AppLinksFeature>()
|
private val appLinksFeature = ViewBoundFeatureWrapper<AppLinksFeature>()
|
||||||
private val promptFeature = ViewBoundFeatureWrapper<PromptFeature>()
|
private val promptFeature = ViewBoundFeatureWrapper<PromptFeature>()
|
||||||
private val webExtensionPromptFeature = ViewBoundFeatureWrapper<WebExtensionPromptFeature>()
|
private val webExtensionPromptFeature = ViewBoundFeatureWrapper<WebExtensionPromptFeature>()
|
||||||
private val sitePermissionsFeature = ViewBoundFeatureWrapper<SitePermissionsFeature>()
|
private val sitePermissionsFeature = ViewBoundFeatureWrapper<SitePermissionsFeature>()
|
||||||
private val swipeRefreshFeature = ViewBoundFeatureWrapper<SwipeRefreshFeature>()
|
private val swipeRefreshFeature = ViewBoundFeatureWrapper<SwipeRefreshFeature>()
|
||||||
|
private val secureWindowFeature = ViewBoundFeatureWrapper<SecureWindowFeature>()
|
||||||
|
private val fullScreenFeature = ViewBoundFeatureWrapper<FullScreenFeature>()
|
||||||
|
private val mediaSessionFullscreenFeature =
|
||||||
|
ViewBoundFeatureWrapper<MediaSessionFullscreenFeature>()
|
||||||
|
|
||||||
|
private val sessionId: String?
|
||||||
protected val sessionId: String?
|
|
||||||
get() = arguments?.getString(SESSION_ID_KEY)
|
get() = arguments?.getString(SESSION_ID_KEY)
|
||||||
|
|
||||||
|
private var _binding: FragmentBrowserBinding? = null
|
||||||
|
val binding get() = _binding!!
|
||||||
|
|
||||||
|
protected val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val backButtonHandler: List<ViewBoundFeatureWrapper<*>> = listOf(
|
||||||
|
fullScreenFeature,
|
||||||
|
sessionFeature,
|
||||||
|
)
|
||||||
|
|
||||||
private val activityResultHandler: List<ViewBoundFeatureWrapper<*>> = listOf(
|
private val activityResultHandler: List<ViewBoundFeatureWrapper<*>> = listOf(
|
||||||
promptFeature,
|
promptFeature,
|
||||||
)
|
)
|
||||||
|
|
||||||
private var _engineView: EngineView? = null
|
|
||||||
private var _binding: FragmentBrowserBinding? = null
|
|
||||||
private var _components: Components? = null
|
|
||||||
|
|
||||||
val binding get() = _binding!!
|
|
||||||
val components get() = _components!!
|
|
||||||
val engineView get() = _engineView!!
|
|
||||||
|
|
||||||
protected abstract fun createEngine(components: Components) : EngineView
|
protected abstract fun createEngine(components: Components) : EngineView
|
||||||
|
|
||||||
|
private lateinit var requestDownloadPermissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||||
|
private lateinit var requestSitePermissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||||
|
private lateinit var requestPromptsPermissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
requestDownloadPermissionsLauncher =
|
||||||
|
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { results ->
|
||||||
|
val permissions = results.keys.toTypedArray()
|
||||||
|
val grantResults =
|
||||||
|
results.values.map {
|
||||||
|
if (it) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED
|
||||||
|
}.toIntArray()
|
||||||
|
downloadsFeature.withFeature {
|
||||||
|
it.onPermissionsResult(permissions, grantResults)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestSitePermissionsLauncher =
|
||||||
|
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { results ->
|
||||||
|
val permissions = results.keys.toTypedArray()
|
||||||
|
val grantResults =
|
||||||
|
results.values.map {
|
||||||
|
if (it) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED
|
||||||
|
}.toIntArray()
|
||||||
|
sitePermissionsFeature.withFeature {
|
||||||
|
it.onPermissionsResult(permissions, grantResults)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestPromptsPermissionsLauncher =
|
||||||
|
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { results ->
|
||||||
|
val permissions = results.keys.toTypedArray()
|
||||||
|
val grantResults =
|
||||||
|
results.values.map {
|
||||||
|
if (it) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED
|
||||||
|
}.toIntArray()
|
||||||
|
promptFeature.withFeature {
|
||||||
|
it.onPermissionsResult(permissions, grantResults)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
_binding = FragmentBrowserBinding.inflate(inflater, container, false)
|
|
||||||
_components = GlobalComponents.components
|
|
||||||
|
|
||||||
_engineView = createEngine(components)
|
|
||||||
_components?.engineView = _engineView
|
|
||||||
|
|
||||||
val engineNativeView = engineView.asView()
|
|
||||||
// Set layout parameters
|
|
||||||
val layoutParams = FrameLayout.LayoutParams(
|
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
engineNativeView.layoutParams = layoutParams
|
|
||||||
|
|
||||||
binding.swipeToRefresh.addView(engineNativeView)
|
|
||||||
|
|
||||||
val originalContext = ActivityContextWrapper.getOriginalContext(requireActivity())
|
|
||||||
engineView.setActivityContext(originalContext)
|
|
||||||
|
|
||||||
sessionFeature.set(
|
sessionFeature.set(
|
||||||
feature = SessionFeature(
|
feature = SessionFeature(
|
||||||
components.store,
|
components.core.store,
|
||||||
components.sessionUseCases.goBack,
|
components.useCases.sessionUseCases.goBack,
|
||||||
components.sessionUseCases.goForward,
|
components.useCases.sessionUseCases.goForward,
|
||||||
engineView,
|
components.engineView!!,
|
||||||
sessionId,
|
sessionId,
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root,
|
view = view,
|
||||||
)
|
)
|
||||||
|
|
||||||
swipeRefreshFeature.set(
|
swipeRefreshFeature.set(
|
||||||
feature = SwipeRefreshFeature(
|
feature = SwipeRefreshFeature(
|
||||||
components.store,
|
components.core.store,
|
||||||
components.sessionUseCases.reload,
|
components.useCases.sessionUseCases.reload,
|
||||||
binding.swipeToRefresh,
|
binding.swipeToRefresh,
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root,
|
view = view,
|
||||||
|
)
|
||||||
|
|
||||||
|
shareDownloadsFeature.set(
|
||||||
|
ShareDownloadFeature(
|
||||||
|
context = requireContext().applicationContext,
|
||||||
|
httpClient = components.core.client,
|
||||||
|
store = components.core.store,
|
||||||
|
tabId = sessionId,
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view,
|
||||||
)
|
)
|
||||||
|
|
||||||
downloadsFeature.set(
|
downloadsFeature.set(
|
||||||
feature = DownloadsFeature(
|
feature = DownloadsFeature(
|
||||||
requireContext().applicationContext,
|
requireContext().applicationContext,
|
||||||
store = components.store,
|
store = components.core.store,
|
||||||
useCases = components.downloadsUseCases,
|
useCases = components.useCases.downloadsUseCases,
|
||||||
fragmentManager = childFragmentManager,
|
fragmentManager = childFragmentManager,
|
||||||
onDownloadStopped = { download, id, status ->
|
onDownloadStopped = { download, id, status ->
|
||||||
Logger.debug("Download done. ID#$id $download with status $status")
|
Logger.debug("Download done. ID#$id $download with status $status")
|
||||||
},
|
},
|
||||||
downloadManager = FetchDownloadManager(
|
downloadManager = FetchDownloadManager(
|
||||||
requireContext().applicationContext,
|
requireContext().applicationContext,
|
||||||
components.store,
|
components.core.store,
|
||||||
DownloadService::class,
|
DownloadService::class,
|
||||||
notificationsDelegate = components.notificationsDelegate,
|
notificationsDelegate = components.notificationsDelegate,
|
||||||
),
|
),
|
||||||
tabId = sessionId,
|
tabId = sessionId,
|
||||||
onNeedToRequestPermissions = { permissions ->
|
onNeedToRequestPermissions = { permissions ->
|
||||||
requestInPlacePermissions(REQUEST_KEY_DOWNLOAD_PERMISSIONS, permissions) { result ->
|
requestDownloadPermissionsLauncher.launch(permissions)
|
||||||
downloadsFeature.get()?.onPermissionsResult(
|
|
||||||
result.keys.toTypedArray(),
|
|
||||||
result.values.map {
|
|
||||||
when (it) {
|
|
||||||
true -> PackageManager.PERMISSION_GRANTED
|
|
||||||
false -> PackageManager.PERMISSION_DENIED
|
|
||||||
}
|
|
||||||
}.toIntArray(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root,
|
view = view,
|
||||||
)
|
)
|
||||||
|
|
||||||
appLinksFeature.set(
|
appLinksFeature.set(
|
||||||
feature = AppLinksFeature(
|
feature = AppLinksFeature(
|
||||||
context = requireContext(),
|
context = requireContext(),
|
||||||
store = components.store,
|
store = components.core.store,
|
||||||
sessionId = sessionId,
|
sessionId = sessionId,
|
||||||
fragmentManager = parentFragmentManager,
|
fragmentManager = parentFragmentManager,
|
||||||
launchInApp = { components.preferences.getBoolean(DefaultComponents.PREF_LAUNCH_EXTERNAL_APP, false) },
|
launchInApp = { components.core.prefs.getBoolean(context?.getPreferenceKey(R.string.pref_key_launch_external_app), false) },
|
||||||
loadUrlUseCase = components.sessionUseCases.loadUrl,
|
loadUrlUseCase = components.useCases.sessionUseCases.loadUrl,
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root,
|
view = view,
|
||||||
)
|
)
|
||||||
|
|
||||||
promptFeature.set(
|
promptFeature.set(
|
||||||
feature = PromptFeature(
|
feature = PromptFeature(
|
||||||
fragment = this,
|
fragment = this,
|
||||||
store = components.store,
|
store = components.core.store,
|
||||||
customTabId = sessionId,
|
customTabId = sessionId,
|
||||||
tabsUseCases = components.tabsUseCases,
|
tabsUseCases = components.useCases.tabsUseCases,
|
||||||
fragmentManager = parentFragmentManager,
|
fragmentManager = parentFragmentManager,
|
||||||
fileUploadsDirCleaner = components.fileUploadsDirCleaner,
|
fileUploadsDirCleaner = components.core.fileUploadsDirCleaner,
|
||||||
onNeedToRequestPermissions = { permissions ->
|
onNeedToRequestPermissions = { permissions ->
|
||||||
requestInPlacePermissions(REQUEST_KEY_PROMPT_PERMISSIONS, permissions) { result ->
|
requestPromptsPermissionsLauncher.launch(permissions)
|
||||||
promptFeature.get()?.onPermissionsResult(
|
|
||||||
result.keys.toTypedArray(),
|
|
||||||
result.values.map {
|
|
||||||
when (it) {
|
|
||||||
true -> PackageManager.PERMISSION_GRANTED
|
|
||||||
false -> PackageManager.PERMISSION_DENIED
|
|
||||||
}
|
|
||||||
}.toIntArray(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root,
|
view = view,
|
||||||
)
|
)
|
||||||
|
|
||||||
sitePermissionsFeature.set(
|
sitePermissionsFeature.set(
|
||||||
feature = SitePermissionsFeature(
|
feature = SitePermissionsFeature(
|
||||||
context = requireContext(),
|
context = requireContext(),
|
||||||
sessionId = sessionId,
|
sessionId = sessionId,
|
||||||
storage = components.permissionStorage,
|
storage = components.core.geckoSitePermissionsStorage,
|
||||||
fragmentManager = parentFragmentManager,
|
fragmentManager = parentFragmentManager,
|
||||||
sitePermissionsRules = SitePermissionsRules(
|
sitePermissionsRules = SitePermissionsRules(
|
||||||
autoplayAudible = AutoplayAction.BLOCKED,
|
autoplayAudible = AutoplayAction.BLOCKED,
|
||||||
@@ -202,63 +230,92 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
|||||||
crossOriginStorageAccess = SitePermissionsRules.Action.ASK_TO_ALLOW,
|
crossOriginStorageAccess = SitePermissionsRules.Action.ASK_TO_ALLOW,
|
||||||
),
|
),
|
||||||
onNeedToRequestPermissions = { permissions ->
|
onNeedToRequestPermissions = { permissions ->
|
||||||
requestInPlacePermissions(REQUEST_KEY_SITE_PERMISSIONS, permissions) { result ->
|
requestSitePermissionsLauncher.launch(permissions)
|
||||||
sitePermissionsFeature.get()?.onPermissionsResult(
|
|
||||||
result.keys.toTypedArray(),
|
|
||||||
result.values.map {
|
|
||||||
when (it) {
|
|
||||||
true -> PackageManager.PERMISSION_GRANTED
|
|
||||||
false -> PackageManager.PERMISSION_DENIED
|
|
||||||
}
|
|
||||||
}.toIntArray(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onShouldShowRequestPermissionRationale = { shouldShowRequestPermissionRationale(it) },
|
onShouldShowRequestPermissionRationale = { shouldShowRequestPermissionRationale(it) },
|
||||||
store = components.store,
|
store = components.core.store,
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view,
|
||||||
|
)
|
||||||
|
|
||||||
|
webExtensionPromptFeature.set(
|
||||||
|
feature = WebExtensionPromptFeature(
|
||||||
|
store = components.core.store,
|
||||||
|
context = requireContext(),
|
||||||
|
fragmentManager = parentFragmentManager,
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
fullScreenFeature.set(
|
||||||
|
feature = FullScreenFeature(
|
||||||
|
components.core.store,
|
||||||
|
components.useCases.sessionUseCases,
|
||||||
|
sessionId,
|
||||||
|
) { inFullScreen ->
|
||||||
|
if (inFullScreen) {
|
||||||
|
activity?.enterImmersiveMode()
|
||||||
|
} else {
|
||||||
|
activity?.exitImmersiveMode()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
owner = this,
|
||||||
|
view = binding.root,
|
||||||
|
)
|
||||||
|
|
||||||
|
mediaSessionFullscreenFeature.set(
|
||||||
|
feature = MediaSessionFullscreenFeature(
|
||||||
|
requireActivity(),
|
||||||
|
components.core.store,
|
||||||
|
sessionId,
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root,
|
view = binding.root,
|
||||||
)
|
)
|
||||||
|
|
||||||
webExtensionPromptFeature.set(
|
secureWindowFeature.set(
|
||||||
feature = WebExtensionPromptFeature(
|
feature = SecureWindowFeature(
|
||||||
store = components.store,
|
window = requireActivity().window,
|
||||||
context = requireContext(),
|
store = components.core.store,
|
||||||
fragmentManager = parentFragmentManager,
|
customTabId = sessionId,
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root
|
view = binding.root,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
@Suppress("LongMethod")
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
_binding = FragmentBrowserBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
// Set layout parameters
|
||||||
|
val layoutParams = FrameLayout.LayoutParams(
|
||||||
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
FrameLayout.LayoutParams.MATCH_PARENT
|
||||||
)
|
)
|
||||||
|
|
||||||
val secureWindowFeature = SecureWindowFeature(
|
val originalContext = ActivityContextWrapper.getOriginalContext(requireActivity())
|
||||||
window = requireActivity().window,
|
|
||||||
store = components.store,
|
|
||||||
customTabId = sessionId,
|
|
||||||
)
|
|
||||||
|
|
||||||
val webExtensionPopupObserver = WebExtensionPopupObserver(components.store, ::openPopup)
|
val engineView = createEngine(components)
|
||||||
|
components.engineView = engineView
|
||||||
|
|
||||||
// Observe the lifecycle for supported features
|
val engineNativeView = engineView.asView()
|
||||||
lifecycle.addObservers(
|
engineNativeView.layoutParams = layoutParams
|
||||||
secureWindowFeature,
|
|
||||||
webExtensionPopupObserver,
|
engineView.setActivityContext(originalContext)
|
||||||
)
|
|
||||||
|
binding.swipeToRefresh.addView(engineNativeView)
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openPopup(webExtensionState: WebExtensionState) {
|
|
||||||
val intent = Intent(requireContext().applicationContext, WebExtensionActionPopupActivity::class.java)
|
|
||||||
intent.putExtra("web_extension_id", webExtensionState.id)
|
|
||||||
intent.putExtra("web_extension_name", webExtensionState.name)
|
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onBackPressed(): Boolean =
|
override fun onBackPressed(): Boolean {
|
||||||
listOf(sessionFeature).any { it.onBackPressed() }
|
return backButtonHandler.any { it.onBackPressed() }
|
||||||
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onActivityResult(requestCode: Int, data: Intent?, resultCode: Int): Boolean {
|
override fun onActivityResult(requestCode: Int, data: Intent?, resultCode: Int): Boolean {
|
||||||
@@ -268,10 +325,6 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
|||||||
companion object {
|
companion object {
|
||||||
private const val SESSION_ID_KEY = "session_id"
|
private const val SESSION_ID_KEY = "session_id"
|
||||||
|
|
||||||
private const val REQUEST_KEY_DOWNLOAD_PERMISSIONS = "downloadFeature"
|
|
||||||
private const val REQUEST_KEY_PROMPT_PERMISSIONS = "promptFeature"
|
|
||||||
private const val REQUEST_KEY_SITE_PERMISSIONS = "sitePermissionsFeature"
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
protected fun Bundle.putSessionId(sessionId: String?) {
|
protected fun Bundle.putSessionId(sessionId: String?) {
|
||||||
putString(SESSION_ID_KEY, sessionId)
|
putString(SESSION_ID_KEY, sessionId)
|
||||||
@@ -279,7 +332,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
|||||||
}
|
}
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
engineView.setActivityContext(null)
|
|
||||||
|
components.engineView?.setActivityContext(null)
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-57
@@ -2,107 +2,89 @@ package eu.lensai.flutter_mozilla_components
|
|||||||
|
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import eu.lensai.flutter_mozilla_components.addons.WebExtensionActionPopupActivity
|
||||||
import eu.lensai.flutter_mozilla_components.feature.DefaultSelectionActionDelegate
|
import eu.lensai.flutter_mozilla_components.feature.WebExtensionToolbarFeature
|
||||||
import eu.lensai.flutter_mozilla_components.integration.ReaderViewIntegration
|
import eu.lensai.flutter_mozilla_components.integration.ReaderViewIntegration
|
||||||
|
import mozilla.components.browser.state.state.WebExtensionState
|
||||||
import mozilla.components.browser.thumbnails.BrowserThumbnails
|
import mozilla.components.browser.thumbnails.BrowserThumbnails
|
||||||
import mozilla.components.concept.engine.EngineView
|
import mozilla.components.concept.engine.EngineView
|
||||||
import mozilla.components.feature.media.fullscreen.MediaSessionFullscreenFeature
|
|
||||||
import mozilla.components.feature.session.FullScreenFeature
|
|
||||||
import mozilla.components.feature.tabs.WindowFeature
|
import mozilla.components.feature.tabs.WindowFeature
|
||||||
import mozilla.components.support.base.feature.UserInteractionHandler
|
import mozilla.components.support.base.feature.UserInteractionHandler
|
||||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
||||||
import mozilla.components.support.ktx.android.view.enterImmersiveMode
|
import mozilla.components.support.webextensions.WebExtensionPopupObserver
|
||||||
import mozilla.components.support.ktx.android.view.exitImmersiveMode
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fragment used for browsing the web within the main app.
|
* Fragment used for browsing the web within the main app.
|
||||||
*/
|
*/
|
||||||
class BrowserFragment(private val context: Context) : BaseBrowserFragment(), UserInteractionHandler {
|
class BrowserFragment(private val context: Context) : BaseBrowserFragment(), UserInteractionHandler {
|
||||||
|
private val windowFeature = ViewBoundFeatureWrapper<WindowFeature>()
|
||||||
private val thumbnailsFeature = ViewBoundFeatureWrapper<BrowserThumbnails>()
|
private val thumbnailsFeature = ViewBoundFeatureWrapper<BrowserThumbnails>()
|
||||||
private val readerViewFeature = ViewBoundFeatureWrapper<ReaderViewIntegration>()
|
private val readerViewFeature = ViewBoundFeatureWrapper<ReaderViewIntegration>()
|
||||||
private val fullScreenFeature = ViewBoundFeatureWrapper<FullScreenFeature>()
|
private val webExtensionPopupObserver = ViewBoundFeatureWrapper<WebExtensionPopupObserver>()
|
||||||
private val mediaSessionFullscreenFeature =
|
private val webExtToolbarFeature = ViewBoundFeatureWrapper<WebExtensionToolbarFeature>()
|
||||||
ViewBoundFeatureWrapper<MediaSessionFullscreenFeature>()
|
|
||||||
|
|
||||||
override fun createEngine(components: Components): EngineView {
|
override fun createEngine(components: Components): EngineView {
|
||||||
return components.engine.createView(context).apply {
|
return components.core.engine.createView(context).apply {
|
||||||
selectionActionDelegate = components.selectionAction
|
selectionActionDelegate = components.selectionAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
override fun onCreateView(
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
inflater: LayoutInflater,
|
super.onViewCreated(view, savedInstanceState)
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?,
|
|
||||||
): View {
|
|
||||||
super.onCreateView(inflater, container, savedInstanceState)
|
|
||||||
|
|
||||||
val binding = super.binding
|
|
||||||
|
|
||||||
readerViewFeature.set(
|
readerViewFeature.set(
|
||||||
feature = ReaderViewIntegration(
|
feature = ReaderViewIntegration(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
components.engine,
|
components.core.engine,
|
||||||
components.store,
|
components.core.store,
|
||||||
binding.readerViewBar,
|
binding.readerViewBar,
|
||||||
components.readerViewEvents,
|
components.events.readerViewEvents,
|
||||||
components.readerViewController,
|
components.readerViewController,
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root,
|
view = view,
|
||||||
)
|
)
|
||||||
|
|
||||||
fullScreenFeature.set(
|
windowFeature.set(
|
||||||
feature = FullScreenFeature(
|
feature = WindowFeature(components.core.store, components.useCases.tabsUseCases),
|
||||||
components.store,
|
|
||||||
components.sessionUseCases,
|
|
||||||
sessionId,
|
|
||||||
) { inFullScreen ->
|
|
||||||
if (inFullScreen) {
|
|
||||||
activity?.enterImmersiveMode()
|
|
||||||
} else {
|
|
||||||
activity?.exitImmersiveMode()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root,
|
view = view,
|
||||||
)
|
|
||||||
|
|
||||||
mediaSessionFullscreenFeature.set(
|
|
||||||
feature = MediaSessionFullscreenFeature(
|
|
||||||
requireActivity(),
|
|
||||||
components.store,
|
|
||||||
sessionId,
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = binding.root,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
thumbnailsFeature.set(
|
thumbnailsFeature.set(
|
||||||
feature = BrowserThumbnails(requireContext(), engineView, components.store),
|
feature = BrowserThumbnails(requireContext(), components.engineView!!, components.core.store),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = binding.root,
|
view = view,
|
||||||
)
|
)
|
||||||
|
|
||||||
val windowFeature = WindowFeature(components.store, components.tabsUseCases)
|
webExtensionPopupObserver.set(
|
||||||
lifecycle.addObserver(windowFeature)
|
feature = WebExtensionPopupObserver(components.core.store, ::openPopup),
|
||||||
|
owner = this,
|
||||||
|
view = view,
|
||||||
|
)
|
||||||
|
|
||||||
return binding.root
|
webExtToolbarFeature.set(
|
||||||
|
feature = components.features.webExtensionToolbarFeature,
|
||||||
|
owner = this,
|
||||||
|
view = view,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun openPopup(webExtensionState: WebExtensionState) {
|
||||||
override fun onBackPressed(): Boolean {
|
val intent = Intent(requireContext().applicationContext, WebExtensionActionPopupActivity::class.java)
|
||||||
return when {
|
intent.putExtra("web_extension_id", webExtensionState.id)
|
||||||
fullScreenFeature.onBackPressed() -> true
|
intent.putExtra("web_extension_name", webExtensionState.name)
|
||||||
else -> super.onBackPressed()
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
}
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed(): Boolean =
|
||||||
|
readerViewFeature.onBackPressed() || super.onBackPressed()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun create(context: Context, sessionId: String? = null) = BrowserFragment(context).apply {
|
fun create(context: Context, sessionId: String? = null) = BrowserFragment(context).apply {
|
||||||
arguments = Bundle().apply {
|
arguments = Bundle().apply {
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package eu.lensai.flutter_mozilla_components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import eu.lensai.flutter_mozilla_components.components.Core
|
||||||
|
import eu.lensai.flutter_mozilla_components.components.Events
|
||||||
|
import eu.lensai.flutter_mozilla_components.components.Features
|
||||||
|
import eu.lensai.flutter_mozilla_components.components.Services
|
||||||
|
import eu.lensai.flutter_mozilla_components.components.UseCases
|
||||||
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents
|
||||||
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
||||||
|
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
|
||||||
|
import mozilla.components.concept.engine.EngineView
|
||||||
|
import mozilla.components.concept.engine.selection.SelectionActionDelegate
|
||||||
|
import mozilla.components.support.base.android.NotificationsDelegate
|
||||||
|
|
||||||
|
class Components(private val context: Context,
|
||||||
|
val flutterEvents: GeckoStateEvents,
|
||||||
|
val readerViewController: ReaderViewController,
|
||||||
|
val selectionAction: SelectionActionDelegate,
|
||||||
|
val addonEvents: GeckoAddonEvents
|
||||||
|
) {
|
||||||
|
val core by lazy { Core(context, this, flutterEvents) }
|
||||||
|
val events by lazy { Events(flutterEvents) }
|
||||||
|
val useCases by lazy { UseCases(context, core.engine, core.store) }
|
||||||
|
val services by lazy { Services(context, useCases.tabsUseCases) }
|
||||||
|
val features by lazy { Features(core.store, addonEvents) }
|
||||||
|
|
||||||
|
var engineView: EngineView? = null
|
||||||
|
var engineReportedInitialized = false
|
||||||
|
|
||||||
|
private val notificationManagerCompat = NotificationManagerCompat.from(context)
|
||||||
|
val notificationsDelegate: NotificationsDelegate by lazy {
|
||||||
|
NotificationsDelegate(
|
||||||
|
notificationManagerCompat,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+415
-415
@@ -1,415 +1,415 @@
|
|||||||
package eu.lensai.flutter_mozilla_components
|
//package eu.lensai.flutter_mozilla_components
|
||||||
|
//
|
||||||
|
//
|
||||||
import android.annotation.SuppressLint
|
//import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
//import android.content.Context
|
||||||
import android.content.SharedPreferences
|
//import android.content.SharedPreferences
|
||||||
import androidx.core.app.NotificationManagerCompat
|
//import androidx.core.app.NotificationManagerCompat
|
||||||
import eu.lensai.flutter_mozilla_components.api.ReaderViewEventsImpl
|
//import eu.lensai.flutter_mozilla_components.api.ReaderViewEventsImpl
|
||||||
import eu.lensai.flutter_mozilla_components.ext.toWebPBytes
|
//import eu.lensai.flutter_mozilla_components.ext.toWebPBytes
|
||||||
import eu.lensai.flutter_mozilla_components.middleware.FlutterEventMiddleware
|
//import eu.lensai.flutter_mozilla_components.middleware.FlutterEventMiddleware
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.FindResultState
|
//import eu.lensai.flutter_mozilla_components.pigeons.FindResultState
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
//import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.HistoryItem
|
//import eu.lensai.flutter_mozilla_components.pigeons.HistoryItem
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.HistoryState
|
//import eu.lensai.flutter_mozilla_components.pigeons.HistoryState
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
|
//import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.ReaderableState
|
//import eu.lensai.flutter_mozilla_components.pigeons.ReaderableState
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.SecurityInfoState
|
//import eu.lensai.flutter_mozilla_components.pigeons.SecurityInfoState
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.TabContentState
|
//import eu.lensai.flutter_mozilla_components.pigeons.TabContentState
|
||||||
import kotlinx.coroutines.FlowPreview
|
//import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.flow.debounce
|
//import kotlinx.coroutines.flow.debounce
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
//import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.map
|
//import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapNotNull
|
//import kotlinx.coroutines.flow.mapNotNull
|
||||||
import mozilla.components.browser.engine.gecko.GeckoEngine
|
//import mozilla.components.browser.engine.gecko.GeckoEngine
|
||||||
import mozilla.components.browser.icons.BrowserIcons
|
//import mozilla.components.browser.icons.BrowserIcons
|
||||||
import mozilla.components.browser.session.storage.SessionStorage
|
//import mozilla.components.browser.session.storage.SessionStorage
|
||||||
import mozilla.components.browser.state.engine.EngineMiddleware
|
//import mozilla.components.browser.state.engine.EngineMiddleware
|
||||||
import mozilla.components.browser.state.engine.middleware.SessionPrioritizationMiddleware
|
//import mozilla.components.browser.state.engine.middleware.SessionPrioritizationMiddleware
|
||||||
import mozilla.components.browser.state.store.BrowserStore
|
//import mozilla.components.browser.state.store.BrowserStore
|
||||||
import mozilla.components.browser.thumbnails.ThumbnailsMiddleware
|
//import mozilla.components.browser.thumbnails.ThumbnailsMiddleware
|
||||||
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
|
//import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
|
||||||
import mozilla.components.concept.base.crash.Breadcrumb
|
//import mozilla.components.concept.base.crash.Breadcrumb
|
||||||
import mozilla.components.concept.engine.DefaultSettings
|
//import mozilla.components.concept.engine.DefaultSettings
|
||||||
import mozilla.components.concept.engine.Engine
|
//import mozilla.components.concept.engine.Engine
|
||||||
import mozilla.components.concept.engine.EngineView
|
//import mozilla.components.concept.engine.EngineView
|
||||||
import mozilla.components.concept.engine.mediaquery.PreferredColorScheme
|
//import mozilla.components.concept.engine.mediaquery.PreferredColorScheme
|
||||||
import mozilla.components.concept.engine.selection.SelectionActionDelegate
|
//import mozilla.components.concept.engine.selection.SelectionActionDelegate
|
||||||
import mozilla.components.concept.fetch.Client
|
//import mozilla.components.concept.fetch.Client
|
||||||
import mozilla.components.feature.addons.AddonManager
|
//import mozilla.components.feature.addons.AddonManager
|
||||||
import mozilla.components.feature.addons.amo.AMOAddonsProvider
|
//import mozilla.components.feature.addons.amo.AMOAddonsProvider
|
||||||
import mozilla.components.feature.addons.logger
|
//import mozilla.components.feature.addons.logger
|
||||||
import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker
|
//import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker
|
||||||
import mozilla.components.feature.addons.update.DefaultAddonUpdater
|
//import mozilla.components.feature.addons.update.DefaultAddonUpdater
|
||||||
import mozilla.components.feature.app.links.AppLinksInterceptor
|
//import mozilla.components.feature.app.links.AppLinksInterceptor
|
||||||
import mozilla.components.feature.app.links.AppLinksUseCases
|
//import mozilla.components.feature.app.links.AppLinksUseCases
|
||||||
import mozilla.components.feature.downloads.DownloadMiddleware
|
//import mozilla.components.feature.downloads.DownloadMiddleware
|
||||||
import mozilla.components.feature.downloads.DownloadsUseCases
|
//import mozilla.components.feature.downloads.DownloadsUseCases
|
||||||
import mozilla.components.feature.media.MediaSessionFeature
|
//import mozilla.components.feature.media.MediaSessionFeature
|
||||||
import mozilla.components.feature.media.middleware.RecordingDevicesMiddleware
|
//import mozilla.components.feature.media.middleware.RecordingDevicesMiddleware
|
||||||
import mozilla.components.feature.prompts.PromptMiddleware
|
//import mozilla.components.feature.prompts.PromptMiddleware
|
||||||
import mozilla.components.feature.prompts.file.FileUploadsDirCleaner
|
//import mozilla.components.feature.prompts.file.FileUploadsDirCleaner
|
||||||
import mozilla.components.feature.readerview.ReaderViewMiddleware
|
//import mozilla.components.feature.readerview.ReaderViewMiddleware
|
||||||
import mozilla.components.feature.session.SessionUseCases
|
//import mozilla.components.feature.session.SessionUseCases
|
||||||
import mozilla.components.feature.tabs.TabsUseCases
|
//import mozilla.components.feature.tabs.TabsUseCases
|
||||||
import mozilla.components.feature.session.middleware.LastAccessMiddleware
|
//import mozilla.components.feature.session.middleware.LastAccessMiddleware
|
||||||
import mozilla.components.feature.session.middleware.undo.UndoMiddleware
|
//import mozilla.components.feature.session.middleware.undo.UndoMiddleware
|
||||||
import mozilla.components.feature.sitepermissions.OnDiskSitePermissionsStorage
|
//import mozilla.components.feature.sitepermissions.OnDiskSitePermissionsStorage
|
||||||
import mozilla.components.feature.webnotifications.WebNotificationFeature
|
//import mozilla.components.feature.webnotifications.WebNotificationFeature
|
||||||
import mozilla.components.lib.crash.Crash
|
//import mozilla.components.lib.crash.Crash
|
||||||
import mozilla.components.lib.crash.CrashReporter
|
//import mozilla.components.lib.crash.CrashReporter
|
||||||
import mozilla.components.lib.crash.service.CrashReporterService
|
//import mozilla.components.lib.crash.service.CrashReporterService
|
||||||
import mozilla.components.lib.dataprotect.SecureAbove22Preferences
|
//import mozilla.components.lib.dataprotect.SecureAbove22Preferences
|
||||||
import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient
|
//import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient
|
||||||
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
|
//import mozilla.components.lib.publicsuffixlist.PublicSuffixList
|
||||||
import mozilla.components.lib.state.ext.flowScoped
|
//import mozilla.components.lib.state.ext.flowScoped
|
||||||
import mozilla.components.service.digitalassetlinks.local.StatementApi
|
//import mozilla.components.service.digitalassetlinks.local.StatementApi
|
||||||
import mozilla.components.service.digitalassetlinks.local.StatementRelationChecker
|
//import mozilla.components.service.digitalassetlinks.local.StatementRelationChecker
|
||||||
import mozilla.components.support.base.android.NotificationsDelegate
|
//import mozilla.components.support.base.android.NotificationsDelegate
|
||||||
import mozilla.components.support.base.worker.Frequency
|
//import mozilla.components.support.base.worker.Frequency
|
||||||
import mozilla.components.support.ktx.kotlinx.coroutines.flow.filterChanged
|
//import mozilla.components.support.ktx.kotlinx.coroutines.flow.filterChanged
|
||||||
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged
|
//import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged
|
||||||
import java.util.concurrent.TimeUnit
|
//import java.util.concurrent.TimeUnit
|
||||||
|
//
|
||||||
private const val DAY_IN_MINUTES = 24 * 60L
|
//private const val DAY_IN_MINUTES = 24 * 60L
|
||||||
|
//
|
||||||
@SuppressLint("NewApi")
|
//@SuppressLint("NewApi")
|
||||||
@Suppress("LargeClass")
|
//@Suppress("LargeClass")
|
||||||
open class DefaultComponents(
|
//open class DefaultComponents(
|
||||||
private val applicationContext: Context,
|
// private val applicationContext: Context,
|
||||||
val flutterEvents: GeckoStateEvents,
|
// val flutterEvents: GeckoStateEvents,
|
||||||
val readerViewController: ReaderViewController,
|
// val readerViewController: ReaderViewController,
|
||||||
val selectionAction: SelectionActionDelegate,
|
// val selectionAction: SelectionActionDelegate,
|
||||||
) {
|
//) {
|
||||||
companion object {
|
// companion object {
|
||||||
const val SAMPLE_BROWSER_PREFERENCES = "sample_browser_preferences"
|
// const val SAMPLE_BROWSER_PREFERENCES = "sample_browser_preferences"
|
||||||
const val PREF_LAUNCH_EXTERNAL_APP = "sample_browser_launch_external_app"
|
// const val PREF_LAUNCH_EXTERNAL_APP = "sample_browser_launch_external_app"
|
||||||
const val PREF_GLOBAL_PRIVACY_CONTROL = "sample_browser_global_privacy_control"
|
// const val PREF_GLOBAL_PRIVACY_CONTROL = "sample_browser_global_privacy_control"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
var engineView: EngineView? = null
|
// var engineView: EngineView? = null
|
||||||
var engineReportedInitialized = false
|
// var engineReportedInitialized = false
|
||||||
|
//
|
||||||
val preferences: SharedPreferences =
|
// val preferences: SharedPreferences =
|
||||||
applicationContext.getSharedPreferences(SAMPLE_BROWSER_PREFERENCES, Context.MODE_PRIVATE)
|
// applicationContext.getSharedPreferences(SAMPLE_BROWSER_PREFERENCES, Context.MODE_PRIVATE)
|
||||||
|
//
|
||||||
private val securePreferences by lazy { SecureAbove22Preferences(applicationContext, "key_store") }
|
// private val securePreferences by lazy { SecureAbove22Preferences(applicationContext, "key_store") }
|
||||||
|
//
|
||||||
val publicSuffixList by lazy { PublicSuffixList(applicationContext) }
|
// val publicSuffixList by lazy { PublicSuffixList(applicationContext) }
|
||||||
|
//
|
||||||
// Engine Settings
|
// // Engine Settings
|
||||||
val engineSettings by lazy {
|
// val engineSettings by lazy {
|
||||||
DefaultSettings().apply {
|
// DefaultSettings().apply {
|
||||||
//historyTrackingDelegate = HistoryDelegate(lazyHistoryStorage)
|
// //historyTrackingDelegate = HistoryDelegate(lazyHistoryStorage)
|
||||||
requestInterceptor = AppRequestInterceptor(applicationContext)
|
// requestInterceptor = AppRequestInterceptor(applicationContext)
|
||||||
remoteDebuggingEnabled = true
|
// remoteDebuggingEnabled = true
|
||||||
supportMultipleWindows = true
|
// supportMultipleWindows = true
|
||||||
preferredColorScheme = PreferredColorScheme.Dark
|
// preferredColorScheme = PreferredColorScheme.Dark
|
||||||
httpsOnlyMode = Engine.HttpsOnlyMode.ENABLED
|
// httpsOnlyMode = Engine.HttpsOnlyMode.ENABLED
|
||||||
globalPrivacyControlEnabled = preferences.getBoolean(
|
// globalPrivacyControlEnabled = preferences.getBoolean(
|
||||||
PREF_GLOBAL_PRIVACY_CONTROL,
|
// PREF_GLOBAL_PRIVACY_CONTROL,
|
||||||
false,
|
// false,
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private val notificationManagerCompat = NotificationManagerCompat.from(applicationContext)
|
// private val notificationManagerCompat = NotificationManagerCompat.from(applicationContext)
|
||||||
|
//
|
||||||
val notificationsDelegate: NotificationsDelegate by lazy {
|
// val notificationsDelegate: NotificationsDelegate by lazy {
|
||||||
NotificationsDelegate(
|
// NotificationsDelegate(
|
||||||
notificationManagerCompat,
|
// notificationManagerCompat,
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
val addonUpdater =
|
// val addonUpdater =
|
||||||
DefaultAddonUpdater(applicationContext, Frequency(1, TimeUnit.DAYS), notificationsDelegate)
|
// DefaultAddonUpdater(applicationContext, Frequency(1, TimeUnit.DAYS), notificationsDelegate)
|
||||||
|
//
|
||||||
// Engine
|
// // Engine
|
||||||
open val engine: Engine by lazy {
|
// open val engine: Engine by lazy {
|
||||||
GeckoEngine(applicationContext, engineSettings)
|
// GeckoEngine(applicationContext, engineSettings)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
val icons by lazy { BrowserIcons(applicationContext, client) }
|
// val icons by lazy { BrowserIcons(applicationContext, client) }
|
||||||
|
//
|
||||||
open val client: Client by lazy { HttpURLConnectionClient() }
|
// open val client: Client by lazy { HttpURLConnectionClient() }
|
||||||
|
//
|
||||||
// Storage
|
// // Storage
|
||||||
//private val lazyHistoryStorage = lazy { PlacesHistoryStorage(applicationContext) }
|
// //private val lazyHistoryStorage = lazy { PlacesHistoryStorage(applicationContext) }
|
||||||
//val historyStorage by lazy { lazyHistoryStorage.value }
|
// //val historyStorage by lazy { lazyHistoryStorage.value }
|
||||||
|
//
|
||||||
val sessionStorage by lazy { SessionStorage(applicationContext, engine) }
|
// val sessionStorage by lazy { SessionStorage(applicationContext, engine) }
|
||||||
|
//
|
||||||
val permissionStorage by lazy { OnDiskSitePermissionsStorage(applicationContext) }
|
// val permissionStorage by lazy { OnDiskSitePermissionsStorage(applicationContext) }
|
||||||
|
//
|
||||||
val thumbnailStorage by lazy { ThumbnailStorage(applicationContext) }
|
// val thumbnailStorage by lazy { ThumbnailStorage(applicationContext) }
|
||||||
|
//
|
||||||
val fileUploadsDirCleaner: FileUploadsDirCleaner by lazy {
|
// val fileUploadsDirCleaner: FileUploadsDirCleaner by lazy {
|
||||||
FileUploadsDirCleaner { applicationContext.cacheDir }
|
// FileUploadsDirCleaner { applicationContext.cacheDir }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@OptIn(FlowPreview::class)
|
// @OptIn(FlowPreview::class)
|
||||||
val store by lazy {
|
// val store by lazy {
|
||||||
BrowserStore(
|
// BrowserStore(
|
||||||
middleware = listOf(
|
// middleware = listOf(
|
||||||
FlutterEventMiddleware(flutterEvents),
|
// FlutterEventMiddleware(flutterEvents),
|
||||||
DownloadMiddleware(applicationContext, DownloadService::class.java),
|
// DownloadMiddleware(applicationContext, DownloadService::class.java),
|
||||||
ReaderViewMiddleware(),
|
// ReaderViewMiddleware(),
|
||||||
ThumbnailsMiddleware(thumbnailStorage),
|
// ThumbnailsMiddleware(thumbnailStorage),
|
||||||
UndoMiddleware(),
|
// UndoMiddleware(),
|
||||||
RecordingDevicesMiddleware(applicationContext, notificationsDelegate),
|
// RecordingDevicesMiddleware(applicationContext, notificationsDelegate),
|
||||||
LastAccessMiddleware(),
|
// LastAccessMiddleware(),
|
||||||
PromptMiddleware(),
|
// PromptMiddleware(),
|
||||||
SessionPrioritizationMiddleware(),
|
// SessionPrioritizationMiddleware(),
|
||||||
) + EngineMiddleware.create(engine),
|
// ) + EngineMiddleware.create(engine),
|
||||||
).apply {
|
// ).apply {
|
||||||
this.flowScoped { flow ->
|
// this.flowScoped { flow ->
|
||||||
flow.map { state -> state.selectedTabId }
|
// flow.map { state -> state.selectedTabId }
|
||||||
.distinctUntilChanged()
|
// .distinctUntilChanged()
|
||||||
.collect { tabId ->
|
// .collect { tabId ->
|
||||||
flutterEvents.onSelectedTabChange(
|
// flutterEvents.onSelectedTabChange(
|
||||||
System.currentTimeMillis(),
|
// System.currentTimeMillis(),
|
||||||
tabId
|
// tabId
|
||||||
) { _ -> }
|
// ) { _ -> }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
this.flowScoped { flow ->
|
// this.flowScoped { flow ->
|
||||||
flow.mapNotNull { state -> state.tabs }
|
// flow.mapNotNull { state -> state.tabs }
|
||||||
.filterChanged {
|
// .filterChanged {
|
||||||
it.content
|
// it.content
|
||||||
}
|
// }
|
||||||
.ifAnyChanged { arrayOf (it.content.icon) }
|
// .ifAnyChanged { arrayOf (it.content.icon) }
|
||||||
.debounce { 50 }
|
// .debounce { 50 }
|
||||||
.collect { tab ->
|
// .collect { tab ->
|
||||||
val iconBytes = tab.content.icon?.toWebPBytes()
|
// val iconBytes = tab.content.icon?.toWebPBytes()
|
||||||
flutterEvents.onIconChange(
|
// flutterEvents.onIconChange(
|
||||||
System.currentTimeMillis(),
|
// System.currentTimeMillis(),
|
||||||
tab.id,
|
// tab.id,
|
||||||
iconBytes
|
// iconBytes
|
||||||
) { _ -> }
|
// ) { _ -> }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
this.flowScoped { flow ->
|
// this.flowScoped { flow ->
|
||||||
flow.mapNotNull { state -> state.tabs }
|
// flow.mapNotNull { state -> state.tabs }
|
||||||
.filterChanged {
|
// .filterChanged {
|
||||||
it.content.securityInfo
|
// it.content.securityInfo
|
||||||
}
|
// }
|
||||||
.debounce { 50 }
|
// .debounce { 50 }
|
||||||
.collect { tab ->
|
// .collect { tab ->
|
||||||
flutterEvents.onSecurityInfoStateChange(
|
// flutterEvents.onSecurityInfoStateChange(
|
||||||
System.currentTimeMillis(),
|
// System.currentTimeMillis(),
|
||||||
tab.id,
|
// tab.id,
|
||||||
SecurityInfoState(
|
// SecurityInfoState(
|
||||||
tab.content.securityInfo.secure,
|
// tab.content.securityInfo.secure,
|
||||||
tab.content.securityInfo.host,
|
// tab.content.securityInfo.host,
|
||||||
tab.content.securityInfo.issuer,
|
// tab.content.securityInfo.issuer,
|
||||||
)
|
// )
|
||||||
) { _ -> }
|
// ) { _ -> }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
this.flowScoped { flow ->
|
// this.flowScoped { flow ->
|
||||||
flow.mapNotNull { state -> state.tabs }
|
// flow.mapNotNull { state -> state.tabs }
|
||||||
.filterChanged {
|
// .filterChanged {
|
||||||
it.readerState
|
// it.readerState
|
||||||
}
|
// }
|
||||||
.ifAnyChanged { arrayOf(
|
// .ifAnyChanged { arrayOf(
|
||||||
it.readerState.readerable,
|
// it.readerState.readerable,
|
||||||
it.readerState.active,
|
// it.readerState.active,
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
.debounce { 50 }
|
// .debounce { 50 }
|
||||||
.collect { tab ->
|
// .collect { tab ->
|
||||||
flutterEvents.onReaderableStateChange(
|
// flutterEvents.onReaderableStateChange(
|
||||||
System.currentTimeMillis(),
|
// System.currentTimeMillis(),
|
||||||
tab.id,
|
// tab.id,
|
||||||
ReaderableState(
|
// ReaderableState(
|
||||||
tab.readerState.readerable,
|
// tab.readerState.readerable,
|
||||||
tab.readerState.active,
|
// tab.readerState.active,
|
||||||
)
|
// )
|
||||||
) { _ -> }
|
// ) { _ -> }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
this.flowScoped { flow ->
|
// this.flowScoped { flow ->
|
||||||
flow.mapNotNull { state -> state.tabs }
|
// flow.mapNotNull { state -> state.tabs }
|
||||||
.filterChanged {
|
// .filterChanged {
|
||||||
it.content
|
// it.content
|
||||||
}
|
// }
|
||||||
.ifAnyChanged { arrayOf(
|
// .ifAnyChanged { arrayOf(
|
||||||
it.content.history,
|
// it.content.history,
|
||||||
it.content.canGoBack,
|
// it.content.canGoBack,
|
||||||
it.content.canGoForward,
|
// it.content.canGoForward,
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
.debounce { 50 }
|
// .debounce { 50 }
|
||||||
.collect { tab ->
|
// .collect { tab ->
|
||||||
flutterEvents.onHistoryStateChange(
|
// flutterEvents.onHistoryStateChange(
|
||||||
System.currentTimeMillis(),
|
// System.currentTimeMillis(),
|
||||||
tab.id,
|
// tab.id,
|
||||||
HistoryState(
|
// HistoryState(
|
||||||
items = tab.content.history.items.map { item -> HistoryItem(
|
// items = tab.content.history.items.map { item -> HistoryItem(
|
||||||
url = item.uri,
|
// url = item.uri,
|
||||||
title = item.title
|
// title = item.title
|
||||||
) },
|
// ) },
|
||||||
currentIndex = tab.content.history.currentIndex.toLong(),
|
// currentIndex = tab.content.history.currentIndex.toLong(),
|
||||||
canGoBack = tab.content.canGoBack,
|
// canGoBack = tab.content.canGoBack,
|
||||||
canGoForward = tab.content.canGoForward,
|
// canGoForward = tab.content.canGoForward,
|
||||||
)
|
// )
|
||||||
) { _ -> }
|
// ) { _ -> }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
this.flowScoped { flow ->
|
// this.flowScoped { flow ->
|
||||||
flow.mapNotNull { state -> state.tabs.map {tab -> tab.id} }
|
// flow.mapNotNull { state -> state.tabs.map {tab -> tab.id} }
|
||||||
.distinctUntilChanged()
|
// .distinctUntilChanged()
|
||||||
.collect { tabs ->
|
// .collect { tabs ->
|
||||||
flutterEvents.onTabListChange(System.currentTimeMillis(), tabs) { _ -> }
|
// flutterEvents.onTabListChange(System.currentTimeMillis(), tabs) { _ -> }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
this.flowScoped { flow ->
|
// this.flowScoped { flow ->
|
||||||
flow.mapNotNull { state -> state.tabs }
|
// flow.mapNotNull { state -> state.tabs }
|
||||||
.filterChanged {
|
// .filterChanged {
|
||||||
it.content
|
// it.content
|
||||||
}
|
// }
|
||||||
.ifAnyChanged { arrayOf(
|
// .ifAnyChanged { arrayOf(
|
||||||
it.content.url,
|
// it.content.url,
|
||||||
it.content.title,
|
// it.content.title,
|
||||||
it.content.private,
|
// it.content.private,
|
||||||
it.content.fullScreen,
|
// it.content.fullScreen,
|
||||||
it.content.progress,
|
// it.content.progress,
|
||||||
it.content.loading)
|
// it.content.loading)
|
||||||
}
|
// }
|
||||||
.debounce { 50 }
|
// .debounce { 50 }
|
||||||
.collect { tab ->
|
// .collect { tab ->
|
||||||
logger.info("title: ${tab.content.title} ${tab.content.url}")
|
// logger.info("title: ${tab.content.title} ${tab.content.url}")
|
||||||
flutterEvents.onTabContentStateChange(
|
// flutterEvents.onTabContentStateChange(
|
||||||
System.currentTimeMillis(),
|
// System.currentTimeMillis(),
|
||||||
TabContentState(
|
// TabContentState(
|
||||||
id = tab.id,
|
// id = tab.id,
|
||||||
contextId = tab.contextId,
|
// contextId = tab.contextId,
|
||||||
url = tab.content.url,
|
// url = tab.content.url,
|
||||||
title = tab.content.title,
|
// title = tab.content.title,
|
||||||
progress = tab.content.progress.toLong(),
|
// progress = tab.content.progress.toLong(),
|
||||||
isPrivate = tab.content.private,
|
// isPrivate = tab.content.private,
|
||||||
isFullScreen = tab.content.fullScreen,
|
// isFullScreen = tab.content.fullScreen,
|
||||||
isLoading = tab.content.loading
|
// isLoading = tab.content.loading
|
||||||
)
|
// )
|
||||||
) { _ -> }
|
// ) { _ -> }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
this.flowScoped { flow ->
|
// this.flowScoped { flow ->
|
||||||
flow.mapNotNull { state -> state.tabs }
|
// flow.mapNotNull { state -> state.tabs }
|
||||||
.filterChanged {
|
// .filterChanged {
|
||||||
it.content.findResults
|
// it.content.findResults
|
||||||
}
|
// }
|
||||||
.distinctUntilChanged()
|
// .distinctUntilChanged()
|
||||||
.collect { tab ->
|
// .collect { tab ->
|
||||||
tab.content.findResults
|
// tab.content.findResults
|
||||||
flutterEvents.onFindResults(
|
// flutterEvents.onFindResults(
|
||||||
System.currentTimeMillis(),
|
// System.currentTimeMillis(),
|
||||||
tab.id,
|
// tab.id,
|
||||||
tab.content.findResults.map { result -> FindResultState(
|
// tab.content.findResults.map { result -> FindResultState(
|
||||||
activeMatchOrdinal = result.activeMatchOrdinal.toLong(),
|
// activeMatchOrdinal = result.activeMatchOrdinal.toLong(),
|
||||||
numberOfMatches = result.numberOfMatches.toLong(),
|
// numberOfMatches = result.numberOfMatches.toLong(),
|
||||||
isDoneCounting = result.isDoneCounting,
|
// isDoneCounting = result.isDoneCounting,
|
||||||
) }
|
// ) }
|
||||||
) { _ -> }
|
// ) { _ -> }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
icons.install(engine, this)
|
// icons.install(engine, this)
|
||||||
|
//
|
||||||
WebNotificationFeature(
|
// WebNotificationFeature(
|
||||||
applicationContext,
|
// applicationContext,
|
||||||
engine,
|
// engine,
|
||||||
icons,
|
// icons,
|
||||||
R.drawable.ic_launcher_foreground,
|
// R.drawable.ic_launcher_foreground,
|
||||||
permissionStorage,
|
// permissionStorage,
|
||||||
NotificationActivity::class.java,
|
// NotificationActivity::class.java,
|
||||||
notificationsDelegate = notificationsDelegate,
|
// notificationsDelegate = notificationsDelegate,
|
||||||
)
|
// )
|
||||||
|
//
|
||||||
MediaSessionFeature(applicationContext, MediaSessionService::class.java, this).start()
|
// MediaSessionFeature(applicationContext, MediaSessionService::class.java, this).start()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
val sessionUseCases by lazy { SessionUseCases(store) }
|
// val sessionUseCases by lazy { SessionUseCases(store) }
|
||||||
val tabsUseCases by lazy { TabsUseCases(store) }
|
// val tabsUseCases by lazy { TabsUseCases(store) }
|
||||||
|
//
|
||||||
val readerViewEvents by lazy { ReaderViewEventsImpl() }
|
// val readerViewEvents by lazy { ReaderViewEventsImpl() }
|
||||||
|
//
|
||||||
// Addons
|
// // Addons
|
||||||
val addonManager by lazy {
|
// val addonManager by lazy {
|
||||||
AddonManager(store, engine, addonsProvider, addonUpdater)
|
// AddonManager(store, engine, addonsProvider, addonUpdater)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
val addonsProvider by lazy {
|
// val addonsProvider by lazy {
|
||||||
AMOAddonsProvider(
|
// AMOAddonsProvider(
|
||||||
applicationContext,
|
// applicationContext,
|
||||||
client,
|
// client,
|
||||||
collectionName = "7dfae8669acc4312a65e8ba5553036",
|
// collectionName = "7dfae8669acc4312a65e8ba5553036",
|
||||||
maxCacheAgeInMinutes = DAY_IN_MINUTES,
|
// maxCacheAgeInMinutes = DAY_IN_MINUTES,
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
val supportedAddonsChecker by lazy {
|
// val supportedAddonsChecker by lazy {
|
||||||
DefaultSupportedAddonsChecker(applicationContext, Frequency(1, TimeUnit.DAYS))
|
// DefaultSupportedAddonsChecker(applicationContext, Frequency(1, TimeUnit.DAYS))
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
val appLinksUseCases by lazy { AppLinksUseCases(applicationContext) }
|
// val appLinksUseCases by lazy { AppLinksUseCases(applicationContext) }
|
||||||
|
//
|
||||||
val appLinksInterceptor by lazy {
|
// val appLinksInterceptor by lazy {
|
||||||
AppLinksInterceptor(
|
// AppLinksInterceptor(
|
||||||
applicationContext,
|
// applicationContext,
|
||||||
interceptLinkClicks = true,
|
// interceptLinkClicks = true,
|
||||||
launchInApp = {
|
// launchInApp = {
|
||||||
preferences.getBoolean(PREF_LAUNCH_EXTERNAL_APP, false)
|
// preferences.getBoolean(PREF_LAUNCH_EXTERNAL_APP, false)
|
||||||
},
|
// },
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Digital Asset Links checking
|
// // Digital Asset Links checking
|
||||||
val relationChecker by lazy {
|
// val relationChecker by lazy {
|
||||||
StatementRelationChecker(StatementApi(client))
|
// StatementRelationChecker(StatementApi(client))
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
val downloadsUseCases: DownloadsUseCases by lazy { DownloadsUseCases(store) }
|
// val downloadsUseCases: DownloadsUseCases by lazy { DownloadsUseCases(store) }
|
||||||
|
//
|
||||||
val crashReporter: CrashReporter by lazy {
|
// val crashReporter: CrashReporter by lazy {
|
||||||
CrashReporter(
|
// CrashReporter(
|
||||||
applicationContext,
|
// applicationContext,
|
||||||
services = listOf(
|
// services = listOf(
|
||||||
object : CrashReporterService {
|
// object : CrashReporterService {
|
||||||
override val id: String
|
// override val id: String
|
||||||
get() = "xxx"
|
// get() = "xxx"
|
||||||
override val name: String
|
// override val name: String
|
||||||
get() = "Test"
|
// get() = "Test"
|
||||||
|
//
|
||||||
override fun createCrashReportUrl(identifier: String): String? {
|
// override fun createCrashReportUrl(identifier: String): String? {
|
||||||
return null
|
// return null
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun report(crash: Crash.UncaughtExceptionCrash): String? {
|
// override fun report(crash: Crash.UncaughtExceptionCrash): String? {
|
||||||
return null
|
// return null
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun report(crash: Crash.NativeCodeCrash): String? {
|
// override fun report(crash: Crash.NativeCodeCrash): String? {
|
||||||
return null
|
// return null
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun report(
|
// override fun report(
|
||||||
throwable: Throwable,
|
// throwable: Throwable,
|
||||||
breadcrumbs: ArrayList<Breadcrumb>,
|
// breadcrumbs: ArrayList<Breadcrumb>,
|
||||||
): String? {
|
// ): String? {
|
||||||
return null
|
// return null
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
notificationsDelegate = notificationsDelegate,
|
// notificationsDelegate = notificationsDelegate,
|
||||||
).install(applicationContext)
|
// ).install(applicationContext)
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
-11
@@ -1,11 +0,0 @@
|
|||||||
package eu.lensai.flutter_mozilla_components
|
|
||||||
|
|
||||||
import mozilla.components.browser.state.store.BrowserStore
|
|
||||||
import mozilla.components.feature.downloads.AbstractFetchDownloadService
|
|
||||||
import mozilla.components.support.base.android.NotificationsDelegate
|
|
||||||
|
|
||||||
class DownloadService : AbstractFetchDownloadService() {
|
|
||||||
override val httpClient by lazy { GlobalComponents.components!!.client }
|
|
||||||
override val store: BrowserStore by lazy { GlobalComponents.components!!.store }
|
|
||||||
override val notificationsDelegate: NotificationsDelegate by lazy { GlobalComponents.components!!.notificationsDelegate }
|
|
||||||
}
|
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package eu.lensai.flutter_mozilla_components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.lensai.flutter_mozilla_components.feature.CookieManagerFeature
|
||||||
|
import mozilla.components.browser.engine.gecko.GeckoEngine
|
||||||
|
import mozilla.components.browser.engine.gecko.fetch.GeckoViewFetchClient
|
||||||
|
import mozilla.components.concept.engine.DefaultSettings
|
||||||
|
import mozilla.components.concept.engine.Engine
|
||||||
|
import mozilla.components.concept.fetch.Client
|
||||||
|
import mozilla.components.feature.webcompat.WebCompatFeature
|
||||||
|
import mozilla.components.support.base.log.logger.Logger
|
||||||
|
import org.mozilla.geckoview.GeckoRuntime
|
||||||
|
import org.mozilla.geckoview.GeckoRuntimeSettings
|
||||||
|
|
||||||
|
object EngineProvider {
|
||||||
|
private var runtime: GeckoRuntime? = null
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun getOrCreateRuntime(context: Context): GeckoRuntime {
|
||||||
|
if (runtime == null) {
|
||||||
|
Logger.debug("Creating Runtime")
|
||||||
|
val builder = GeckoRuntimeSettings.Builder()
|
||||||
|
|
||||||
|
// if (isCrashReportActive) {
|
||||||
|
// builder.crashHandler(CrashHandlerService::class.java)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// About config it's no longer enabled by default
|
||||||
|
builder.aboutConfigEnabled(true)
|
||||||
|
builder.extensionsWebAPIEnabled(true)
|
||||||
|
runtime = GeckoRuntime.create(context, builder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
return runtime!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createEngine(context: Context, defaultSettings: DefaultSettings): Engine {
|
||||||
|
Logger.debug("Creating Engine")
|
||||||
|
val runtime = getOrCreateRuntime(context)
|
||||||
|
|
||||||
|
return GeckoEngine(context, defaultSettings, runtime).also {
|
||||||
|
WebCompatFeature.install(it)
|
||||||
|
CookieManagerFeature.install(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createClient(context: Context): Client {
|
||||||
|
Logger.debug("Fetching Client")
|
||||||
|
val runtime = getOrCreateRuntime(context)
|
||||||
|
return GeckoViewFetchClient(context, runtime)
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-60
@@ -1,9 +1,10 @@
|
|||||||
package eu.lensai.flutter_mozilla_components
|
package eu.lensai.flutter_mozilla_components
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import eu.lensai.flutter_mozilla_components.activities.NotificationActivity
|
||||||
|
import eu.lensai.flutter_mozilla_components.api.GeckoAddonsApiImpl
|
||||||
import eu.lensai.flutter_mozilla_components.api.GeckoBrowserApiImpl
|
import eu.lensai.flutter_mozilla_components.api.GeckoBrowserApiImpl
|
||||||
import eu.lensai.flutter_mozilla_components.api.GeckoCookieApiImpl
|
import eu.lensai.flutter_mozilla_components.api.GeckoCookieApiImpl
|
||||||
import eu.lensai.flutter_mozilla_components.api.GeckoEngineSettingsApiImpl
|
import eu.lensai.flutter_mozilla_components.api.GeckoEngineSettingsApiImpl
|
||||||
@@ -12,8 +13,9 @@ import eu.lensai.flutter_mozilla_components.api.GeckoIconsApiImpl
|
|||||||
import eu.lensai.flutter_mozilla_components.api.GeckoSelectionActionControllerImpl
|
import eu.lensai.flutter_mozilla_components.api.GeckoSelectionActionControllerImpl
|
||||||
import eu.lensai.flutter_mozilla_components.api.GeckoSessionApiImpl
|
import eu.lensai.flutter_mozilla_components.api.GeckoSessionApiImpl
|
||||||
import eu.lensai.flutter_mozilla_components.api.GeckoTabsApiImpl
|
import eu.lensai.flutter_mozilla_components.api.GeckoTabsApiImpl
|
||||||
import eu.lensai.flutter_mozilla_components.feature.CookieManagerFeature
|
|
||||||
import eu.lensai.flutter_mozilla_components.feature.DefaultSelectionActionDelegate
|
import eu.lensai.flutter_mozilla_components.feature.DefaultSelectionActionDelegate
|
||||||
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents
|
||||||
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonsApi
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoBrowserApi
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoBrowserApi
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoCookieApi
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoCookieApi
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
|
||||||
@@ -30,68 +32,16 @@ import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewEvents
|
|||||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||||
import mozilla.components.browser.engine.gecko.GeckoEngine
|
|
||||||
import mozilla.components.browser.engine.gecko.fetch.GeckoViewFetchClient
|
|
||||||
import mozilla.components.concept.engine.Engine
|
|
||||||
import mozilla.components.concept.engine.selection.SelectionActionDelegate
|
|
||||||
import mozilla.components.experiment.NimbusExperimentDelegate
|
|
||||||
import mozilla.components.feature.webcompat.WebCompatFeature
|
|
||||||
import mozilla.components.lib.crash.handler.CrashHandlerService
|
|
||||||
import mozilla.components.support.base.log.Log
|
import mozilla.components.support.base.log.Log
|
||||||
import mozilla.components.support.base.log.sink.AndroidLogSink
|
import mozilla.components.support.base.log.sink.AndroidLogSink
|
||||||
import org.mozilla.geckoview.GeckoRuntime
|
|
||||||
import org.mozilla.geckoview.GeckoRuntimeSettings
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class for lazily instantiating components needed by the application.
|
|
||||||
*/
|
|
||||||
class Components(
|
|
||||||
private val applicationContext: Context,
|
|
||||||
flutterEvents: GeckoStateEvents,
|
|
||||||
readerViewController: ReaderViewController,
|
|
||||||
selectionAction: SelectionActionDelegate,
|
|
||||||
) : DefaultComponents(
|
|
||||||
applicationContext,
|
|
||||||
flutterEvents,
|
|
||||||
readerViewController,
|
|
||||||
selectionAction
|
|
||||||
) {
|
|
||||||
private val runtime by lazy {
|
|
||||||
// Allow for exfiltrating Gecko metrics through the Glean SDK.
|
|
||||||
val builder = GeckoRuntimeSettings.Builder()
|
|
||||||
.aboutConfigEnabled(true)
|
|
||||||
.extensionsWebAPIEnabled(true)
|
|
||||||
|
|
||||||
builder.experimentDelegate(NimbusExperimentDelegate())
|
|
||||||
builder.crashHandler(CrashHandlerService::class.java)
|
|
||||||
|
|
||||||
GeckoRuntime.create(applicationContext, builder.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
override val engine: Engine by lazy {
|
|
||||||
GeckoEngine(applicationContext, engineSettings, runtime).also {
|
|
||||||
// it.installBuiltInWebExtension("borderify@mozac.org", "resource://android/assets/extensions/borderify/") {
|
|
||||||
// throwable ->
|
|
||||||
// Log.log(Log.Priority.ERROR, "SampleBrowser", throwable, "Failed to install borderify")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// it.installBuiltInWebExtension("testext@mozac.org", "resource://android/assets/extensions/test/") {
|
|
||||||
// throwable ->
|
|
||||||
// Log.log(Log.Priority.ERROR, "SampleBrowser", throwable, "Failed to install testext")
|
|
||||||
// }
|
|
||||||
|
|
||||||
WebCompatFeature.install(it)
|
|
||||||
CookieManagerFeature.install(it)
|
|
||||||
//WebCompatReporterFeature.install(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val client by lazy { GeckoViewFetchClient(applicationContext, runtime) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** FlutterMozillaComponentsPlugin */
|
/** FlutterMozillaComponentsPlugin */
|
||||||
class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
||||||
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
private var activity: Activity? = null
|
private var activity: Activity? = null
|
||||||
|
|
||||||
private lateinit var _flutterPluginBinding: FlutterPlugin.FlutterPluginBinding;
|
private lateinit var _flutterPluginBinding: FlutterPlugin.FlutterPluginBinding;
|
||||||
@@ -112,11 +62,14 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
|||||||
val readerViewController =
|
val readerViewController =
|
||||||
ReaderViewController(_flutterPluginBinding.binaryMessenger)
|
ReaderViewController(_flutterPluginBinding.binaryMessenger)
|
||||||
|
|
||||||
|
val addonEvents = GeckoAddonEvents(_flutterPluginBinding.binaryMessenger)
|
||||||
|
|
||||||
GlobalComponents.setUp(
|
GlobalComponents.setUp(
|
||||||
flutterPluginBinding.applicationContext,
|
flutterPluginBinding.applicationContext,
|
||||||
_flutterEvents,
|
_flutterEvents,
|
||||||
readerViewController,
|
readerViewController,
|
||||||
selectionActionDelegate
|
selectionActionDelegate,
|
||||||
|
addonEvents
|
||||||
)
|
)
|
||||||
|
|
||||||
GeckoBrowserApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoBrowserApiImpl {
|
GeckoBrowserApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoBrowserApiImpl {
|
||||||
@@ -124,6 +77,7 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
|||||||
})
|
})
|
||||||
|
|
||||||
GeckoEngineSettingsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoEngineSettingsApiImpl())
|
GeckoEngineSettingsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoEngineSettingsApiImpl())
|
||||||
|
GeckoAddonsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoAddonsApiImpl(flutterPluginBinding.applicationContext))
|
||||||
GeckoSessionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoSessionApiImpl())
|
GeckoSessionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoSessionApiImpl())
|
||||||
GeckoTabsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoTabsApiImpl())
|
GeckoTabsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoTabsApiImpl())
|
||||||
GeckoIconsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoIconsApiImpl())
|
GeckoIconsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoIconsApiImpl())
|
||||||
@@ -135,7 +89,7 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
|||||||
|
|
||||||
ReaderViewEvents.setUp(
|
ReaderViewEvents.setUp(
|
||||||
_flutterPluginBinding.binaryMessenger,
|
_flutterPluginBinding.binaryMessenger,
|
||||||
GlobalComponents.components!!.readerViewEvents
|
components.events.readerViewEvents
|
||||||
)
|
)
|
||||||
|
|
||||||
val intent = Intent(flutterPluginBinding.applicationContext, NotificationActivity::class.java)
|
val intent = Intent(flutterPluginBinding.applicationContext, NotificationActivity::class.java)
|
||||||
|
|||||||
+5
-1
@@ -26,6 +26,10 @@ private class NativeFragmentView(
|
|||||||
containerId: Int,
|
containerId: Int,
|
||||||
private val flutterEvents: GeckoStateEvents
|
private val flutterEvents: GeckoStateEvents
|
||||||
) : PlatformView {
|
) : PlatformView {
|
||||||
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
private val container: View
|
private val container: View
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -41,7 +45,7 @@ private class NativeFragmentView(
|
|||||||
override fun onFlutterViewAttached(flutterView: View) {
|
override fun onFlutterViewAttached(flutterView: View) {
|
||||||
super.onFlutterViewAttached(flutterView)
|
super.onFlutterViewAttached(flutterView)
|
||||||
|
|
||||||
GlobalComponents.components!!.engineReportedInitialized = false;
|
components.engineReportedInitialized = false;
|
||||||
flutterEvents.onViewReadyStateChange(System.currentTimeMillis(),true) { _ -> }
|
flutterEvents.onViewReadyStateChange(System.currentTimeMillis(),true) { _ -> }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-18
@@ -1,6 +1,7 @@
|
|||||||
package eu.lensai.flutter_mozilla_components
|
package eu.lensai.flutter_mozilla_components
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
|
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
@@ -11,7 +12,9 @@ import mozilla.components.concept.engine.selection.SelectionActionDelegate
|
|||||||
import mozilla.components.feature.addons.update.GlobalAddonDependencyProvider
|
import mozilla.components.feature.addons.update.GlobalAddonDependencyProvider
|
||||||
import mozilla.components.support.base.facts.Facts
|
import mozilla.components.support.base.facts.Facts
|
||||||
import mozilla.components.support.base.facts.processor.LogFactProcessor
|
import mozilla.components.support.base.facts.processor.LogFactProcessor
|
||||||
|
import mozilla.components.support.base.log.Log
|
||||||
import mozilla.components.support.base.log.logger.Logger
|
import mozilla.components.support.base.log.logger.Logger
|
||||||
|
import mozilla.components.support.base.log.sink.AndroidLogSink
|
||||||
import mozilla.components.support.webextensions.WebExtensionSupport
|
import mozilla.components.support.webextensions.WebExtensionSupport
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@@ -23,60 +26,69 @@ object GlobalComponents {
|
|||||||
|
|
||||||
@DelicateCoroutinesApi
|
@DelicateCoroutinesApi
|
||||||
private fun restoreBrowserState(newComponents: Components) = GlobalScope.launch(Dispatchers.Main) {
|
private fun restoreBrowserState(newComponents: Components) = GlobalScope.launch(Dispatchers.Main) {
|
||||||
newComponents.tabsUseCases.restore(newComponents.sessionStorage)
|
newComponents.useCases.tabsUseCases.restore(newComponents.core.sessionStorage)
|
||||||
|
|
||||||
newComponents.sessionStorage.autoSave(newComponents.store)
|
newComponents.core.sessionStorage.autoSave(newComponents.core.store)
|
||||||
.periodicallyInForeground(interval = 30, unit = TimeUnit.SECONDS)
|
.periodicallyInForeground(interval = 30, unit = TimeUnit.SECONDS)
|
||||||
.whenGoingToBackground()
|
.whenGoingToBackground()
|
||||||
.whenSessionsChange()
|
.whenSessionsChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
fun setUp(
|
fun setUp(
|
||||||
applicationContext: Context,
|
applicationContext: Context,
|
||||||
flutterEvents: GeckoStateEvents,
|
flutterEvents: GeckoStateEvents,
|
||||||
readerViewController: ReaderViewController,
|
readerViewController: ReaderViewController,
|
||||||
selectionAction: SelectionActionDelegate
|
selectionAction: SelectionActionDelegate,
|
||||||
|
addonEvents: GeckoAddonEvents
|
||||||
) {
|
) {
|
||||||
|
Logger.debug("Creating new components")
|
||||||
|
|
||||||
val newComponents = Components(
|
val newComponents = Components(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
flutterEvents,
|
flutterEvents,
|
||||||
readerViewController,
|
readerViewController,
|
||||||
selectionAction
|
selectionAction,
|
||||||
|
addonEvents,
|
||||||
)
|
)
|
||||||
|
|
||||||
newComponents.crashReporter.install(applicationContext)
|
//newComponents.crashReporter.install(applicationContext)
|
||||||
Facts.registerProcessor(LogFactProcessor())
|
|
||||||
|
|
||||||
newComponents.engine.warmUp()
|
//Facts.registerProcessor(LogFactProcessor())
|
||||||
|
|
||||||
|
//RustHttpConfig.setClient(lazy { newComponents.core.client })
|
||||||
|
|
||||||
|
newComponents.core.engine.warmUp()
|
||||||
|
|
||||||
restoreBrowserState(newComponents)
|
restoreBrowserState(newComponents)
|
||||||
newComponents.downloadsUseCases.restoreDownloads()
|
|
||||||
|
//newComponents.useCases.downloadsUseCases.restoreDownloads()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GlobalAddonDependencyProvider.initialize(
|
GlobalAddonDependencyProvider.initialize(
|
||||||
newComponents.addonManager,
|
newComponents.core.addonManager,
|
||||||
newComponents.addonUpdater,
|
newComponents.core.addonUpdater,
|
||||||
)
|
)
|
||||||
|
|
||||||
WebExtensionSupport.initialize(
|
WebExtensionSupport.initialize(
|
||||||
newComponents.engine,
|
newComponents.core.engine,
|
||||||
newComponents.store,
|
newComponents.core.store,
|
||||||
onNewTabOverride = {
|
onNewTabOverride = {
|
||||||
_, engineSession, url ->
|
_, engineSession, url ->
|
||||||
newComponents.tabsUseCases.addTab(url, selectTab = true, engineSession = engineSession)
|
newComponents.useCases.tabsUseCases.addTab(url, selectTab = true, engineSession = engineSession)
|
||||||
},
|
},
|
||||||
onCloseTabOverride = {
|
onCloseTabOverride = {
|
||||||
_, sessionId ->
|
_, sessionId ->
|
||||||
newComponents.tabsUseCases.removeTab(sessionId)
|
newComponents.useCases.tabsUseCases.removeTab(sessionId)
|
||||||
},
|
},
|
||||||
onSelectTabOverride = {
|
onSelectTabOverride = {
|
||||||
_, sessionId ->
|
_, sessionId ->
|
||||||
newComponents.tabsUseCases.selectTab(sessionId)
|
newComponents.useCases.tabsUseCases.selectTab(sessionId)
|
||||||
},
|
},
|
||||||
onUpdatePermissionRequest = newComponents.addonUpdater::onUpdatePermissionRequest,
|
onUpdatePermissionRequest = newComponents.core.addonUpdater::onUpdatePermissionRequest,
|
||||||
onExtensionsLoaded = { extensions ->
|
onExtensionsLoaded = { extensions ->
|
||||||
newComponents.addonUpdater.registerForFutureUpdates(extensions)
|
newComponents.core.addonUpdater.registerForFutureUpdates(extensions)
|
||||||
newComponents.supportedAddonsChecker.registerForChecks()
|
newComponents.core.supportedAddonsChecker.registerForChecks()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} catch (e: UnsupportedOperationException) {
|
} catch (e: UnsupportedOperationException) {
|
||||||
@@ -84,6 +96,10 @@ object GlobalComponents {
|
|||||||
Logger.error("Failed to initialize web extension support", e)
|
Logger.error("Failed to initialize web extension support", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
newComponents.core.fileUploadsDirCleaner.cleanUploadsDirectory()
|
||||||
|
}
|
||||||
|
|
||||||
_components = newComponents
|
_components = newComponents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-2
@@ -1,2 +0,0 @@
|
|||||||
package eu.lensai.flutter_mozilla_components
|
|
||||||
|
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
package eu.lensai.flutter_mozilla_components
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
|
|
||||||
class NotificationActivity: AppCompatActivity() {
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
GlobalComponents.components!!.notificationsDelegate.bindToActivity(this)
|
|
||||||
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package eu.lensai.flutter_mozilla_components.activities
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import eu.lensai.flutter_mozilla_components.GlobalComponents
|
||||||
|
|
||||||
|
class NotificationActivity: AppCompatActivity() {
|
||||||
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
components.notificationsDelegate.bindToActivity(this)
|
||||||
|
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-5
@@ -21,13 +21,14 @@ import mozilla.components.feature.addons.ui.translateName
|
|||||||
import mozilla.components.support.utils.ext.getParcelableCompat
|
import mozilla.components.support.utils.ext.getParcelableCompat
|
||||||
import mozilla.components.support.utils.ext.getParcelableExtraCompat
|
import mozilla.components.support.utils.ext.getParcelableExtraCompat
|
||||||
import eu.lensai.flutter_mozilla_components.R
|
import eu.lensai.flutter_mozilla_components.R
|
||||||
import mozilla.components.browser.state.store.BrowserStore
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity to show the settings of an add-on.
|
* An activity to show the settings of an add-on.
|
||||||
*/
|
*/
|
||||||
class AddonSettingsActivity : AppCompatActivity() {
|
class AddonSettingsActivity : AppCompatActivity() {
|
||||||
private val components: Components by lazy { GlobalComponents.components!! }
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -47,7 +48,7 @@ class AddonSettingsActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? =
|
override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? =
|
||||||
when (name) {
|
when (name) {
|
||||||
EngineView::class.java.name -> components.engine.createView(context, attrs).asView()
|
EngineView::class.java.name -> components.core.engine.createView(context, attrs).asView()
|
||||||
else -> super.onCreateView(parent, name, context, attrs)
|
else -> super.onCreateView(parent, name, context, attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +56,9 @@ class AddonSettingsActivity : AppCompatActivity() {
|
|||||||
* A fragment to show the settings of an add-on with [EngineView].
|
* A fragment to show the settings of an add-on with [EngineView].
|
||||||
*/
|
*/
|
||||||
class AddonSettingsFragment : Fragment() {
|
class AddonSettingsFragment : Fragment() {
|
||||||
private val components: Components by lazy { GlobalComponents.components!! }
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
private lateinit var optionsPageUrl: String
|
private lateinit var optionsPageUrl: String
|
||||||
private lateinit var engineSession: EngineSession
|
private lateinit var engineSession: EngineSession
|
||||||
@@ -68,7 +71,7 @@ class AddonSettingsActivity : AppCompatActivity() {
|
|||||||
)?.installedState?.optionsPageUrl,
|
)?.installedState?.optionsPageUrl,
|
||||||
)
|
)
|
||||||
|
|
||||||
engineSession = components.engine.createSession()
|
engineSession = components.core.engine.createSession()
|
||||||
|
|
||||||
return inflater.inflate(R.layout.fragment_add_on_settings, container, false)
|
return inflater.inflate(R.layout.fragment_add_on_settings, container, false)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -30,7 +30,9 @@ import mozilla.components.feature.addons.R as MozComp
|
|||||||
* Fragment use for managing add-ons.
|
* Fragment use for managing add-ons.
|
||||||
*/
|
*/
|
||||||
class AddonsFragment : Fragment(), AddonsManagerAdapterDelegate {
|
class AddonsFragment : Fragment(), AddonsManagerAdapterDelegate {
|
||||||
private val components: Components by lazy { GlobalComponents.components!! }
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
private val webExtensionPromptFeature = ViewBoundFeatureWrapper<WebExtensionPromptFeature>()
|
private val webExtensionPromptFeature = ViewBoundFeatureWrapper<WebExtensionPromptFeature>()
|
||||||
private lateinit var recyclerView: RecyclerView
|
private lateinit var recyclerView: RecyclerView
|
||||||
@@ -54,7 +56,7 @@ class AddonsFragment : Fragment(), AddonsManagerAdapterDelegate {
|
|||||||
bindRecyclerView(rootView)
|
bindRecyclerView(rootView)
|
||||||
webExtensionPromptFeature.set(
|
webExtensionPromptFeature.set(
|
||||||
feature = WebExtensionPromptFeature(
|
feature = WebExtensionPromptFeature(
|
||||||
store = components.store,
|
store = components.core.store,
|
||||||
context = requireContext(),
|
context = requireContext(),
|
||||||
fragmentManager = parentFragmentManager,
|
fragmentManager = parentFragmentManager,
|
||||||
),
|
),
|
||||||
@@ -78,13 +80,13 @@ class AddonsFragment : Fragment(), AddonsManagerAdapterDelegate {
|
|||||||
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
scope.launch {
|
scope.launch {
|
||||||
try {
|
try {
|
||||||
addons = components.addonManager.getAddons()
|
addons = components.core.addonManager.getAddons()
|
||||||
|
|
||||||
scope.launch(Dispatchers.Main) {
|
scope.launch(Dispatchers.Main) {
|
||||||
adapter = AddonsManagerAdapter(
|
adapter = AddonsManagerAdapter(
|
||||||
this@AddonsFragment,
|
this@AddonsFragment,
|
||||||
addons,
|
addons,
|
||||||
store = components.store,
|
store = components.core.store,
|
||||||
)
|
)
|
||||||
recyclerView.adapter = adapter
|
recyclerView.adapter = adapter
|
||||||
}
|
}
|
||||||
@@ -122,7 +124,7 @@ class AddonsFragment : Fragment(), AddonsManagerAdapterDelegate {
|
|||||||
private val installAddon: ((Addon) -> Unit) = { addon ->
|
private val installAddon: ((Addon) -> Unit) = { addon ->
|
||||||
addonProgressOverlay.visibility = View.VISIBLE
|
addonProgressOverlay.visibility = View.VISIBLE
|
||||||
isInstallationInProgress = true
|
isInstallationInProgress = true
|
||||||
components.addonManager.installAddon(
|
components.core.addonManager.installAddon(
|
||||||
url = addon.downloadUrl,
|
url = addon.downloadUrl,
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
runIfFragmentIsAttached {
|
runIfFragmentIsAttached {
|
||||||
|
|||||||
+8
-6
@@ -27,7 +27,9 @@ import mozilla.components.feature.addons.R as MozComp
|
|||||||
* An activity to show the details of a installed add-on.
|
* An activity to show the details of a installed add-on.
|
||||||
*/
|
*/
|
||||||
class InstalledAddonDetailsActivity : AppCompatActivity() {
|
class InstalledAddonDetailsActivity : AppCompatActivity() {
|
||||||
private val components: Components by lazy { GlobalComponents.components!! }
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
private val scope = CoroutineScope(Dispatchers.IO)
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ class InstalledAddonDetailsActivity : AppCompatActivity() {
|
|||||||
private fun bindAddon(addon: Addon) {
|
private fun bindAddon(addon: Addon) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
try {
|
try {
|
||||||
val addons = components.addonManager.getAddons()
|
val addons = components.core.addonManager.getAddons()
|
||||||
scope.launch(Dispatchers.Main) {
|
scope.launch(Dispatchers.Main) {
|
||||||
addons.find { addon.id == it.id }.let {
|
addons.find { addon.id == it.id }.let {
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
@@ -89,7 +91,7 @@ class InstalledAddonDetailsActivity : AppCompatActivity() {
|
|||||||
switch.setState(addon.isEnabled())
|
switch.setState(addon.isEnabled())
|
||||||
switch.setOnCheckedChangeListener { _, isChecked ->
|
switch.setOnCheckedChangeListener { _, isChecked ->
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
components.addonManager.enableAddon(
|
components.core.addonManager.enableAddon(
|
||||||
addon,
|
addon,
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
switch.setState(true)
|
switch.setState(true)
|
||||||
@@ -108,7 +110,7 @@ class InstalledAddonDetailsActivity : AppCompatActivity() {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
components.addonManager.disableAddon(
|
components.core.addonManager.disableAddon(
|
||||||
addon,
|
addon,
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
switch.setState(false)
|
switch.setState(false)
|
||||||
@@ -161,7 +163,7 @@ class InstalledAddonDetailsActivity : AppCompatActivity() {
|
|||||||
val switch = findViewById<SwitchCompat>(R.id.allow_in_private_browsing_switch)
|
val switch = findViewById<SwitchCompat>(R.id.allow_in_private_browsing_switch)
|
||||||
switch.isChecked = addon.isAllowedInPrivateBrowsing()
|
switch.isChecked = addon.isAllowedInPrivateBrowsing()
|
||||||
switch.setOnCheckedChangeListener { _, isChecked ->
|
switch.setOnCheckedChangeListener { _, isChecked ->
|
||||||
components.addonManager.setAddonAllowedInPrivateBrowsing(
|
components.core.addonManager.setAddonAllowedInPrivateBrowsing(
|
||||||
addon,
|
addon,
|
||||||
isChecked,
|
isChecked,
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
@@ -173,7 +175,7 @@ class InstalledAddonDetailsActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun bindRemoveButton(addon: Addon) {
|
private fun bindRemoveButton(addon: Addon) {
|
||||||
findViewById<View>(R.id.remove_add_on).setOnClickListener {
|
findViewById<View>(R.id.remove_add_on).setOnClickListener {
|
||||||
components.addonManager.uninstallAddon(
|
components.core.addonManager.uninstallAddon(
|
||||||
addon,
|
addon,
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
|
|||||||
+10
-6
@@ -25,7 +25,9 @@ import eu.lensai.flutter_mozilla_components.R
|
|||||||
* An activity to show the pop up action of a web extension.
|
* An activity to show the pop up action of a web extension.
|
||||||
*/
|
*/
|
||||||
class WebExtensionActionPopupActivity : AppCompatActivity() {
|
class WebExtensionActionPopupActivity : AppCompatActivity() {
|
||||||
private val components: Components by lazy { GlobalComponents.components!! }
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
private lateinit var webExtensionId: String
|
private lateinit var webExtensionId: String
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ class WebExtensionActionPopupActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? =
|
override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? =
|
||||||
when (name) {
|
when (name) {
|
||||||
EngineView::class.java.name -> components.engine.createView(context, attrs).asView()
|
EngineView::class.java.name -> components.core.engine.createView(context, attrs).asView()
|
||||||
else -> super.onCreateView(parent, name, context, attrs)
|
else -> super.onCreateView(parent, name, context, attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +56,9 @@ class WebExtensionActionPopupActivity : AppCompatActivity() {
|
|||||||
* A fragment to show the web extension action popup with [EngineView].
|
* A fragment to show the web extension action popup with [EngineView].
|
||||||
*/
|
*/
|
||||||
class WebExtensionActionPopupFragment : Fragment(), EngineSession.Observer {
|
class WebExtensionActionPopupFragment : Fragment(), EngineSession.Observer {
|
||||||
private val components: Components by lazy { GlobalComponents.components!! }
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
private var engineSession: EngineSession? = null
|
private var engineSession: EngineSession? = null
|
||||||
private lateinit var webExtensionId: String
|
private lateinit var webExtensionId: String
|
||||||
@@ -64,7 +68,7 @@ class WebExtensionActionPopupActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
webExtensionId = requireNotNull(arguments?.getString("web_extension_id"))
|
webExtensionId = requireNotNull(arguments?.getString("web_extension_id"))
|
||||||
engineSession = components.store.state.extensions[webExtensionId]?.popupSession
|
engineSession = components.core.store.state.extensions[webExtensionId]?.popupSession
|
||||||
|
|
||||||
return inflater.inflate(R.layout.fragment_add_on_settings, container, false)
|
return inflater.inflate(R.layout.fragment_add_on_settings, container, false)
|
||||||
}
|
}
|
||||||
@@ -77,7 +81,7 @@ class WebExtensionActionPopupActivity : AppCompatActivity() {
|
|||||||
addonSettingsEngineView.render(session)
|
addonSettingsEngineView.render(session)
|
||||||
consumePopupSession()
|
consumePopupSession()
|
||||||
} else {
|
} else {
|
||||||
consumeFrom(components.store) { state ->
|
consumeFrom(components.core.store) { state ->
|
||||||
state.extensions[webExtensionId]?.let { extState ->
|
state.extensions[webExtensionId]?.let { extState ->
|
||||||
extState.popupSession?.let {
|
extState.popupSession?.let {
|
||||||
if (engineSession == null) {
|
if (engineSession == null) {
|
||||||
@@ -108,7 +112,7 @@ class WebExtensionActionPopupActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun consumePopupSession() {
|
private fun consumePopupSession() {
|
||||||
components.store.dispatch(
|
components.core.store.dispatch(
|
||||||
WebExtensionAction.UpdatePopupSessionAction(webExtensionId, popupSession = null),
|
WebExtensionAction.UpdatePopupSessionAction(webExtensionId, popupSession = null),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package eu.lensai.flutter_mozilla_components.api
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import eu.lensai.flutter_mozilla_components.GlobalComponents
|
||||||
|
import eu.lensai.flutter_mozilla_components.addons.AddonsActivity
|
||||||
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonsApi
|
||||||
|
import eu.lensai.flutter_mozilla_components.pigeons.WebExtensionActionType
|
||||||
|
|
||||||
|
class GeckoAddonsApiImpl(private val context: Context) : GeckoAddonsApi {
|
||||||
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startAddonManagerActivity() {
|
||||||
|
val intent = Intent(context, AddonsActivity::class.java)
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invokeAddonAction(extensionId: String, actionType: WebExtensionActionType) {
|
||||||
|
when(actionType) {
|
||||||
|
WebExtensionActionType.BROWSER -> components.features.webExtensionToolbarFeature.invokeAddonBrowserAction(extensionId)
|
||||||
|
WebExtensionActionType.PAGE -> components.features.webExtensionToolbarFeature.invokeAddonPageAction(extensionId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
-6
@@ -5,17 +5,35 @@ import eu.lensai.flutter_mozilla_components.pigeons.GeckoBrowserApi
|
|||||||
import mozilla.components.browser.state.action.SystemAction
|
import mozilla.components.browser.state.action.SystemAction
|
||||||
import mozilla.components.feature.addons.logger
|
import mozilla.components.feature.addons.logger
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of GeckoBrowserApi that handles browser-related operations
|
||||||
|
* @param showFragmentCallback Callback function to show native fragment
|
||||||
|
*/
|
||||||
class GeckoBrowserApiImpl(private val showFragmentCallback: () -> Unit) : GeckoBrowserApi {
|
class GeckoBrowserApiImpl(private val showFragmentCallback: () -> Unit) : GeckoBrowserApi {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "GeckoBrowserApiImpl"
|
||||||
|
}
|
||||||
|
|
||||||
override fun showNativeFragment() {
|
override fun showNativeFragment() {
|
||||||
showFragmentCallback.invoke();
|
try {
|
||||||
|
showFragmentCallback()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("Failed to show native fragment", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTrimMemory(level: Long) {
|
override fun onTrimMemory(level: Long) {
|
||||||
logger.debug("onTrimMemory: $level")
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
|
||||||
val components = GlobalComponents.components!!
|
logger.debug("$TAG: onTrimMemory called with level: $level")
|
||||||
|
|
||||||
components.store.dispatch(SystemAction.LowMemoryAction(level.toInt()))
|
with(GlobalComponents.components!!) {
|
||||||
components.icons.onTrimMemory(level.toInt())
|
try {
|
||||||
|
core.store.dispatch(SystemAction.LowMemoryAction(level.toInt()))
|
||||||
|
core.icons.onTrimMemory(level.toInt())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("$TAG: Failed to handle memory trim", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+104
-224
@@ -2,64 +2,96 @@ package eu.lensai.flutter_mozilla_components.api
|
|||||||
|
|
||||||
import eu.lensai.flutter_mozilla_components.feature.CookieManagerFeature
|
import eu.lensai.flutter_mozilla_components.feature.CookieManagerFeature
|
||||||
import eu.lensai.flutter_mozilla_components.feature.ResultConsumer
|
import eu.lensai.flutter_mozilla_components.feature.ResultConsumer
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.Cookie
|
import eu.lensai.flutter_mozilla_components.pigeons.*
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.CookiePartitionKey
|
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.CookieSameSiteStatus
|
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoCookieApi
|
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
class GeckoCookieApiImpl : GeckoCookieApi {
|
class GeckoCookieApiImpl : GeckoCookieApi {
|
||||||
private fun toValueOrNull(json: JSONObject, key: String): Any? {
|
private companion object {
|
||||||
if (!json.has(key)) {
|
const val ERROR_INVALID_KEY = "Invalid map key"
|
||||||
throw RuntimeException("Invalid map key")
|
}
|
||||||
|
|
||||||
|
private fun JSONObject.putNullable(key: String, value: Any?) {
|
||||||
|
put(key, value ?: JSONObject.NULL)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun JSONObject.getValueOrNull(key: String): Any? {
|
||||||
|
if (!has(key)) throw RuntimeException(ERROR_INVALID_KEY)
|
||||||
|
return if (!isNull(key)) get(key) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CookiePartitionKey.toJSON() = JSONObject().apply {
|
||||||
|
put("topLevelSite", topLevelSite)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cookiePartitionKeyFromJSON(json: JSONObject) = CookiePartitionKey(
|
||||||
|
topLevelSite = json.getString("topLevelSite")
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun cookieFromJSON(json: JSONObject): Cookie {
|
||||||
|
val partitionKeyJson = json.getValueOrNull("partitionKey") as JSONObject?
|
||||||
|
val partitionKey = partitionKeyJson?.takeUnless { it.length() == 0 }?.let {
|
||||||
|
cookiePartitionKeyFromJSON(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json.isNull(key)) {
|
return Cookie(
|
||||||
return json.get(key)
|
domain = json.getString("domain"),
|
||||||
}
|
expirationDate = (json.getValueOrNull("expirationDate") as Int?)?.toLong(),
|
||||||
|
firstPartyDomain = json.getString("firstPartyDomain"),
|
||||||
return null
|
hostOnly = json.getBoolean("hostOnly"),
|
||||||
}
|
httpOnly = json.getBoolean("httpOnly"),
|
||||||
|
name = json.getString("name"),
|
||||||
private fun cookiePartitionKeyFromJSON(inputJSON: JSONObject): CookiePartitionKey {
|
|
||||||
return CookiePartitionKey(
|
|
||||||
topLevelSite = inputJSON.getString("topLevelSite")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun CookiePartitionKey.toJSON(): JSONObject {
|
|
||||||
val json = JSONObject()
|
|
||||||
json.put("topLevelSite", topLevelSite)
|
|
||||||
return json
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cookieFromJSON(inputJSON: JSONObject): Cookie {
|
|
||||||
val partitionKeyRaw = toValueOrNull(inputJSON, "partitionKey") as JSONObject?
|
|
||||||
val partitionKey = if (partitionKeyRaw == null || partitionKeyRaw.length() == 0) null
|
|
||||||
else cookiePartitionKeyFromJSON(partitionKeyRaw)
|
|
||||||
|
|
||||||
return Cookie (
|
|
||||||
domain = inputJSON.getString("domain"),
|
|
||||||
expirationDate = (toValueOrNull(inputJSON, "expirationDate") as Int?)?.toLong(),
|
|
||||||
firstPartyDomain = inputJSON.getString("firstPartyDomain"),
|
|
||||||
hostOnly = inputJSON.getBoolean("hostOnly"),
|
|
||||||
httpOnly = inputJSON.getBoolean("httpOnly"),
|
|
||||||
name = inputJSON.getString("name"),
|
|
||||||
partitionKey = partitionKey,
|
partitionKey = partitionKey,
|
||||||
path = inputJSON.getString("path"),
|
path = json.getString("path"),
|
||||||
secure = inputJSON.getBoolean("secure"),
|
secure = json.getBoolean("secure"),
|
||||||
session = inputJSON.getBoolean("session"),
|
session = json.getBoolean("session"),
|
||||||
sameSite = when(inputJSON.getString("sameSite")) {
|
sameSite = parseSameSiteStatus(json.getString("sameSite")),
|
||||||
"no_restriction" -> CookieSameSiteStatus.NO_RESTRICTION
|
storeId = json.getString("storeId"),
|
||||||
"lax" -> CookieSameSiteStatus.LAX
|
value = json.getString("value")
|
||||||
"strict" -> CookieSameSiteStatus.STRICT
|
|
||||||
else -> CookieSameSiteStatus.UNSPECIFIED
|
|
||||||
},
|
|
||||||
storeId = inputJSON.getString("storeId"),
|
|
||||||
value = inputJSON.getString("value")
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun parseSameSiteStatus(status: String) = when(status) {
|
||||||
|
"no_restriction" -> CookieSameSiteStatus.NO_RESTRICTION
|
||||||
|
"lax" -> CookieSameSiteStatus.LAX
|
||||||
|
"strict" -> CookieSameSiteStatus.STRICT
|
||||||
|
else -> CookieSameSiteStatus.UNSPECIFIED
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sameSiteToString(status: CookieSameSiteStatus) = when(status) {
|
||||||
|
CookieSameSiteStatus.NO_RESTRICTION -> "no_restriction"
|
||||||
|
CookieSameSiteStatus.LAX -> "lax"
|
||||||
|
CookieSameSiteStatus.STRICT -> "strict"
|
||||||
|
CookieSameSiteStatus.UNSPECIFIED -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createBaseArgs(
|
||||||
|
firstPartyDomain: String?,
|
||||||
|
partitionKey: CookiePartitionKey?,
|
||||||
|
storeId: String?,
|
||||||
|
url: String
|
||||||
|
) = JSONObject().apply {
|
||||||
|
putNullable("firstPartyDomain", firstPartyDomain)
|
||||||
|
putNullable("partitionKey", partitionKey?.toJSON())
|
||||||
|
putNullable("storeId", storeId)
|
||||||
|
put("url", url)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRequest(
|
||||||
|
action: String,
|
||||||
|
args: JSONObject,
|
||||||
|
callback: (Result<Unit>) -> Unit
|
||||||
|
) {
|
||||||
|
CookieManagerFeature.scheduleRequest(action, args, object : ResultConsumer<JSONObject> {
|
||||||
|
override fun success(result: JSONObject) {
|
||||||
|
callback(Result.success(Unit))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
||||||
|
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
override fun getCookie(
|
override fun getCookie(
|
||||||
firstPartyDomain: String?,
|
firstPartyDomain: String?,
|
||||||
name: String,
|
name: String,
|
||||||
@@ -68,30 +100,11 @@ class GeckoCookieApiImpl : GeckoCookieApi {
|
|||||||
url: String,
|
url: String,
|
||||||
callback: (Result<Cookie>) -> Unit
|
callback: (Result<Cookie>) -> Unit
|
||||||
) {
|
) {
|
||||||
val args = JSONObject()
|
val args = createBaseArgs(firstPartyDomain, partitionKey, storeId, url).apply {
|
||||||
|
put("name", name)
|
||||||
if (firstPartyDomain == null) {
|
|
||||||
args.put("firstPartyDomain", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("firstPartyDomain", firstPartyDomain)
|
|
||||||
}
|
|
||||||
args.put("name", name)
|
|
||||||
|
|
||||||
if (partitionKey == null) {
|
|
||||||
args.put("partitionKey", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("partitionKey", partitionKey.toJSON())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storeId == null) {
|
CookieManagerFeature.scheduleRequest("get", args, object : ResultConsumer<JSONObject> {
|
||||||
args.put("storeId", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("storeId", storeId)
|
|
||||||
}
|
|
||||||
|
|
||||||
args.put("url", url)
|
|
||||||
|
|
||||||
CookieManagerFeature.scheduleRequest("get", args, object: ResultConsumer<JSONObject> {
|
|
||||||
override fun success(result: JSONObject) {
|
override fun success(result: JSONObject) {
|
||||||
callback(Result.success(cookieFromJSON(result.getJSONObject("result"))))
|
callback(Result.success(cookieFromJSON(result.getJSONObject("result"))))
|
||||||
}
|
}
|
||||||
@@ -99,7 +112,6 @@ class GeckoCookieApiImpl : GeckoCookieApi {
|
|||||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
||||||
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
|
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,53 +124,22 @@ class GeckoCookieApiImpl : GeckoCookieApi {
|
|||||||
url: String,
|
url: String,
|
||||||
callback: (Result<List<Cookie>>) -> Unit
|
callback: (Result<List<Cookie>>) -> Unit
|
||||||
) {
|
) {
|
||||||
val args = JSONObject()
|
val args = createBaseArgs(firstPartyDomain, partitionKey, storeId, url).apply {
|
||||||
|
putNullable("domain", domain)
|
||||||
if (domain == null) {
|
putNullable("name", name)
|
||||||
args.put("domain", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("domain", domain)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstPartyDomain == null) {
|
CookieManagerFeature.scheduleRequest("getAll", args, object : ResultConsumer<JSONObject> {
|
||||||
args.put("firstPartyDomain", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("firstPartyDomain", firstPartyDomain)
|
|
||||||
}
|
|
||||||
|
|
||||||
args.put("name", name)
|
|
||||||
|
|
||||||
if (partitionKey == null) {
|
|
||||||
args.put("partitionKey", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("partitionKey", partitionKey.toJSON())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storeId == null) {
|
|
||||||
args.put("storeId", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("storeId", storeId)
|
|
||||||
}
|
|
||||||
|
|
||||||
args.put("url", url)
|
|
||||||
|
|
||||||
CookieManagerFeature.scheduleRequest("getAll", args, object: ResultConsumer<JSONObject> {
|
|
||||||
override fun success(result: JSONObject) {
|
override fun success(result: JSONObject) {
|
||||||
val jsonArray = result.getJSONArray("result")
|
val cookies = result.getJSONArray("result").let { jsonArray ->
|
||||||
val cookies: MutableList<Cookie> = mutableListOf()
|
List(jsonArray.length()) { cookieFromJSON(jsonArray.getJSONObject(it)) }
|
||||||
|
|
||||||
repeat(jsonArray.length()) {
|
|
||||||
index ->
|
|
||||||
cookies.add(cookieFromJSON(jsonArray.getJSONObject(index)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(Result.success(cookies))
|
callback(Result.success(cookies))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
||||||
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
|
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,90 +158,18 @@ class GeckoCookieApiImpl : GeckoCookieApi {
|
|||||||
value: String?,
|
value: String?,
|
||||||
callback: (Result<Unit>) -> Unit
|
callback: (Result<Unit>) -> Unit
|
||||||
) {
|
) {
|
||||||
val args = JSONObject()
|
val args = createBaseArgs(firstPartyDomain, partitionKey, storeId, url).apply {
|
||||||
|
putNullable("domain", domain)
|
||||||
if (domain == null) {
|
putNullable("expirationDate", expirationDate)
|
||||||
args.put("domain", JSONObject.NULL)
|
putNullable("httpOnly", httpOnly)
|
||||||
} else {
|
putNullable("name", name)
|
||||||
args.put("domain", domain)
|
putNullable("path", path)
|
||||||
|
putNullable("sameSite", sameSite?.let { sameSiteToString(it) })
|
||||||
|
putNullable("secure", secure)
|
||||||
|
putNullable("value", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expirationDate == null) {
|
handleRequest("set", args, callback)
|
||||||
args.put("expirationDate", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("expirationDate", domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstPartyDomain == null) {
|
|
||||||
args.put("firstPartyDomain", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("firstPartyDomain", firstPartyDomain)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (httpOnly == null) {
|
|
||||||
args.put("httpOnly", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("httpOnly", httpOnly)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name == null) {
|
|
||||||
args.put("name", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("name", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (partitionKey == null) {
|
|
||||||
args.put("partitionKey", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("partitionKey", partitionKey.toJSON())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path == null) {
|
|
||||||
args.put("path", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("path", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sameSite == null) {
|
|
||||||
args.put("sameSite", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("sameSite", when(sameSite) {
|
|
||||||
CookieSameSiteStatus.NO_RESTRICTION -> "no_restriction"
|
|
||||||
CookieSameSiteStatus.LAX -> "lax"
|
|
||||||
CookieSameSiteStatus.STRICT -> "strict"
|
|
||||||
CookieSameSiteStatus.UNSPECIFIED -> ""
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (secure == null) {
|
|
||||||
args.put("secure", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("secure", secure)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storeId == null) {
|
|
||||||
args.put("storeId", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("storeId", storeId)
|
|
||||||
}
|
|
||||||
|
|
||||||
args.put("url", url)
|
|
||||||
|
|
||||||
if (value == null) {
|
|
||||||
args.put("value", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("value", value)
|
|
||||||
}
|
|
||||||
|
|
||||||
CookieManagerFeature.scheduleRequest("set", args, object: ResultConsumer<JSONObject> {
|
|
||||||
override fun success(result: JSONObject) {
|
|
||||||
callback(Result.success(Unit))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
|
||||||
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeCookie(
|
override fun removeCookie(
|
||||||
@@ -271,39 +180,10 @@ class GeckoCookieApiImpl : GeckoCookieApi {
|
|||||||
url: String,
|
url: String,
|
||||||
callback: (Result<Unit>) -> Unit
|
callback: (Result<Unit>) -> Unit
|
||||||
) {
|
) {
|
||||||
val args = JSONObject()
|
val args = createBaseArgs(firstPartyDomain, partitionKey, storeId, url).apply {
|
||||||
|
put("name", name)
|
||||||
if (firstPartyDomain == null) {
|
|
||||||
args.put("firstPartyDomain", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("firstPartyDomain", firstPartyDomain)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args.put("name", name)
|
handleRequest("remove", args, callback)
|
||||||
|
|
||||||
if (partitionKey == null) {
|
|
||||||
args.put("partitionKey", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("partitionKey", partitionKey.toJSON())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storeId == null) {
|
|
||||||
args.put("storeId", JSONObject.NULL)
|
|
||||||
} else {
|
|
||||||
args.put("storeId", storeId)
|
|
||||||
}
|
|
||||||
|
|
||||||
args.put("url", url)
|
|
||||||
|
|
||||||
CookieManagerFeature.scheduleRequest("remove", args, object: ResultConsumer<JSONObject> {
|
|
||||||
override fun success(result: JSONObject) {
|
|
||||||
callback(Result.success(Unit))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
|
||||||
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
+19
-3
@@ -3,11 +3,27 @@ package eu.lensai.flutter_mozilla_components.api
|
|||||||
import eu.lensai.flutter_mozilla_components.GlobalComponents
|
import eu.lensai.flutter_mozilla_components.GlobalComponents
|
||||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
|
import eu.lensai.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
|
||||||
import mozilla.components.concept.engine.Engine
|
import mozilla.components.concept.engine.Engine
|
||||||
|
import mozilla.components.feature.addons.logger
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of GeckoEngineSettingsApi that manages engine-specific settings
|
||||||
|
*/
|
||||||
class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
|
class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
|
||||||
private val engine: Engine by lazy { GlobalComponents.components!!.engine }
|
companion object {
|
||||||
|
private const val TAG = "GeckoEngineSettingsApi"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
override fun javaScriptEnabled(state: Boolean) {
|
override fun javaScriptEnabled(state: Boolean) {
|
||||||
engine.settings.javascriptEnabled = state
|
try {
|
||||||
|
components.core.engine.settings.javascriptEnabled = state
|
||||||
|
logger.debug("$TAG: JavaScript enabled state changed to: $state")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("$TAG: Failed to set JavaScript enabled state", e)
|
||||||
|
throw IllegalStateException("Failed to set JavaScript enabled state", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -7,17 +7,19 @@ import mozilla.components.browser.state.state.BrowserState
|
|||||||
import mozilla.components.concept.engine.EngineSession
|
import mozilla.components.concept.engine.EngineSession
|
||||||
|
|
||||||
class GeckoFindApiImpl : GeckoFindApi {
|
class GeckoFindApiImpl : GeckoFindApi {
|
||||||
private val state: BrowserState by lazy { GlobalComponents.components!!.store.state }
|
private val components by lazy {
|
||||||
|
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||||
|
}
|
||||||
|
|
||||||
private fun sessionByTabId(tabId: String?) : EngineSession? {
|
private fun sessionByTabId(tabId: String?) : EngineSession? {
|
||||||
val loadSessionId = tabId
|
val loadSessionId = tabId
|
||||||
?: state.selectedTabId
|
?: components.core.store.state.selectedTabId
|
||||||
|
|
||||||
if (loadSessionId == null) {
|
if (loadSessionId == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val tab = state.findTabOrCustomTab(loadSessionId)
|
val tab = components.core.store.state.findTabOrCustomTab(loadSessionId)
|
||||||
return tab?.engineState?.engineSession
|
return tab?.engineState?.engineSession
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user