everything build but untested & migration not finished
This commit is contained in:
@@ -25,7 +25,7 @@ if (flutterVersionName == null) {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "me.movenext.bang_navigator"
|
namespace = "me.movenext.bang_navigator"
|
||||||
compileSdk = 34
|
compileSdk = 35
|
||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
@@ -43,7 +43,7 @@ android {
|
|||||||
// https://api.flutter.dev/flutter/widgets/AndroidView-class.html
|
// https://api.flutter.dev/flutter/widgets/AndroidView-class.html
|
||||||
//https://inappwebview.dev/docs/intro/#setup-android
|
//https://inappwebview.dev/docs/intro/#setup-android
|
||||||
minSdk = 23
|
minSdk = 23
|
||||||
targetSdk = 34
|
targetSdk = 35
|
||||||
versionCode = flutterVersionCode.toInteger()
|
versionCode = flutterVersionCode.toInteger()
|
||||||
versionName = flutterVersionName
|
versionName = flutterVersionName
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
// implementation 'androidx.glance:glance-appwidget:1.0.0'
|
// implementation 'androidx.glance:glance-appwidget:1.0.0'
|
||||||
implementation 'com.google.android.material:material:1.11.0'
|
implementation 'com.google.android.material:material:1.12.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version "7.3.0" apply false
|
id "com.android.application" version "8.3.1" apply false
|
||||||
id "org.jetbrains.kotlin.android" version "1.9.22" apply false
|
id "org.jetbrains.kotlin.android" version "1.9.22" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
../../js/readability/dist/readability.min.js.gz
|
|
||||||
@@ -8,14 +8,14 @@ import 'package:lensai/features/bangs/presentation/screens/search.dart';
|
|||||||
import 'package:lensai/features/chat_archive/presentation/screens/detail.dart';
|
import 'package:lensai/features/chat_archive/presentation/screens/detail.dart';
|
||||||
import 'package:lensai/features/chat_archive/presentation/screens/list.dart';
|
import 'package:lensai/features/chat_archive/presentation/screens/list.dart';
|
||||||
import 'package:lensai/features/chat_archive/presentation/screens/search.dart';
|
import 'package:lensai/features/chat_archive/presentation/screens/search.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/screens/browser.dart';
|
import 'package:lensai/features/geckoview/features/browser/screens/browser.dart';
|
||||||
import 'package:lensai/features/settings/presentation/screens/settings.dart';
|
|
||||||
import 'package:lensai/features/geckoview/features/topics/presentation/screens/topic_list.dart';
|
import 'package:lensai/features/geckoview/features/topics/presentation/screens/topic_list.dart';
|
||||||
|
import 'package:lensai/features/settings/presentation/screens/settings.dart';
|
||||||
|
|
||||||
part 'routes.g.dart';
|
part 'routes.g.dart';
|
||||||
|
|
||||||
@TypedGoRoute<KagiRoute>(
|
@TypedGoRoute<BrowserRoute>(
|
||||||
name: 'KagiRoute',
|
name: 'BrowserRoute',
|
||||||
path: '/',
|
path: '/',
|
||||||
routes: [
|
routes: [
|
||||||
TypedGoRoute<AboutRoute>(
|
TypedGoRoute<AboutRoute>(
|
||||||
@@ -48,10 +48,10 @@ part 'routes.g.dart';
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
class KagiRoute extends GoRouteData {
|
class BrowserRoute extends GoRouteData {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, GoRouterState state) {
|
Widget build(BuildContext context, GoRouterState state) {
|
||||||
return const KagiScreen();
|
return const BrowserScreen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ part of 'routes.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
List<RouteBase> get $appRoutes => [
|
List<RouteBase> get $appRoutes => [
|
||||||
$kagiRoute,
|
$browserRoute,
|
||||||
$settingsRoute,
|
$settingsRoute,
|
||||||
$chatArchiveListRoute,
|
$chatArchiveListRoute,
|
||||||
];
|
];
|
||||||
|
|
||||||
RouteBase get $kagiRoute => GoRouteData.$route(
|
RouteBase get $browserRoute => GoRouteData.$route(
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'KagiRoute',
|
name: 'BrowserRoute',
|
||||||
factory: $KagiRouteExtension._fromState,
|
factory: $BrowserRouteExtension._fromState,
|
||||||
routes: [
|
routes: [
|
||||||
GoRouteData.$route(
|
GoRouteData.$route(
|
||||||
path: 'about',
|
path: 'about',
|
||||||
@@ -54,8 +54,8 @@ RouteBase get $kagiRoute => GoRouteData.$route(
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
extension $KagiRouteExtension on KagiRoute {
|
extension $BrowserRouteExtension on BrowserRoute {
|
||||||
static KagiRoute _fromState(GoRouterState state) => KagiRoute();
|
static BrowserRoute _fromState(GoRouterState state) => BrowserRoute();
|
||||||
|
|
||||||
String get location => GoRouteData.$location(
|
String get location => GoRouteData.$location(
|
||||||
'/',
|
'/',
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ import 'package:lensai/features/bangs/data/models/bang.dart';
|
|||||||
import 'package:lensai/features/bangs/domain/repositories/sync.dart';
|
import 'package:lensai/features/bangs/domain/repositories/sync.dart';
|
||||||
import 'package:lensai/features/content_block/data/models/host.dart';
|
import 'package:lensai/features/content_block/data/models/host.dart';
|
||||||
import 'package:lensai/features/content_block/domain/repositories/sync.dart';
|
import 'package:lensai/features/content_block/domain/repositories/sync.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/services/session.dart';
|
import 'package:lensai/features/kagi/data/services/session.dart';
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'app_initialization.g.dart';
|
part 'app_initialization.g.dart';
|
||||||
@@ -77,15 +76,11 @@ class AppInitializationService extends _$AppInitializationService {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (settings.incognitoMode) {
|
|
||||||
await ref.read(sessionServiceProvider.notifier).clearAllData();
|
|
||||||
//Delete all unsasigned tabs
|
|
||||||
await ref.read(tabDatabaseProvider).tabDao.deleteTopicTabs(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings.kagiSession case final String session) {
|
if (settings.kagiSession case final String session) {
|
||||||
if (session.isNotEmpty) {
|
if (session.isNotEmpty) {
|
||||||
await ref.read(sessionServiceProvider.notifier).setKagiSession(session);
|
await ref
|
||||||
|
.read(kagiSessionServiceProvider.notifier)
|
||||||
|
.setKagiSession(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'app_initialization.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$appInitializationServiceHash() =>
|
String _$appInitializationServiceHash() =>
|
||||||
r'eee9c8eadc793fb435af1032ad2099dfd381a034';
|
r'0d7dc3eb3ed2e17643f4c34e4e172734ed8d09e2';
|
||||||
|
|
||||||
/// See also [AppInitializationService].
|
/// See also [AppInitializationService].
|
||||||
@ProviderFor(AppInitializationService)
|
@ProviderFor(AppInitializationService)
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
|
||||||
import 'package:lensai/features/bangs/data/database/database.dart';
|
import 'package:lensai/features/bangs/data/database/database.dart';
|
||||||
import 'package:lensai/features/bangs/data/models/bang.dart';
|
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';
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:lensai/core/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.dart';
|
||||||
import 'package:lensai/features/bangs/domain/providers.dart';
|
import 'package:lensai/features/bangs/domain/providers.dart';
|
||||||
import 'package:lensai/features/bangs/presentation/widgets/bang_details.dart';
|
import 'package:lensai/features/bangs/presentation/widgets/bang_details.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/domain/entities/sheet.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/controllers/bottom_sheet.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/entities/sheet.dart';
|
|
||||||
import 'package:lensai/features/search_browser/domain/providers.dart';
|
|
||||||
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
||||||
|
|
||||||
class BangListScreen extends HookConsumerWidget {
|
class BangListScreen extends HookConsumerWidget {
|
||||||
@@ -49,15 +50,16 @@ class BangListScreen extends HookConsumerWidget {
|
|||||||
.read(selectedBangTriggerProvider().notifier)
|
.read(selectedBangTriggerProvider().notifier)
|
||||||
.setTrigger(bang.trigger);
|
.setTrigger(bang.trigger);
|
||||||
|
|
||||||
if (ref.read(bottomSheetProvider) is! CreateTabSheet) {
|
if (ref.read(bottomSheetControllerProvider)
|
||||||
ref.read(bottomSheetProvider.notifier).show(
|
is! CreateTabSheet) {
|
||||||
|
ref.read(bottomSheetControllerProvider.notifier).show(
|
||||||
CreateTabSheet(
|
CreateTabSheet(
|
||||||
preferredTool: KagiTool.search,
|
preferredTool: KagiTool.search,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.go(KagiRoute().location);
|
context.go(BrowserRoute().location);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:lensai/core/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.dart';
|
||||||
import 'package:lensai/features/bangs/domain/repositories/search.dart';
|
import 'package:lensai/features/bangs/domain/repositories/search.dart';
|
||||||
import 'package:lensai/features/bangs/presentation/widgets/bang_details.dart';
|
import 'package:lensai/features/bangs/presentation/widgets/bang_details.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/domain/entities/sheet.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/controllers/bottom_sheet.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/entities/sheet.dart';
|
|
||||||
import 'package:lensai/features/search_browser/domain/providers.dart';
|
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/presentation/hooks/listenable_callback.dart';
|
import 'package:lensai/presentation/hooks/listenable_callback.dart';
|
||||||
@@ -77,13 +78,14 @@ class BangSearchScreen extends HookConsumerWidget {
|
|||||||
.read(selectedBangTriggerProvider().notifier)
|
.read(selectedBangTriggerProvider().notifier)
|
||||||
.setTrigger(bang.trigger);
|
.setTrigger(bang.trigger);
|
||||||
|
|
||||||
if (ref.read(bottomSheetProvider) is! CreateTabSheet) {
|
if (ref.read(bottomSheetControllerProvider)
|
||||||
ref.read(bottomSheetProvider.notifier).show(
|
is! CreateTabSheet) {
|
||||||
|
ref.read(bottomSheetControllerProvider.notifier).show(
|
||||||
CreateTabSheet(preferredTool: KagiTool.search),
|
CreateTabSheet(preferredTool: KagiTool.search),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.go(KagiRoute().location);
|
context.go(BrowserRoute().location);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:lensai/core/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.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/presentation/widgets/bang_icon.dart';
|
import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/utils/ui_helper.dart' as ui_helper;
|
import 'package:lensai/utils/ui_helper.dart' as ui_helper;
|
||||||
@@ -82,11 +83,11 @@ class BangDetails extends HookConsumerWidget {
|
|||||||
await ui_helper.launchUrlFeedback(context, url);
|
await ui_helper.launchUrlFeedback(context, url);
|
||||||
} else {
|
} else {
|
||||||
await ref
|
await ref
|
||||||
.read(switchNewTabControllerProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
.add(url);
|
.addTab(url: url);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.go(KagiRoute().location);
|
context.go(BrowserRoute().location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||||
import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart';
|
import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/speech_to_text_button.dart';
|
||||||
import 'package:lensai/features/kagi/domain/repositories/autosuggest.dart';
|
import 'package:lensai/features/kagi/domain/repositories/autosuggest.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/speech_to_text_button.dart';
|
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/presentation/widgets/autocomplete.dart';
|
import 'package:lensai/presentation/widgets/autocomplete.dart';
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ 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/presentation/widgets/bang_icon.dart';
|
import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart';
|
||||||
import 'package:lensai/features/bangs/presentation/widgets/search_field.dart';
|
import 'package:lensai/features/bangs/presentation/widgets/search_field.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/providers.dart';
|
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/controllers/overlay_dialog.dart';
|
||||||
import 'package:lensai/presentation/widgets/selectable_chips.dart';
|
import 'package:lensai/presentation/widgets/selectable_chips.dart';
|
||||||
|
|
||||||
class SiteSearch extends HookConsumerWidget {
|
class SiteSearch extends HookConsumerWidget {
|
||||||
@@ -39,10 +41,10 @@ class SiteSearch extends HookConsumerWidget {
|
|||||||
.increaseFrequency(activeBang.trigger);
|
.increaseFrequency(activeBang.trigger);
|
||||||
|
|
||||||
await ref
|
await ref
|
||||||
.read(switchNewTabControllerProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
.add(activeBang.getUrl(textController.text));
|
.addTab(url: activeBang.getUrl(textController.text));
|
||||||
|
|
||||||
ref.read(overlayDialogProvider.notifier).dismiss();
|
ref.read(overlayDialogControllerProvider.notifier).dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:lensai/core/logger.dart';
|
import 'package:lensai/core/logger.dart';
|
||||||
import 'package:lensai/features/chat_archive/data/database/database.dart';
|
import 'package:lensai/features/chat_archive/data/database/database.dart';
|
||||||
import 'package:lensai/features/chat_archive/data/providers.dart';
|
import 'package:lensai/features/chat_archive/data/providers.dart';
|
||||||
@@ -53,7 +52,7 @@ class ChatArchiveSearchRepository extends _$ChatArchiveSearchRepository {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return availableChats.whereNotNull();
|
return availableChats.nonNulls;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> search(
|
Future<void> search(
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'search.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$chatArchiveSearchRepositoryHash() =>
|
String _$chatArchiveSearchRepositoryHash() =>
|
||||||
r'6cb31ab2c4a37561ec17a60dae3bb4ecd3893744';
|
r'a3decc7975bf49995b20ea578db3c08b69f7c03c';
|
||||||
|
|
||||||
/// See also [ChatArchiveSearchRepository].
|
/// See also [ChatArchiveSearchRepository].
|
||||||
@ProviderFor(ChatArchiveSearchRepository)
|
@ProviderFor(ChatArchiveSearchRepository)
|
||||||
|
|||||||
@@ -10,6 +10,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/chat_archive/domain/repositories/archive.dart';
|
import 'package:lensai/features/chat_archive/domain/repositories/archive.dart';
|
||||||
import 'package:lensai/features/chat_archive/utils/markdown_to_text.dart';
|
import 'package:lensai/features/chat_archive/utils/markdown_to_text.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
||||||
@@ -113,11 +114,11 @@ class ChatArchiveDetailScreen extends HookConsumerWidget {
|
|||||||
await ui_helper.launchUrlFeedback(context, Uri.parse(href));
|
await ui_helper.launchUrlFeedback(context, Uri.parse(href));
|
||||||
} else {
|
} else {
|
||||||
await ref
|
await ref
|
||||||
.read(switchNewTabControllerProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
.add(url);
|
.addTab(url: url);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.go(KagiRoute().location);
|
context.go(BrowserRoute().location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import 'package:fading_scroll/fading_scroll.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/extensions/date_time.dart';
|
|
||||||
import 'package:lensai/core/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.dart';
|
||||||
|
import 'package:lensai/extensions/date_time.dart';
|
||||||
import 'package:lensai/features/chat_archive/domain/repositories/archive.dart';
|
import 'package:lensai/features/chat_archive/domain/repositories/archive.dart';
|
||||||
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
||||||
import 'package:skeletonizer/skeletonizer.dart';
|
import 'package:skeletonizer/skeletonizer.dart';
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.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/extensions/date_time.dart';
|
|
||||||
import 'package:lensai/core/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.dart';
|
||||||
|
import 'package:lensai/extensions/date_time.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/chat_archive/domain/repositories/search.dart';
|
import 'package:lensai/features/chat_archive/domain/repositories/search.dart';
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:exceptions/exceptions.dart';
|
import 'package:exceptions/exceptions.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
@@ -30,10 +29,7 @@ class HostSourceService extends _$HostSourceService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final matches = hostRegex.allMatches(utf8.decode(args[0]));
|
final matches = hostRegex.allMatches(utf8.decode(args[0]));
|
||||||
return matches
|
return matches.map((match) => match.group(2)).nonNulls.toSet();
|
||||||
.map((match) => match.group(2))
|
|
||||||
.whereNotNull()
|
|
||||||
.toSet();
|
|
||||||
},
|
},
|
||||||
[response.bodyBytes],
|
[response.bodyBytes],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'source.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$hostSourceServiceHash() => r'26ac09fcd34cc37440eb643075984707e0e9bba3';
|
String _$hostSourceServiceHash() => r'6c1ee7bfde02cc542a4f55db666d49037fda187e';
|
||||||
|
|
||||||
/// See also [HostSourceService].
|
/// See also [HostSourceService].
|
||||||
@ProviderFor(HostSourceService)
|
@ProviderFor(HostSourceService)
|
||||||
|
|||||||
@@ -21,14 +21,14 @@ class BrowserIcon with FastEquatable {
|
|||||||
final image =
|
final image =
|
||||||
await tryDecodeImage(bytes).then((image) => image!.toEquatable());
|
await tryDecodeImage(bytes).then((image) => image!.toEquatable());
|
||||||
|
|
||||||
return BrowserIcon._(
|
return BrowserIcon(
|
||||||
image: image,
|
image: image,
|
||||||
dominantColor: dominantColor,
|
dominantColor: dominantColor,
|
||||||
source: source,
|
source: source,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserIcon._({
|
BrowserIcon({
|
||||||
required this.image,
|
required this.image,
|
||||||
required this.dominantColor,
|
required this.dominantColor,
|
||||||
required this.source,
|
required this.source,
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import 'package:fast_equatable/fast_equatable.dart';
|
||||||
|
|
||||||
|
class FindResultState with FastEquatable {
|
||||||
|
final int activeMatchOrdinal;
|
||||||
|
final int numberOfMatches;
|
||||||
|
final bool isDoneCounting;
|
||||||
|
|
||||||
|
FindResultState({
|
||||||
|
required this.activeMatchOrdinal,
|
||||||
|
required this.numberOfMatches,
|
||||||
|
required this.isDoneCounting,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory FindResultState.$default() => FindResultState(
|
||||||
|
activeMatchOrdinal: -1,
|
||||||
|
numberOfMatches: 0,
|
||||||
|
isDoneCounting: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get hashParameters => [
|
||||||
|
activeMatchOrdinal,
|
||||||
|
numberOfMatches,
|
||||||
|
isDoneCounting,
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get cacheHash => true;
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
import 'package:copy_with_extension/copy_with_extension.dart';
|
import 'package:copy_with_extension/copy_with_extension.dart';
|
||||||
import 'package:fast_equatable/fast_equatable.dart';
|
import 'package:fast_equatable/fast_equatable.dart';
|
||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:lensai/data/models/web_page_info.dart';
|
||||||
import 'package:lensai/domain/entities/equatable_image.dart';
|
import 'package:lensai/domain/entities/equatable_image.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/entities/browser_icon.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/entities/find_result_state.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/entities/history_state.dart';
|
import 'package:lensai/features/geckoview/domain/entities/history_state.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/entities/readerable_state.dart';
|
import 'package:lensai/features/geckoview/domain/entities/readerable_state.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/entities/security_state.dart';
|
import 'package:lensai/features/geckoview/domain/entities/security_state.dart';
|
||||||
@@ -8,16 +12,28 @@ import 'package:lensai/features/geckoview/domain/entities/security_state.dart';
|
|||||||
part 'tab_state.g.dart';
|
part 'tab_state.g.dart';
|
||||||
|
|
||||||
@CopyWith()
|
@CopyWith()
|
||||||
class TabState with FastEquatable {
|
class TabState with FastEquatable implements WebPageInfo {
|
||||||
@CopyWithField(immutable: true)
|
@CopyWithField(immutable: true)
|
||||||
final String id;
|
final String id;
|
||||||
|
|
||||||
final String? contextId;
|
final String? contextId;
|
||||||
|
|
||||||
|
@override
|
||||||
final Uri url;
|
final Uri url;
|
||||||
|
@override
|
||||||
final String title;
|
final String title;
|
||||||
|
|
||||||
final EquatableImage? icon;
|
final EquatableImage? icon;
|
||||||
|
|
||||||
|
@override
|
||||||
|
BrowserIcon? get favicon => (icon != null)
|
||||||
|
? BrowserIcon(
|
||||||
|
image: icon!,
|
||||||
|
dominantColor: null,
|
||||||
|
source: IconSource.memory,
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
final EquatableImage? thumbnail;
|
final EquatableImage? thumbnail;
|
||||||
|
|
||||||
final int progress;
|
final int progress;
|
||||||
@@ -29,6 +45,7 @@ class TabState with FastEquatable {
|
|||||||
final SecurityState securityInfoState;
|
final SecurityState securityInfoState;
|
||||||
final HistoryState historyState;
|
final HistoryState historyState;
|
||||||
final ReaderableState readerableState;
|
final ReaderableState readerableState;
|
||||||
|
final FindResultState findResultState;
|
||||||
|
|
||||||
TabState({
|
TabState({
|
||||||
required this.id,
|
required this.id,
|
||||||
@@ -44,6 +61,7 @@ class TabState with FastEquatable {
|
|||||||
required this.securityInfoState,
|
required this.securityInfoState,
|
||||||
required this.historyState,
|
required this.historyState,
|
||||||
required this.readerableState,
|
required this.readerableState,
|
||||||
|
required this.findResultState,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory TabState.$default(String tabId) => TabState(
|
factory TabState.$default(String tabId) => TabState(
|
||||||
@@ -60,6 +78,7 @@ class TabState with FastEquatable {
|
|||||||
securityInfoState: SecurityState.$default(),
|
securityInfoState: SecurityState.$default(),
|
||||||
historyState: HistoryState.$default(),
|
historyState: HistoryState.$default(),
|
||||||
readerableState: ReaderableState.$default(),
|
readerableState: ReaderableState.$default(),
|
||||||
|
findResultState: FindResultState.$default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -80,5 +99,6 @@ class TabState with FastEquatable {
|
|||||||
securityInfoState,
|
securityInfoState,
|
||||||
historyState,
|
historyState,
|
||||||
readerableState,
|
readerableState,
|
||||||
|
findResultState,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ abstract class _$TabStateCWProxy {
|
|||||||
|
|
||||||
TabState readerableState(ReaderableState readerableState);
|
TabState readerableState(ReaderableState readerableState);
|
||||||
|
|
||||||
|
TabState findResultState(FindResultState findResultState);
|
||||||
|
|
||||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TabState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TabState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||||
///
|
///
|
||||||
/// Usage
|
/// Usage
|
||||||
@@ -50,6 +52,7 @@ abstract class _$TabStateCWProxy {
|
|||||||
SecurityState? securityInfoState,
|
SecurityState? securityInfoState,
|
||||||
HistoryState? historyState,
|
HistoryState? historyState,
|
||||||
ReaderableState? readerableState,
|
ReaderableState? readerableState,
|
||||||
|
FindResultState? findResultState,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +101,10 @@ class _$TabStateCWProxyImpl implements _$TabStateCWProxy {
|
|||||||
TabState readerableState(ReaderableState readerableState) =>
|
TabState readerableState(ReaderableState readerableState) =>
|
||||||
this(readerableState: readerableState);
|
this(readerableState: readerableState);
|
||||||
|
|
||||||
|
@override
|
||||||
|
TabState findResultState(FindResultState findResultState) =>
|
||||||
|
this(findResultState: findResultState);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
||||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TabState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TabState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||||
@@ -119,6 +126,7 @@ class _$TabStateCWProxyImpl implements _$TabStateCWProxy {
|
|||||||
Object? securityInfoState = const $CopyWithPlaceholder(),
|
Object? securityInfoState = const $CopyWithPlaceholder(),
|
||||||
Object? historyState = const $CopyWithPlaceholder(),
|
Object? historyState = const $CopyWithPlaceholder(),
|
||||||
Object? readerableState = const $CopyWithPlaceholder(),
|
Object? readerableState = const $CopyWithPlaceholder(),
|
||||||
|
Object? findResultState = const $CopyWithPlaceholder(),
|
||||||
}) {
|
}) {
|
||||||
return TabState(
|
return TabState(
|
||||||
id: _value.id,
|
id: _value.id,
|
||||||
@@ -174,6 +182,11 @@ class _$TabStateCWProxyImpl implements _$TabStateCWProxy {
|
|||||||
? _value.readerableState
|
? _value.readerableState
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
: readerableState as ReaderableState,
|
: readerableState as ReaderableState,
|
||||||
|
findResultState: findResultState == const $CopyWithPlaceholder() ||
|
||||||
|
findResultState == null
|
||||||
|
? _value.findResultState
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: findResultState as FindResultState,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/entities/tab_state.dart';
|
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/repositories/selected_tab.dart';
|
|
||||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
|
||||||
import 'package:lensai/features/geckoview/domain/repositories/tab_session.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
@@ -18,23 +15,6 @@ GeckoEventService eventService(EventServiceRef ref) {
|
|||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
|
||||||
TabState? tabState(TabStateRef ref, String? tabId) {
|
|
||||||
if (tabId == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ref.watch(
|
|
||||||
tabRepositoryProvider.select((tabs) => tabs[tabId]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod()
|
|
||||||
TabState? selectedTabState(SelectedTabStateRef ref) {
|
|
||||||
final tabId = ref.watch(selectedTabControllerProvider);
|
|
||||||
return ref.watch(tabStateProvider(tabId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
TabSession selectedTabSessionNotifier(SelectedTabSessionNotifierRef ref) {
|
TabSession selectedTabSessionNotifier(SelectedTabSessionNotifierRef ref) {
|
||||||
return ref.watch(tabSessionProvider(null).notifier);
|
return ref.watch(tabSessionProvider(null).notifier);
|
||||||
|
|||||||
@@ -20,169 +20,6 @@ final eventServiceProvider = Provider<GeckoEventService>.internal(
|
|||||||
);
|
);
|
||||||
|
|
||||||
typedef EventServiceRef = ProviderRef<GeckoEventService>;
|
typedef EventServiceRef = ProviderRef<GeckoEventService>;
|
||||||
String _$tabStateHash() => r'6985f5472625a9cf44c8bbc61e61b7577eb60e71';
|
|
||||||
|
|
||||||
/// 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [tabState].
|
|
||||||
@ProviderFor(tabState)
|
|
||||||
const tabStateProvider = TabStateFamily();
|
|
||||||
|
|
||||||
/// See also [tabState].
|
|
||||||
class TabStateFamily extends Family<TabState?> {
|
|
||||||
/// See also [tabState].
|
|
||||||
const TabStateFamily();
|
|
||||||
|
|
||||||
/// See also [tabState].
|
|
||||||
TabStateProvider call(
|
|
||||||
String? tabId,
|
|
||||||
) {
|
|
||||||
return TabStateProvider(
|
|
||||||
tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
TabStateProvider getProviderOverride(
|
|
||||||
covariant TabStateProvider provider,
|
|
||||||
) {
|
|
||||||
return call(
|
|
||||||
provider.tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'tabStateProvider';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [tabState].
|
|
||||||
class TabStateProvider extends AutoDisposeProvider<TabState?> {
|
|
||||||
/// See also [tabState].
|
|
||||||
TabStateProvider(
|
|
||||||
String? tabId,
|
|
||||||
) : this._internal(
|
|
||||||
(ref) => tabState(
|
|
||||||
ref as TabStateRef,
|
|
||||||
tabId,
|
|
||||||
),
|
|
||||||
from: tabStateProvider,
|
|
||||||
name: r'tabStateProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$tabStateHash,
|
|
||||||
dependencies: TabStateFamily._dependencies,
|
|
||||||
allTransitiveDependencies: TabStateFamily._allTransitiveDependencies,
|
|
||||||
tabId: tabId,
|
|
||||||
);
|
|
||||||
|
|
||||||
TabStateProvider._internal(
|
|
||||||
super._createNotifier, {
|
|
||||||
required super.name,
|
|
||||||
required super.dependencies,
|
|
||||||
required super.allTransitiveDependencies,
|
|
||||||
required super.debugGetCreateSourceHash,
|
|
||||||
required super.from,
|
|
||||||
required this.tabId,
|
|
||||||
}) : super.internal();
|
|
||||||
|
|
||||||
final String? tabId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Override overrideWith(
|
|
||||||
TabState? Function(TabStateRef provider) create,
|
|
||||||
) {
|
|
||||||
return ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
override: TabStateProvider._internal(
|
|
||||||
(ref) => create(ref as TabStateRef),
|
|
||||||
from: from,
|
|
||||||
name: null,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
debugGetCreateSourceHash: null,
|
|
||||||
tabId: tabId,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
AutoDisposeProviderElement<TabState?> createElement() {
|
|
||||||
return _TabStateProviderElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is TabStateProvider && other.tabId == tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, tabId.hashCode);
|
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mixin TabStateRef on AutoDisposeProviderRef<TabState?> {
|
|
||||||
/// The parameter `tabId` of this provider.
|
|
||||||
String? get tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TabStateProviderElement extends AutoDisposeProviderElement<TabState?>
|
|
||||||
with TabStateRef {
|
|
||||||
_TabStateProviderElement(super.provider);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get tabId => (origin as TabStateProvider).tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
String _$selectedTabStateHash() => r'd5240ade9010f5c9f00d7a4f419e1b776f75fac1';
|
|
||||||
|
|
||||||
/// See also [selectedTabState].
|
|
||||||
@ProviderFor(selectedTabState)
|
|
||||||
final selectedTabStateProvider = AutoDisposeProvider<TabState?>.internal(
|
|
||||||
selectedTabState,
|
|
||||||
name: r'selectedTabStateProvider',
|
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$selectedTabStateHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef SelectedTabStateRef = AutoDisposeProviderRef<TabState?>;
|
|
||||||
String _$selectedTabSessionNotifierHash() =>
|
String _$selectedTabSessionNotifierHash() =>
|
||||||
r'1b0fe1afa87c0b09fc8407ceb91946fffaef5214';
|
r'1b0fe1afa87c0b09fc8407ceb91946fffaef5214';
|
||||||
|
|
||||||
|
|||||||
+1
-8
@@ -1,19 +1,12 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
|
||||||
import 'package:lensai/features/geckoview/domain/providers.dart';
|
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'selected_tab.g.dart';
|
part 'selected_tab.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
class SelectedTabController extends _$SelectedTabController {
|
class SelectedTab extends _$SelectedTab {
|
||||||
final _tabsService = GeckoTabService();
|
|
||||||
|
|
||||||
Future<void> selectTab(String tabId) {
|
|
||||||
return _tabsService.selectTab(tabId: tabId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? build() {
|
String? build() {
|
||||||
final eventSerivce = ref.watch(eventServiceProvider);
|
final eventSerivce = ref.watch(eventServiceProvider);
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'selected_tab.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$selectedTabHash() => r'd30f0490c7924b7de30e23f3d4d132311bf336d0';
|
||||||
|
|
||||||
|
/// See also [SelectedTab].
|
||||||
|
@ProviderFor(SelectedTab)
|
||||||
|
final selectedTabProvider = NotifierProvider<SelectedTab, String?>.internal(
|
||||||
|
SelectedTab.new,
|
||||||
|
name: r'selectedTabProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product') ? null : _$selectedTabHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$SelectedTab = Notifier<String?>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
+12
@@ -19,6 +19,18 @@ class TabSession extends _$TabSession {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> reload() {
|
||||||
|
return _sessionService.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> goBack() {
|
||||||
|
return _sessionService.goBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> goForward() {
|
||||||
|
return _sessionService.goForward();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void build(String? tabId) {
|
void build(String? tabId) {
|
||||||
_sessionService = (tabId != null)
|
_sessionService = (tabId != null)
|
||||||
+1
-1
@@ -6,7 +6,7 @@ part of 'tab_session.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$tabSessionHash() => r'4aab49dcb544cfc9e7a61b498d2ccf2c28ef729b';
|
String _$tabSessionHash() => r'cdde9c7426178f50dc430284939e215f158e8535';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:lensai/extensions/image.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/entities/find_result_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/entities/history_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/entities/readerable_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/entities/security_state.dart';
|
||||||
|
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/selected_tab.dart';
|
||||||
|
import 'package:lensai/features/geckoview/utils/image_helper.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'tab_state.g.dart';
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class TabStates extends _$TabStates {
|
||||||
|
final _tabsService = GeckoTabService();
|
||||||
|
|
||||||
|
void _onTabListChange(List<String> tabs) {
|
||||||
|
state = {
|
||||||
|
for (final tabId in tabs) tabId: state[tabId] ?? TabState.$default(tabId),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onTabContentStateChange(TabContentState contentState) {
|
||||||
|
final current =
|
||||||
|
state[contentState.id] ?? TabState.$default(contentState.id);
|
||||||
|
|
||||||
|
state = {...state}..[contentState.id] = current.copyWith(
|
||||||
|
contextId: contentState.contextId,
|
||||||
|
url: Uri.parse(contentState.url),
|
||||||
|
title: contentState.title,
|
||||||
|
progress: contentState.progress,
|
||||||
|
isPrivate: contentState.isPrivate,
|
||||||
|
isFullScreen: contentState.isFullScreen,
|
||||||
|
isLoading: contentState.isLoading,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onIconChange(IconEvent event) async {
|
||||||
|
final IconEvent(:tabId, :bytes) = event;
|
||||||
|
|
||||||
|
final current = state[tabId] ?? TabState.$default(tabId);
|
||||||
|
|
||||||
|
final image = (bytes != null)
|
||||||
|
? (await tryDecodeImage(bytes)
|
||||||
|
.then((image) async => image?.toEquatable()))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
state = {...state}..[tabId] = current.copyWith.icon(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onThumbnailChange(ThumbnailEvent event) async {
|
||||||
|
final ThumbnailEvent(:tabId, :bytes) = event;
|
||||||
|
|
||||||
|
final current = state[tabId] ?? TabState.$default(tabId);
|
||||||
|
|
||||||
|
final image = (bytes != null)
|
||||||
|
? (await tryDecodeImage(bytes)
|
||||||
|
.then((image) async => image?.toEquatable()))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
state = {...state}..[tabId] = current.copyWith.thumbnail(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onSecurityInfoStateChange(SecurityInfoEvent event) {
|
||||||
|
final SecurityInfoEvent(:tabId, :securityInfo) = event;
|
||||||
|
|
||||||
|
final current = state[tabId] ?? TabState.$default(tabId);
|
||||||
|
|
||||||
|
state = {...state}..[tabId] = current.copyWith.securityInfoState(
|
||||||
|
SecurityState(
|
||||||
|
secure: securityInfo.secure,
|
||||||
|
host: securityInfo.host,
|
||||||
|
issuer: securityInfo.issuer,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onHistoryStateChange(HistoryEvent event) {
|
||||||
|
final HistoryEvent(:tabId, :history) = event;
|
||||||
|
|
||||||
|
final current = state[tabId] ?? TabState.$default(tabId);
|
||||||
|
|
||||||
|
state = {...state}..[tabId] = current.copyWith.historyState(
|
||||||
|
HistoryState(
|
||||||
|
items: history.items.nonNulls
|
||||||
|
.map(
|
||||||
|
(item) =>
|
||||||
|
HistoryItem(url: Uri.parse(item.url), title: item.title),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
currentIndex: history.currentIndex,
|
||||||
|
canGoBack: history.canGoBack,
|
||||||
|
canGoForward: history.canGoForward,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onReaderableStateChange(ReaderableEvent event) {
|
||||||
|
final ReaderableEvent(:tabId, :readerable) = event;
|
||||||
|
|
||||||
|
final current = state[tabId] ?? TabState.$default(tabId);
|
||||||
|
|
||||||
|
state = {...state}..[tabId] = current.copyWith.readerableState(
|
||||||
|
ReaderableState(
|
||||||
|
readerable: readerable.readerable,
|
||||||
|
active: readerable.active,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onFindResults(FindResultsEvent event) {
|
||||||
|
final FindResultsEvent(:tabId, :results) = event;
|
||||||
|
|
||||||
|
if (results.isNotEmpty) {
|
||||||
|
final current = state[tabId] ?? TabState.$default(tabId);
|
||||||
|
final result = results.last;
|
||||||
|
|
||||||
|
state = {...state}..[tabId] = current.copyWith.findResultState(
|
||||||
|
FindResultState(
|
||||||
|
activeMatchOrdinal: result.activeMatchOrdinal,
|
||||||
|
numberOfMatches: result.numberOfMatches,
|
||||||
|
isDoneCounting: result.isDoneCounting,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> addTab({
|
||||||
|
Uri? url,
|
||||||
|
bool selectTab = true,
|
||||||
|
bool startLoading = true,
|
||||||
|
String? parentId,
|
||||||
|
LoadUrlFlags flags = LoadUrlFlags.NONE,
|
||||||
|
String? contextId,
|
||||||
|
Source source = Internal.newTab,
|
||||||
|
bool private = false,
|
||||||
|
HistoryMetadataKey? historyMetadata,
|
||||||
|
Map<String, String>? additionalHeaders,
|
||||||
|
}) {
|
||||||
|
return _tabsService.addTab(
|
||||||
|
url: url,
|
||||||
|
selectTab: selectTab,
|
||||||
|
startLoading: startLoading,
|
||||||
|
parentId: parentId,
|
||||||
|
flags: flags,
|
||||||
|
contextId: contextId,
|
||||||
|
source: source,
|
||||||
|
private: private,
|
||||||
|
historyMetadata: historyMetadata,
|
||||||
|
additionalHeaders: additionalHeaders,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> closeTabs(List<String> tabIds) {
|
||||||
|
return _tabsService.removeTabs(ids: tabIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> closeTab(String tabIds) {
|
||||||
|
return _tabsService.removeTab(tabId: tabIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, TabState> build() {
|
||||||
|
final eventService = ref.watch(eventServiceProvider);
|
||||||
|
|
||||||
|
final subscriptions = [
|
||||||
|
eventService.tabListEvents.listen(_onTabListChange),
|
||||||
|
eventService.tabContentEvents.listen(_onTabContentStateChange),
|
||||||
|
eventService.iconEvents.listen(_onIconChange),
|
||||||
|
eventService.thumbnailEvents.listen(_onThumbnailChange),
|
||||||
|
eventService.securityInfoEvents.listen(_onSecurityInfoStateChange),
|
||||||
|
eventService.historyEvents.listen(_onHistoryStateChange),
|
||||||
|
eventService.readerableEvents.listen(_onReaderableStateChange),
|
||||||
|
eventService.findResultsEvent.listen(_onFindResults),
|
||||||
|
];
|
||||||
|
|
||||||
|
ref.onDispose(() {
|
||||||
|
for (final sub in subscriptions) {
|
||||||
|
unawaited(sub.cancel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Riverpod()
|
||||||
|
TabState? tabState(TabStateRef ref, String? tabId) {
|
||||||
|
if (tabId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref.watch(
|
||||||
|
tabStatesProvider.select((tabs) => tabs[tabId]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Riverpod()
|
||||||
|
TabState? selectedTabState(SelectedTabStateRef ref) {
|
||||||
|
final tabId = ref.watch(selectedTabProvider);
|
||||||
|
return ref.watch(tabStateProvider(tabId));
|
||||||
|
}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'tab_state.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$tabStateHash() => r'9fd7990804643fac180dd4fd50803bc7c9fa2827';
|
||||||
|
|
||||||
|
/// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [tabState].
|
||||||
|
@ProviderFor(tabState)
|
||||||
|
const tabStateProvider = TabStateFamily();
|
||||||
|
|
||||||
|
/// See also [tabState].
|
||||||
|
class TabStateFamily extends Family<TabState?> {
|
||||||
|
/// See also [tabState].
|
||||||
|
const TabStateFamily();
|
||||||
|
|
||||||
|
/// See also [tabState].
|
||||||
|
TabStateProvider call(
|
||||||
|
String? tabId,
|
||||||
|
) {
|
||||||
|
return TabStateProvider(
|
||||||
|
tabId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TabStateProvider getProviderOverride(
|
||||||
|
covariant TabStateProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
provider.tabId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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'tabStateProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [tabState].
|
||||||
|
class TabStateProvider extends AutoDisposeProvider<TabState?> {
|
||||||
|
/// See also [tabState].
|
||||||
|
TabStateProvider(
|
||||||
|
String? tabId,
|
||||||
|
) : this._internal(
|
||||||
|
(ref) => tabState(
|
||||||
|
ref as TabStateRef,
|
||||||
|
tabId,
|
||||||
|
),
|
||||||
|
from: tabStateProvider,
|
||||||
|
name: r'tabStateProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$tabStateHash,
|
||||||
|
dependencies: TabStateFamily._dependencies,
|
||||||
|
allTransitiveDependencies: TabStateFamily._allTransitiveDependencies,
|
||||||
|
tabId: tabId,
|
||||||
|
);
|
||||||
|
|
||||||
|
TabStateProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.tabId,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String? tabId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(
|
||||||
|
TabState? Function(TabStateRef provider) create,
|
||||||
|
) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: TabStateProvider._internal(
|
||||||
|
(ref) => create(ref as TabStateRef),
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
tabId: tabId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeProviderElement<TabState?> createElement() {
|
||||||
|
return _TabStateProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is TabStateProvider && other.tabId == tabId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, tabId.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin TabStateRef on AutoDisposeProviderRef<TabState?> {
|
||||||
|
/// The parameter `tabId` of this provider.
|
||||||
|
String? get tabId;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TabStateProviderElement extends AutoDisposeProviderElement<TabState?>
|
||||||
|
with TabStateRef {
|
||||||
|
_TabStateProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get tabId => (origin as TabStateProvider).tabId;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$selectedTabStateHash() => r'22172913554e14e67f692eff0777ea015175906e';
|
||||||
|
|
||||||
|
/// See also [selectedTabState].
|
||||||
|
@ProviderFor(selectedTabState)
|
||||||
|
final selectedTabStateProvider = AutoDisposeProvider<TabState?>.internal(
|
||||||
|
selectedTabState,
|
||||||
|
name: r'selectedTabStateProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$selectedTabStateHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef SelectedTabStateRef = AutoDisposeProviderRef<TabState?>;
|
||||||
|
String _$tabStatesHash() => r'22fd36fe2e443fd2dfb703dc3be72716fbccef6d';
|
||||||
|
|
||||||
|
/// See also [TabStates].
|
||||||
|
@ProviderFor(TabStates)
|
||||||
|
final tabStatesProvider =
|
||||||
|
NotifierProvider<TabStates, Map<String, TabState>>.internal(
|
||||||
|
TabStates.new,
|
||||||
|
name: r'tabStatesProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product') ? null : _$tabStatesHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$TabStates = Notifier<Map<String, TabState>>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
@@ -1,13 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
import 'package:lensai/extensions/image.dart';
|
|
||||||
import 'package:lensai/features/geckoview/domain/entities/history_state.dart';
|
|
||||||
import 'package:lensai/features/geckoview/domain/entities/readerable_state.dart';
|
|
||||||
import 'package:lensai/features/geckoview/domain/entities/security_state.dart';
|
|
||||||
import 'package:lensai/features/geckoview/domain/entities/tab_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:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'tab.g.dart';
|
part 'tab.g.dart';
|
||||||
@@ -16,100 +9,6 @@ part 'tab.g.dart';
|
|||||||
class TabRepository extends _$TabRepository {
|
class TabRepository extends _$TabRepository {
|
||||||
final _tabsService = GeckoTabService();
|
final _tabsService = GeckoTabService();
|
||||||
|
|
||||||
void _onTabListChange(List<String> tabs) {
|
|
||||||
state = {
|
|
||||||
for (final tabId in tabs) tabId: state[tabId] ?? TabState.$default(tabId),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onTabContentStateChange(TabContentState contentState) {
|
|
||||||
final current =
|
|
||||||
state[contentState.id] ?? TabState.$default(contentState.id);
|
|
||||||
|
|
||||||
state = {...state}..[contentState.id] = current.copyWith(
|
|
||||||
contextId: contentState.contextId,
|
|
||||||
url: Uri.parse(contentState.url),
|
|
||||||
title: contentState.title,
|
|
||||||
progress: contentState.progress,
|
|
||||||
isPrivate: contentState.isPrivate,
|
|
||||||
isFullScreen: contentState.isFullScreen,
|
|
||||||
isLoading: contentState.isLoading,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onIconChange(IconEvent event) async {
|
|
||||||
final IconEvent(:tabId, :bytes) = event;
|
|
||||||
|
|
||||||
final current = state[tabId] ?? TabState.$default(tabId);
|
|
||||||
|
|
||||||
final image = (bytes != null)
|
|
||||||
? (await tryDecodeImage(bytes)
|
|
||||||
.then((image) async => image?.toEquatable()))
|
|
||||||
: null;
|
|
||||||
|
|
||||||
state = {...state}..[tabId] = current.copyWith.icon(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onThumbnailChange(ThumbnailEvent event) async {
|
|
||||||
final ThumbnailEvent(:tabId, :bytes) = event;
|
|
||||||
|
|
||||||
final current = state[tabId] ?? TabState.$default(tabId);
|
|
||||||
|
|
||||||
final image = (bytes != null)
|
|
||||||
? (await tryDecodeImage(bytes)
|
|
||||||
.then((image) async => image?.toEquatable()))
|
|
||||||
: null;
|
|
||||||
|
|
||||||
state = {...state}..[tabId] = current.copyWith.thumbnail(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onSecurityInfoStateChange(SecurityInfoEvent event) {
|
|
||||||
final SecurityInfoEvent(:tabId, :securityInfo) = event;
|
|
||||||
|
|
||||||
final current = state[tabId] ?? TabState.$default(tabId);
|
|
||||||
|
|
||||||
state = {...state}..[tabId] = current.copyWith.securityInfoState(
|
|
||||||
SecurityState(
|
|
||||||
secure: securityInfo.secure,
|
|
||||||
host: securityInfo.host,
|
|
||||||
issuer: securityInfo.issuer,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onHistoryStateChange(HistoryEvent event) {
|
|
||||||
final HistoryEvent(:tabId, :history) = event;
|
|
||||||
|
|
||||||
final current = state[tabId] ?? TabState.$default(tabId);
|
|
||||||
|
|
||||||
state = {...state}..[tabId] = current.copyWith.historyState(
|
|
||||||
HistoryState(
|
|
||||||
items: history.items.nonNulls
|
|
||||||
.map(
|
|
||||||
(item) =>
|
|
||||||
HistoryItem(url: Uri.parse(item.url), title: item.title),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
currentIndex: history.currentIndex,
|
|
||||||
canGoBack: history.canGoBack,
|
|
||||||
canGoForward: history.canGoForward,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onReaderableStateChange(ReaderableEvent event) {
|
|
||||||
final ReaderableEvent(:tabId, :readerable) = event;
|
|
||||||
|
|
||||||
final current = state[tabId] ?? TabState.$default(tabId);
|
|
||||||
|
|
||||||
state = {...state}..[tabId] = current.copyWith.readerableState(
|
|
||||||
ReaderableState(
|
|
||||||
readerable: readerable.readerable,
|
|
||||||
active: readerable.active,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> addTab({
|
Future<String> addTab({
|
||||||
Uri? url,
|
Uri? url,
|
||||||
bool selectTab = true,
|
bool selectTab = true,
|
||||||
@@ -136,30 +35,18 @@ class TabRepository extends _$TabRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> selectTab(String tabId) {
|
||||||
|
return _tabsService.selectTab(tabId: tabId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> closeTab(String tabId) {
|
||||||
|
return _tabsService.removeTab(tabId: tabId);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> closeTabs(List<String> tabIds) {
|
Future<void> closeTabs(List<String> tabIds) {
|
||||||
return _tabsService.removeTabs(ids: tabIds);
|
return _tabsService.removeTabs(ids: tabIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, TabState> build() {
|
void build() {}
|
||||||
final eventService = ref.watch(eventServiceProvider);
|
|
||||||
|
|
||||||
final subscriptions = [
|
|
||||||
eventService.tabListEvents.listen(_onTabListChange),
|
|
||||||
eventService.tabContentEvents.listen(_onTabContentStateChange),
|
|
||||||
eventService.iconEvents.listen(_onIconChange),
|
|
||||||
eventService.thumbnailEvents.listen(_onThumbnailChange),
|
|
||||||
eventService.securityInfoEvents.listen(_onSecurityInfoStateChange),
|
|
||||||
eventService.historyEvents.listen(_onHistoryStateChange),
|
|
||||||
eventService.readerableEvents.listen(_onReaderableStateChange),
|
|
||||||
];
|
|
||||||
|
|
||||||
ref.onDispose(() {
|
|
||||||
for (final sub in subscriptions) {
|
|
||||||
unawaited(sub.cancel());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,11 @@ part of 'tab.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$tabRepositoryHash() => r'64724c0215624753c5c6ff8d6827b890ad9a6f2c';
|
String _$tabRepositoryHash() => r'0abf38ef42f29015d81ccd11eb5990b741ebc616';
|
||||||
|
|
||||||
/// See also [TabRepository].
|
/// See also [TabRepository].
|
||||||
@ProviderFor(TabRepository)
|
@ProviderFor(TabRepository)
|
||||||
final tabRepositoryProvider =
|
final tabRepositoryProvider = NotifierProvider<TabRepository, void>.internal(
|
||||||
NotifierProvider<TabRepository, Map<String, TabState>>.internal(
|
|
||||||
TabRepository.new,
|
TabRepository.new,
|
||||||
name: r'tabRepositoryProvider',
|
name: r'tabRepositoryProvider',
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
@@ -21,6 +20,6 @@ final tabRepositoryProvider =
|
|||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef _$TabRepository = Notifier<Map<String, TabState>>;
|
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
|
||||||
|
|||||||
-3
@@ -2,12 +2,9 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/widgets.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/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/entities/sheet.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
+1
-1
@@ -3,8 +3,8 @@ import 'dart:async';
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:lensai/data/models/received_parameter.dart';
|
import 'package:lensai/data/models/received_parameter.dart';
|
||||||
import 'package:lensai/features/app_widget/domain/services/home_widget.dart';
|
import 'package:lensai/features/app_widget/domain/services/home_widget.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/domain/entities/sheet.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/entities/sheet.dart';
|
|
||||||
import 'package:lensai/features/share_intent/domain/services/sharing_intent.dart';
|
import 'package:lensai/features/share_intent/domain/services/sharing_intent.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';
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'engine_settings.g.dart';
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
GeckoEngineSettingsService engineSettingsService(EngineSettingsServiceRef ref) {
|
||||||
|
return GeckoEngineSettingsService();
|
||||||
|
}
|
||||||
+11
-11
@@ -1,27 +1,27 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
part of 'selected_tab.dart';
|
part of 'engine_settings.dart';
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$selectedTabControllerHash() =>
|
String _$engineSettingsServiceHash() =>
|
||||||
r'b5d79d4d5c2dc08d504e601fa29c8b83d51c9716';
|
r'9d9abb3601a3782f1f3ef91e31049db40acbf64a';
|
||||||
|
|
||||||
/// See also [SelectedTabController].
|
/// See also [engineSettingsService].
|
||||||
@ProviderFor(SelectedTabController)
|
@ProviderFor(engineSettingsService)
|
||||||
final selectedTabControllerProvider =
|
final engineSettingsServiceProvider =
|
||||||
NotifierProvider<SelectedTabController, String?>.internal(
|
Provider<GeckoEngineSettingsService>.internal(
|
||||||
SelectedTabController.new,
|
engineSettingsService,
|
||||||
name: r'selectedTabControllerProvider',
|
name: r'engineSettingsServiceProvider',
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
? null
|
? null
|
||||||
: _$selectedTabControllerHash,
|
: _$engineSettingsServiceHash,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef _$SelectedTabController = Notifier<String?>;
|
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
|
||||||
+15
-13
@@ -3,28 +3,32 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/entities/tab_state.dart';
|
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/tab_state.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/repositories/topic.dart';
|
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/topics/domain/repositories/tab_link.dart';
|
||||||
|
|
||||||
class TabActionDialog extends HookConsumerWidget {
|
class TabActionDialog extends HookConsumerWidget {
|
||||||
final String tabId;
|
final TabState initialTab;
|
||||||
|
|
||||||
final void Function()? onDismiss;
|
final void Function()? onDismiss;
|
||||||
|
|
||||||
const TabActionDialog({
|
const TabActionDialog({
|
||||||
required this.tabId,
|
required this.initialTab,
|
||||||
this.onDismiss,
|
this.onDismiss,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final tabState =
|
final tabState = ref.watch(tabStateProvider(initialTab.id)) ?? initialTab;
|
||||||
ref.watch(tabStateProvider(tabId)) ?? TabState.$default(tabId);
|
final tabTopicId = ref.watch(
|
||||||
|
tabTopicIdProvider(initialTab.id).select((value) => value.valueOrNull),
|
||||||
|
);
|
||||||
|
|
||||||
final topics =
|
final topics =
|
||||||
ref.watch(topicRepositoryProvider.select((value) => value.valueOrNull));
|
ref.watch(topicsWithCountProvider.select((value) => value.valueOrNull));
|
||||||
final selectedTopic =
|
final selectedTopic =
|
||||||
topics?.firstWhereOrNull((topic) => topic.id == tabState.topicId);
|
topics?.firstWhereOrNull((topic) => topic.id == tabTopicId);
|
||||||
|
|
||||||
final expansionController = useExpansionTileController();
|
final expansionController = useExpansionTileController();
|
||||||
|
|
||||||
@@ -64,17 +68,15 @@ class TabActionDialog extends HookConsumerWidget {
|
|||||||
? Text(selectedTopic.name ?? 'New Topic')
|
? Text(selectedTopic.name ?? 'New Topic')
|
||||||
: const Text('Assign a Topic'),
|
: const Text('Assign a Topic'),
|
||||||
children: topics
|
children: topics
|
||||||
?.where((topic) => topic.id != tabState.topicId)
|
?.where((topic) => topic.id != tabTopicId)
|
||||||
.map(
|
.map(
|
||||||
(topic) => ListTile(
|
(topic) => ListTile(
|
||||||
leading: CircleAvatar(backgroundColor: topic.color),
|
leading: CircleAvatar(backgroundColor: topic.color),
|
||||||
title: Text(topic.name ?? 'New Topic'),
|
title: Text(topic.name ?? 'New Topic'),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await ref
|
await ref
|
||||||
.read(
|
.read(tabLinkRepositoryProvider.notifier)
|
||||||
tabStateProvider(initialTab.id).notifier,
|
.assignTab(initialTab.id, topic.id);
|
||||||
)
|
|
||||||
.copyWith(topicId: topic.id);
|
|
||||||
|
|
||||||
expansionController.collapse();
|
expansionController.collapse();
|
||||||
},
|
},
|
||||||
+22
-29
@@ -1,20 +1,19 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
|
||||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:lensai/data/models/web_page_info.dart';
|
import 'package:lensai/data/models/web_page_info.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/providers.dart';
|
import 'package:lensai/features/bangs/domain/providers.dart';
|
||||||
import 'package:lensai/features/bangs/presentation/widgets/site_search.dart';
|
import 'package:lensai/features/bangs/presentation/widgets/site_search.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:lensai/features/search_browser/utils/url_builder.dart'
|
import 'package:lensai/features/kagi/utils/url_builder.dart' as uri_builder;
|
||||||
as uri_builder;
|
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
||||||
import 'package:lensai/features/web_view/presentation/controllers/switch_new_tab.dart';
|
|
||||||
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
import 'package:lensai/presentation/widgets/failure_widget.dart';
|
||||||
import 'package:lensai/presentation/widgets/website_title_tile.dart';
|
import 'package:lensai/presentation/widgets/website_title_tile.dart';
|
||||||
import 'package:lensai/utils/ui_helper.dart' as ui_helper;
|
import 'package:lensai/utils/ui_helper.dart' as ui_helper;
|
||||||
@@ -84,27 +83,23 @@ class WebPageDialog extends HookConsumerWidget {
|
|||||||
enableIMEPersonalizedLearning: !incognitoEnabled,
|
enableIMEPersonalizedLearning: !incognitoEnabled,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'URL',
|
labelText: 'URL',
|
||||||
suffixIcon: (webViewController != null)
|
suffixIcon: IconButton(
|
||||||
? IconButton(
|
onPressed: () async {
|
||||||
onPressed: () async {
|
if (formKey.currentState?.validate() ?? false) {
|
||||||
if (formKey.currentState?.validate() ?? false) {
|
await ref
|
||||||
await webViewController!.loadUrl(
|
.read(tabSessionProvider(null).notifier)
|
||||||
urlRequest: URLRequest(
|
.loadUrl(
|
||||||
url: WebUri.uri(
|
url: uri_parser.tryParseUrl(
|
||||||
uri_parser.tryParseUrl(
|
urlTextController.text,
|
||||||
urlTextController.text,
|
eagerParsing: true,
|
||||||
eagerParsing: true,
|
)!,
|
||||||
)!,
|
);
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
onDismiss?.call();
|
onDismiss?.call();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.send),
|
icon: const Icon(Icons.send),
|
||||||
)
|
),
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (uri_parser.tryParseUrl(value, eagerParsing: true) !=
|
if (uri_parser.tryParseUrl(value, eagerParsing: true) !=
|
||||||
@@ -174,9 +169,7 @@ class WebPageDialog extends HookConsumerWidget {
|
|||||||
leading: const Icon(MdiIcons.tabPlus),
|
leading: const Icon(MdiIcons.tabPlus),
|
||||||
title: const Text('Open in new tab'),
|
title: const Text('Open in new tab'),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await ref
|
await ref.read(tabRepositoryProvider.notifier).addTab(url: url);
|
||||||
.read(switchNewTabControllerProvider.notifier)
|
|
||||||
.add(url);
|
|
||||||
|
|
||||||
onDismiss?.call();
|
onDismiss?.call();
|
||||||
},
|
},
|
||||||
@@ -201,8 +194,8 @@ class WebPageDialog extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await ref
|
await ref
|
||||||
.read(switchNewTabControllerProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
.add(summarizerUrl);
|
.addTab(url: summarizerUrl);
|
||||||
|
|
||||||
onDismiss?.call();
|
onDismiss?.call();
|
||||||
},
|
},
|
||||||
+1
-1
@@ -3,7 +3,7 @@ import 'package:flutter_markdown/flutter_markdown.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/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/error_container.dart';
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/error_container.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
|
|
||||||
class LandingAction extends HookConsumerWidget {
|
class LandingAction extends HookConsumerWidget {
|
||||||
+7
-5
@@ -4,8 +4,9 @@ import 'package:flutter/services.dart' show rootBundle;
|
|||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:lensai/domain/services/app_initialization.dart';
|
import 'package:lensai/domain/services/app_initialization.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/error_container.dart';
|
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/landing/action.dart';
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/error_container.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/landing/action.dart';
|
||||||
import 'package:lensai/presentation/hooks/cached_future.dart';
|
import 'package:lensai/presentation/hooks/cached_future.dart';
|
||||||
|
|
||||||
class LandingContent extends HookConsumerWidget {
|
class LandingContent extends HookConsumerWidget {
|
||||||
@@ -99,7 +100,8 @@ class LandingContent extends HookConsumerWidget {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await ref
|
await ref
|
||||||
.read(
|
.read(
|
||||||
appInitializationServiceProvider.notifier)
|
appInitializationServiceProvider.notifier,
|
||||||
|
)
|
||||||
.reinitialize();
|
.reinitialize();
|
||||||
},
|
},
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
@@ -119,8 +121,8 @@ class LandingContent extends HookConsumerWidget {
|
|||||||
onTapLink: (text, href, title) async {
|
onTapLink: (text, href, title) async {
|
||||||
if (href != null) {
|
if (href != null) {
|
||||||
await ref
|
await ref
|
||||||
.read(switchNewTabControllerProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
.add(Uri.parse(href));
|
.addTab(url: Uri.parse(href));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectable: true,
|
selectable: true,
|
||||||
+6
-6
@@ -2,11 +2,11 @@ import 'package:expandable_page_view/expandable_page_view.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/domain/entities/sheet.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/entities/sheet.dart';
|
import 'package:lensai/features/kagi/presentation/tabs/assistant_tab.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/tabs/assistant_tab.dart';
|
import 'package:lensai/features/kagi/presentation/tabs/search_tab.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/tabs/search_tab.dart';
|
import 'package:lensai/features/kagi/presentation/tabs/summarize_tab.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/tabs/summarize_tab.dart';
|
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
||||||
@@ -14,12 +14,12 @@ import 'package:lensai/presentation/hooks/sync_page_tab.dart';
|
|||||||
|
|
||||||
typedef OnSubmitUri = void Function(Uri url);
|
typedef OnSubmitUri = void Function(Uri url);
|
||||||
|
|
||||||
class SharedContentSheet extends HookConsumerWidget {
|
class CreateTabSheetWidget extends HookConsumerWidget {
|
||||||
final CreateTabSheet parameter;
|
final CreateTabSheet parameter;
|
||||||
final OnSubmitUri onSubmit;
|
final OnSubmitUri onSubmit;
|
||||||
final void Function(KagiTool tool)? onActiveToolChanged;
|
final void Function(KagiTool tool)? onActiveToolChanged;
|
||||||
|
|
||||||
const SharedContentSheet({
|
const CreateTabSheetWidget({
|
||||||
required this.parameter,
|
required this.parameter,
|
||||||
required this.onSubmit,
|
required this.onSubmit,
|
||||||
this.onActiveToolChanged,
|
this.onActiveToolChanged,
|
||||||
+24
-18
@@ -4,10 +4,16 @@ import 'package:fading_scroll/fading_scroll.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/presentation/dialogs/tab_action.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/tab_preview.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/controllers/overlay_dialog.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/topics/domain/providers/selected_topic.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/repositories/tab_link.dart';
|
import 'package:lensai/features/geckoview/features/topics/domain/repositories/tab_link.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/presentation/widgets/topic_chips.dart';
|
import 'package:lensai/features/geckoview/features/topics/presentation/widgets/topic_chips.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/dialogs/tab_action.dart';
|
|
||||||
|
|
||||||
class _SliverHeaderDelagate extends SliverPersistentHeaderDelegate {
|
class _SliverHeaderDelagate extends SliverPersistentHeaderDelegate {
|
||||||
static const _headerSize = 104.0;
|
static const _headerSize = 104.0;
|
||||||
@@ -36,8 +42,8 @@ class _SliverHeaderDelagate extends SliverPersistentHeaderDelegate {
|
|||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await ref
|
await ref
|
||||||
.read(switchNewTabControllerProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
.add(Uri.https('kagi.com'));
|
.addTab(url: Uri.https('kagi.com'));
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
},
|
},
|
||||||
@@ -48,8 +54,8 @@ class _SliverHeaderDelagate extends SliverPersistentHeaderDelegate {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final topic = ref.read(selectedTopicProvider);
|
final topic = ref.read(selectedTopicProvider);
|
||||||
await ref
|
await ref
|
||||||
.read(topicTabRepositoryProvider(topic).notifier)
|
.read(tabLinkRepositoryProvider.notifier)
|
||||||
.closeAllTabs();
|
.closeAllTabs(topic);
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
},
|
},
|
||||||
@@ -79,11 +85,11 @@ class _SliverHeaderDelagate extends SliverPersistentHeaderDelegate {
|
|||||||
false;
|
false;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewTabsSheet extends HookConsumerWidget {
|
class ViewTabsSheetWidget extends HookConsumerWidget {
|
||||||
final ScrollController sheetScrollController;
|
final ScrollController sheetScrollController;
|
||||||
final VoidCallback onClose;
|
final VoidCallback onClose;
|
||||||
|
|
||||||
const ViewTabsSheet({
|
const ViewTabsSheetWidget({
|
||||||
required this.onClose,
|
required this.onClose,
|
||||||
required this.sheetScrollController,
|
required this.sheetScrollController,
|
||||||
super.key,
|
super.key,
|
||||||
@@ -127,10 +133,10 @@ class ViewTabsSheet extends HookConsumerWidget {
|
|||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
final topic = ref.watch(selectedTopicProvider);
|
final topic = ref.watch(selectedTopicProvider);
|
||||||
final availableTabs = ref.watch(
|
final availableTabs = ref.watch(
|
||||||
topicTabRepositoryProvider(topic)
|
topicTabIdsProvider(topic)
|
||||||
.select((value) => value.valueOrNull ?? []),
|
.select((value) => value.valueOrNull ?? []),
|
||||||
);
|
);
|
||||||
final activeTab = ref.watch(webViewTabControllerProvider);
|
final activeTab = ref.watch(selectedTabProvider);
|
||||||
|
|
||||||
final itemHeight = useMemoized(
|
final itemHeight = useMemoized(
|
||||||
() => _calculateItemHeight(
|
() => _calculateItemHeight(
|
||||||
@@ -185,19 +191,18 @@ class ViewTabsSheet extends HookConsumerWidget {
|
|||||||
final tab = ref.watch(tabStateProvider(tabId));
|
final tab = ref.watch(tabStateProvider(tabId));
|
||||||
|
|
||||||
return (tab != null)
|
return (tab != null)
|
||||||
? WebViewTab(
|
? TabPreview(
|
||||||
tab: tab,
|
tab: tab,
|
||||||
isActive: tabId == activeTab,
|
isActive: tabId == activeTab,
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
if (tabId != activeTab) {
|
if (tabId != activeTab) {
|
||||||
//Close first to avoid rebuilds
|
//Close first to avoid rebuilds
|
||||||
onClose();
|
onClose();
|
||||||
ref
|
await ref
|
||||||
.read(
|
.read(
|
||||||
webViewTabControllerProvider
|
tabRepositoryProvider.notifier,
|
||||||
.notifier,
|
|
||||||
)
|
)
|
||||||
.showTab(tab.id);
|
.selectTab(tab.id);
|
||||||
} else {
|
} else {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
@@ -205,14 +210,15 @@ class ViewTabsSheet extends HookConsumerWidget {
|
|||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
ref
|
ref
|
||||||
.read(
|
.read(
|
||||||
overlayDialogProvider.notifier,
|
overlayDialogControllerProvider
|
||||||
|
.notifier,
|
||||||
)
|
)
|
||||||
.show(
|
.show(
|
||||||
TabActionDialog(
|
TabActionDialog(
|
||||||
initialTab: tab,
|
initialTab: tab,
|
||||||
onDismiss: ref
|
onDismiss: ref
|
||||||
.read(
|
.read(
|
||||||
overlayDialogProvider
|
overlayDialogControllerProvider
|
||||||
.notifier,
|
.notifier,
|
||||||
)
|
)
|
||||||
.dismiss,
|
.dismiss,
|
||||||
@@ -224,7 +230,7 @@ class ViewTabsSheet extends HookConsumerWidget {
|
|||||||
.read(
|
.read(
|
||||||
tabRepositoryProvider.notifier,
|
tabRepositoryProvider.notifier,
|
||||||
)
|
)
|
||||||
.deleteTab(tab.id);
|
.closeTab(tab.id);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: const SizedBox.shrink();
|
: const SizedBox.shrink();
|
||||||
+12
-12
@@ -1,16 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lensai/features/web_view/domain/entities/abstract/tab.dart';
|
import 'package:lensai/features/geckoview/domain/entities/tab_state.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/favicon.dart';
|
|
||||||
|
|
||||||
class WebViewTab extends StatelessWidget {
|
class TabPreview extends StatelessWidget {
|
||||||
final ITab tab;
|
final TabState tab;
|
||||||
final bool isActive;
|
final bool isActive;
|
||||||
|
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
final VoidCallback? onLongPress;
|
final VoidCallback? onLongPress;
|
||||||
final VoidCallback? onDelete;
|
final VoidCallback? onDelete;
|
||||||
|
|
||||||
const WebViewTab({
|
const TabPreview({
|
||||||
required this.tab,
|
required this.tab,
|
||||||
required this.isActive,
|
required this.isActive,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
@@ -46,7 +45,7 @@ class WebViewTab extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.only(left: 6.0),
|
padding: const EdgeInsets.only(left: 6.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
tab.title ?? 'New Tab',
|
tab.title,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -64,9 +63,10 @@ class WebViewTab extends StatelessWidget {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 6.0,
|
width: 6.0,
|
||||||
),
|
),
|
||||||
FaviconImage(
|
RawImage(
|
||||||
url: tab.url,
|
image: tab.icon?.value,
|
||||||
favicon: tab.favicon,
|
height: 16,
|
||||||
|
width: 16,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 6.0,
|
width: 6.0,
|
||||||
@@ -82,7 +82,7 @@ class WebViewTab extends StatelessWidget {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
if (tab.screenshot != null)
|
if (tab.thumbnail != null)
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
@@ -91,9 +91,9 @@ class WebViewTab extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: Image.memory(
|
child: RawImage(
|
||||||
|
image: tab.thumbnail!.value,
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
tab.screenshot!,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
+2
-3
@@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||||
|
|
||||||
class TabsActionButton extends HookConsumerWidget {
|
class TabsActionButton extends HookConsumerWidget {
|
||||||
final bool isActive;
|
final bool isActive;
|
||||||
@@ -16,8 +16,7 @@ class TabsActionButton extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
final tabCount =
|
final tabCount = ref.watch(tabStatesProvider.select((tabs) => tabs.length));
|
||||||
ref.watch(tabRepositoryProvider.select((tabs) => tabs.length));
|
|
||||||
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
+170
-194
@@ -1,34 +1,39 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:animations/animations.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.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/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.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/repositories/tab.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/engine_settings.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/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/tabs_action_button.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/controllers/bottom_sheet.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/controllers/overlay_dialog.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/find_in_page/presentation/controllers/find_in_page_visibility.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/find_in_page/presentation/widgets/find_in_page.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/readerview/presentation/widgets/reader_button.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/entities/sheet.dart';
|
import 'package:lensai/features/kagi/data/services/session.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/providers.dart';
|
|
||||||
import 'package:lensai/features/search_browser/domain/services/create_tab.dart';
|
|
||||||
import 'package:lensai/features/search_browser/presentation/controllers/bottom_sheet.dart';
|
|
||||||
import 'package:lensai/features/search_browser/presentation/controllers/overlay_dialog.dart';
|
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/app_bar_title.dart';
|
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/landing/content.dart';
|
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/sheets/shared_content_sheet.dart';
|
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/sheets/view_tabs_sheet.dart';
|
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/tabs_action_button.dart';
|
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/presentation/hooks/overlay_portal_controller.dart';
|
import 'package:lensai/presentation/hooks/overlay_portal_controller.dart';
|
||||||
import 'package:lensai/presentation/widgets/animate_gradient_shader.dart';
|
|
||||||
import 'package:lensai/presentation/widgets/animated_indexed_stack.dart';
|
|
||||||
import 'package:lensai/utils/ui_helper.dart' as ui_helper;
|
import 'package:lensai/utils/ui_helper.dart' as ui_helper;
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:speech_to_text_google_dialog/speech_to_text_google_dialog.dart';
|
import 'package:speech_to_text_google_dialog/speech_to_text_google_dialog.dart';
|
||||||
|
|
||||||
class KagiScreen extends HookConsumerWidget {
|
class BrowserScreen extends HookConsumerWidget {
|
||||||
const KagiScreen({super.key});
|
const BrowserScreen({super.key});
|
||||||
|
|
||||||
double _realtiveSafeArea(BuildContext context) {
|
double _realtiveSafeArea(BuildContext context) {
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
@@ -60,7 +65,8 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final activeTabId = ref.watch(webViewTabControllerProvider);
|
final selectedTabId =
|
||||||
|
ref.watch(selectedTabStateProvider.select((value) => value?.id));
|
||||||
|
|
||||||
final menuController = useMemoized(() => MenuController());
|
final menuController = useMemoized(() => MenuController());
|
||||||
|
|
||||||
@@ -81,12 +87,24 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ref.listen(
|
||||||
|
settingsRepositoryProvider
|
||||||
|
.select((value) => value.valueOrNull?.enableJavascript),
|
||||||
|
(previous, next) async {
|
||||||
|
if (next != null) {
|
||||||
|
await ref.read(engineSettingsServiceProvider).javaScriptEnabled(next);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
ref.listen(
|
ref.listen(
|
||||||
settingsRepositoryProvider
|
settingsRepositoryProvider
|
||||||
.select((value) => value.valueOrNull?.kagiSession),
|
.select((value) => value.valueOrNull?.kagiSession),
|
||||||
(previous, next) async {
|
(previous, next) async {
|
||||||
if (next != null && next.isNotEmpty) {
|
if (next != null && next.isNotEmpty) {
|
||||||
await ref.read(sessionServiceProvider.notifier).setKagiSession(next);
|
await ref
|
||||||
|
.read(kagiSessionServiceProvider.notifier)
|
||||||
|
.setKagiSession(next);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -98,22 +116,28 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
child: AppBar(
|
child: AppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
titleSpacing: 8.0,
|
titleSpacing: 8.0,
|
||||||
title: (activeTabId != null)
|
title: (selectedTabId != null)
|
||||||
? Consumer(
|
? Consumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
final page = ref.watch(tabStateProvider(activeTabId));
|
final tabState = ref.watch(tabStateProvider(selectedTabId));
|
||||||
|
|
||||||
return (page != null)
|
return (tabState != null)
|
||||||
? AppBarTitle(
|
? AppBarTitle(
|
||||||
tab: page,
|
tab: tabState,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ref.read(overlayDialogProvider.notifier).show(
|
ref
|
||||||
|
.read(
|
||||||
|
overlayDialogControllerProvider.notifier,
|
||||||
|
)
|
||||||
|
.show(
|
||||||
WebPageDialog(
|
WebPageDialog(
|
||||||
url: page.url,
|
url: tabState.url,
|
||||||
precachedInfo: page,
|
precachedInfo: tabState,
|
||||||
webViewController: page.controller,
|
|
||||||
onDismiss: ref
|
onDismiss: ref
|
||||||
.read(overlayDialogProvider.notifier)
|
.read(
|
||||||
|
overlayDialogControllerProvider
|
||||||
|
.notifier,
|
||||||
|
)
|
||||||
.dismiss,
|
.dismiss,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -127,7 +151,7 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
final activeTool = useListenableSelector(
|
final activeTool = useListenableSelector(
|
||||||
activeKagiTool,
|
activeKagiTool,
|
||||||
() {
|
() {
|
||||||
if (displayedSheet is SharedContentSheet) {
|
if (displayedSheet is CreateTabSheetWidget) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +170,8 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
.read(createTabStreamProvider.notifier)
|
.read(createTabStreamProvider.notifier)
|
||||||
.createTab(
|
.createTab(
|
||||||
CreateTabSheet(
|
CreateTabSheet(
|
||||||
preferredTool: KagiTool.search),
|
preferredTool: KagiTool.search,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
icon: Icon(KagiTool.search.icon),
|
icon: Icon(KagiTool.search.icon),
|
||||||
@@ -160,7 +185,8 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
.read(createTabStreamProvider.notifier)
|
.read(createTabStreamProvider.notifier)
|
||||||
.createTab(
|
.createTab(
|
||||||
CreateTabSheet(
|
CreateTabSheet(
|
||||||
preferredTool: KagiTool.summarizer),
|
preferredTool: KagiTool.summarizer,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
icon: Icon(KagiTool.summarizer.icon),
|
icon: Icon(KagiTool.summarizer.icon),
|
||||||
@@ -186,93 +212,7 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
if (activeTabId != null)
|
if (selectedTabId != null) ReaderButton(),
|
||||||
HookConsumer(
|
|
||||||
builder: (context, ref, child) {
|
|
||||||
final colorScheme = Theme.of(context).colorScheme;
|
|
||||||
|
|
||||||
final readerabilityState = ref.watch(
|
|
||||||
readerabilityControllerProvider(activeTabId),
|
|
||||||
);
|
|
||||||
|
|
||||||
final enableReadability = ref.watch(
|
|
||||||
settingsRepositoryProvider.select(
|
|
||||||
(value) => (value.valueOrNull ?? Settings.withDefaults())
|
|
||||||
.enableReadability,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
final isReaderable =
|
|
||||||
readerabilityState.valueOrNull?.readerable ?? false;
|
|
||||||
|
|
||||||
final readerableApplied =
|
|
||||||
readerabilityState.valueOrNull?.applied ?? false;
|
|
||||||
|
|
||||||
final icon = useMemoized(
|
|
||||||
() => readerableApplied
|
|
||||||
? Icon(
|
|
||||||
MdiIcons.bookOpen,
|
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
)
|
|
||||||
: const Icon(
|
|
||||||
MdiIcons.bookOpenOutline,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
[readerableApplied],
|
|
||||||
);
|
|
||||||
|
|
||||||
return Visibility(
|
|
||||||
visible: enableReadability,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 15.0,
|
|
||||||
horizontal: 8.0,
|
|
||||||
),
|
|
||||||
child: readerabilityState.when(
|
|
||||||
data: (_) => Visibility(
|
|
||||||
visible: isReaderable == true || readerableApplied,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: readerabilityState.isLoading
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
final controller = ref.read(
|
|
||||||
webViewControllerProvider(activeTabId),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (controller != null) {
|
|
||||||
final readabilityNotifier = ref.read(
|
|
||||||
readerabilityControllerProvider(
|
|
||||||
activeTabId,
|
|
||||||
).notifier,
|
|
||||||
);
|
|
||||||
|
|
||||||
await readabilityNotifier
|
|
||||||
.toggleReaderable();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: icon,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
error: (error, stackTrace) => SizedBox.shrink(),
|
|
||||||
loading: () => AnimateGradientShader(
|
|
||||||
duration: const Duration(milliseconds: 500),
|
|
||||||
primaryEnd: Alignment.bottomLeft,
|
|
||||||
secondaryEnd: Alignment.topRight,
|
|
||||||
primaryColors: [
|
|
||||||
colorScheme.primary,
|
|
||||||
colorScheme.primaryContainer,
|
|
||||||
],
|
|
||||||
secondaryColors: [
|
|
||||||
colorScheme.secondary,
|
|
||||||
colorScheme.secondaryContainer,
|
|
||||||
],
|
|
||||||
child: icon,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (quickAction != null)
|
if (quickAction != null)
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
@@ -321,9 +261,11 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
isActive: displayedSheet is ViewTabsSheet,
|
isActive: displayedSheet is ViewTabsSheet,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (displayedSheet case ViewTabsSheet()) {
|
if (displayedSheet case ViewTabsSheet()) {
|
||||||
ref.read(bottomSheetProvider.notifier).dismiss();
|
ref.read(bottomSheetControllerProvider.notifier).dismiss();
|
||||||
} else {
|
} else {
|
||||||
ref.read(bottomSheetProvider.notifier).show(ViewTabsSheet());
|
ref
|
||||||
|
.read(bottomSheetControllerProvider.notifier)
|
||||||
|
.show(ViewTabsSheet());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -410,63 +352,63 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
child: const Text('Search'),
|
child: const Text('Search'),
|
||||||
),
|
),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
if (activeTabId != null)
|
if (selectedTabId != null)
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final controller =
|
final tabState =
|
||||||
ref.read(webViewControllerProvider(activeTabId));
|
ref.read(tabStateProvider(selectedTabId));
|
||||||
|
|
||||||
final url = await controller?.getUrl();
|
if (tabState?.url case final Uri url) {
|
||||||
if (url != null) {
|
|
||||||
// ignore: use_build_context_synchronously
|
|
||||||
await ui_helper.launchUrlFeedback(context, url);
|
await ui_helper.launchUrlFeedback(context, url);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leadingIcon: const Icon(Icons.open_in_browser),
|
leadingIcon: const Icon(Icons.open_in_browser),
|
||||||
child: const Text('Launch External'),
|
child: const Text('Launch External'),
|
||||||
),
|
),
|
||||||
if (activeTabId != null)
|
if (selectedTabId != null)
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final controller =
|
final tabState =
|
||||||
ref.read(webViewControllerProvider(activeTabId));
|
ref.read(tabStateProvider(selectedTabId));
|
||||||
|
|
||||||
final url = await controller?.getUrl();
|
if (tabState?.url case final Uri url) {
|
||||||
if (url != null) {
|
|
||||||
await Share.shareUri(url);
|
await Share.shareUri(url);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leadingIcon: const Icon(Icons.share),
|
leadingIcon: const Icon(Icons.share),
|
||||||
child: const Text('Share'),
|
child: const Text('Share'),
|
||||||
),
|
),
|
||||||
if (activeTabId != null) const Divider(),
|
if (selectedTabId != null) const Divider(),
|
||||||
if (activeTabId != null)
|
if (selectedTabId != null)
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () {
|
||||||
ref.read(showFindInPageProvider.notifier).update(true);
|
ref
|
||||||
|
.read(findInPageVisibilityControllerProvider.notifier)
|
||||||
|
.show();
|
||||||
},
|
},
|
||||||
leadingIcon: const Icon(Icons.search),
|
leadingIcon: const Icon(Icons.search),
|
||||||
child: const Text('Find in page'),
|
child: const Text('Find in page'),
|
||||||
),
|
),
|
||||||
if (activeTabId != null) const Divider(),
|
if (selectedTabId != null) const Divider(),
|
||||||
if (activeTabId != null)
|
if (selectedTabId != null)
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final controller =
|
final controller =
|
||||||
ref.read(webViewControllerProvider(activeTabId));
|
ref.read(tabSessionProvider(selectedTabId).notifier);
|
||||||
|
|
||||||
await controller?.reload();
|
await controller.reload();
|
||||||
|
menuController.close();
|
||||||
},
|
},
|
||||||
leadingIcon: const Icon(Icons.refresh),
|
leadingIcon: const Icon(Icons.refresh),
|
||||||
child: const Text('Reload'),
|
child: const Text('Reload'),
|
||||||
),
|
),
|
||||||
if (activeTabId != null) const Divider(),
|
if (selectedTabId != null) const Divider(),
|
||||||
if (activeTabId != null)
|
if (selectedTabId != null)
|
||||||
Consumer(
|
Consumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
final history = ref.watch(
|
final history = ref.watch(
|
||||||
tabStateProvider(activeTabId)
|
tabStateProvider(selectedTabId)
|
||||||
.select((value) => value?.pageHistory),
|
.select((value) => value?.historyState),
|
||||||
);
|
);
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
@@ -476,12 +418,12 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
onPressed: (history?.canGoBack == true)
|
onPressed: (history?.canGoBack == true)
|
||||||
? () async {
|
? () async {
|
||||||
final controller = ref.read(
|
final controller = ref.read(
|
||||||
webViewControllerProvider(
|
tabSessionProvider(
|
||||||
activeTabId,
|
selectedTabId,
|
||||||
),
|
).notifier,
|
||||||
);
|
);
|
||||||
|
|
||||||
await controller?.goBack();
|
await controller.goBack();
|
||||||
menuController.close();
|
menuController.close();
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
@@ -494,12 +436,12 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
onPressed: (history?.canGoForward == true)
|
onPressed: (history?.canGoForward == true)
|
||||||
? () async {
|
? () async {
|
||||||
final controller = ref.read(
|
final controller = ref.read(
|
||||||
webViewControllerProvider(
|
tabSessionProvider(
|
||||||
activeTabId,
|
selectedTabId,
|
||||||
),
|
).notifier,
|
||||||
);
|
);
|
||||||
|
|
||||||
await controller?.goForward();
|
await controller.goForward();
|
||||||
menuController.close();
|
menuController.close();
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
@@ -523,42 +465,46 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
child: Listener(
|
child: Listener(
|
||||||
onPointerDown: (displayedSheet != null)
|
onPointerDown: (displayedSheet != null)
|
||||||
? (_) {
|
? (_) {
|
||||||
ref.read(bottomSheetProvider.notifier).dismiss();
|
ref.read(bottomSheetControllerProvider.notifier).dismiss();
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
child: HookConsumer(
|
child: HookConsumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
final webViewWidgets = ref.watch(webViewWidgetCacheProvider);
|
|
||||||
final activeWebViewStackIndex = (activeTabId != null)
|
|
||||||
? webViewWidgets
|
|
||||||
.indexWhere((view) => view.tabId == activeTabId)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return BackButtonListener(
|
return BackButtonListener(
|
||||||
onBackButtonPressed: () async {
|
onBackButtonPressed: () async {
|
||||||
final page = (activeTabId != null)
|
final tabState = (selectedTabId != null)
|
||||||
? ref.read(tabStateProvider(activeTabId))
|
? ref.read(tabStateProvider(selectedTabId))
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
final tabCount =
|
||||||
|
ref.read(tabStatesProvider.select((tabs) => tabs.length));
|
||||||
|
|
||||||
//Don't do anything if a child route is active
|
//Don't do anything if a child route is active
|
||||||
if (GoRouterState.of(context).topRoute?.name != 'KagiRoute') {
|
if (GoRouterState.of(context).topRoute?.path !=
|
||||||
|
BrowserRoute().location) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayedSheet != null) {
|
if (displayedSheet != null) {
|
||||||
ref.read(bottomSheetProvider.notifier).dismiss();
|
ref.read(bottomSheetControllerProvider.notifier).dismiss();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayedOverlayDialog != null) {
|
if (displayedOverlayDialog != null) {
|
||||||
ref.read(overlayDialogProvider.notifier).dismiss();
|
ref
|
||||||
|
.read(overlayDialogControllerProvider.notifier)
|
||||||
|
.dismiss();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page?.pageHistory.canGoBack == true) {
|
if (tabState?.historyState.canGoBack == true) {
|
||||||
lastBackButtonPress.value = null;
|
lastBackButtonPress.value = null;
|
||||||
|
|
||||||
await page?.controller?.goBack();
|
final controller = ref.read(
|
||||||
|
tabSessionProvider(selectedTabId).notifier,
|
||||||
|
);
|
||||||
|
|
||||||
|
await controller.goBack();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,10 +513,10 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
const Duration(seconds: 2)) {
|
const Duration(seconds: 2)) {
|
||||||
lastBackButtonPress.value = null;
|
lastBackButtonPress.value = null;
|
||||||
|
|
||||||
if (page != null && webViewWidgets.length > 1) {
|
if (tabState != null && tabCount > 1) {
|
||||||
await ref
|
await ref
|
||||||
.read(tabRepositoryProvider.notifier)
|
.read(tabStatesProvider.notifier)
|
||||||
.deleteTab(page.id);
|
.closeTab(tabState.id);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
//Mark back as unhandled and navigator will pop
|
//Mark back as unhandled and navigator will pop
|
||||||
@@ -582,7 +528,7 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
..clearSnackBars()
|
..clearSnackBars()
|
||||||
..showSnackBar(
|
..showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: (webViewWidgets.length > 1)
|
content: (tabCount > 1)
|
||||||
? const Text(
|
? const Text(
|
||||||
'Please click BACK again to close current tab',
|
'Please click BACK again to close current tab',
|
||||||
)
|
)
|
||||||
@@ -598,26 +544,52 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
SafeArea(
|
SafeArea(
|
||||||
child: AnimatedIndexedStack(
|
child: Stack(
|
||||||
duration: const Duration(milliseconds: 250),
|
children: [
|
||||||
transitionBuilder:
|
const GeckoView(),
|
||||||
(child, animation, secondaryAnimation) =>
|
Positioned(
|
||||||
SharedAxisTransition(
|
bottom: 0,
|
||||||
animation: animation,
|
left: 0,
|
||||||
secondaryAnimation: secondaryAnimation,
|
right: 0,
|
||||||
transitionType: SharedAxisTransitionType.horizontal,
|
child: Consumer(
|
||||||
child: child,
|
builder: (context, ref, child) {
|
||||||
),
|
final value = ref.watch(
|
||||||
// key: ValueKey(
|
selectedTabStateProvider.select(
|
||||||
// (activeTabId != null)
|
(state) => state?.progress ?? 100,
|
||||||
// ? activeWebViewStackIndex
|
),
|
||||||
// : null,
|
);
|
||||||
// ),
|
|
||||||
index: (activeWebViewStackIndex != null &&
|
return Visibility(
|
||||||
activeWebViewStackIndex > -1)
|
visible: value < 100,
|
||||||
? activeWebViewStackIndex + 1
|
child: LinearProgressIndicator(
|
||||||
: 0,
|
value: value / 100,
|
||||||
children: [const LandingContent(), ...webViewWidgets],
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Consumer(
|
||||||
|
builder: (context, ref, child) {
|
||||||
|
final value = ref.watch(
|
||||||
|
selectedTabStateProvider.select(
|
||||||
|
(state) => EdgeInsets.only(
|
||||||
|
bottom: (state?.progress != null &&
|
||||||
|
state!.progress < 100)
|
||||||
|
? 4.0
|
||||||
|
: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return FindInPageWidget(padding: value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (displayedSheet != null)
|
if (displayedSheet != null)
|
||||||
@@ -636,7 +608,7 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
? NotificationListener<DraggableScrollableNotification>(
|
? NotificationListener<DraggableScrollableNotification>(
|
||||||
onNotification: (notification) {
|
onNotification: (notification) {
|
||||||
if (notification.extent <= 0.1) {
|
if (notification.extent <= 0.1) {
|
||||||
ref.read(bottomSheetProvider.notifier).dismiss();
|
ref.read(bottomSheetControllerProvider.notifier).dismiss();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
ref
|
ref
|
||||||
@@ -658,10 +630,12 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
topLeft: Radius.circular(28),
|
topLeft: Radius.circular(28),
|
||||||
topRight: Radius.circular(28),
|
topRight: Radius.circular(28),
|
||||||
),
|
),
|
||||||
child: ViewTabsSheet(
|
child: ViewTabsSheetWidget(
|
||||||
sheetScrollController: scrollController,
|
sheetScrollController: scrollController,
|
||||||
onClose: () {
|
onClose: () {
|
||||||
ref.read(bottomSheetProvider.notifier).dismiss();
|
ref
|
||||||
|
.read(bottomSheetControllerProvider.notifier)
|
||||||
|
.dismiss();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -676,15 +650,17 @@ class KagiScreen extends HookConsumerWidget {
|
|||||||
builder: (context, scrollController) {
|
builder: (context, scrollController) {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
child: SharedContentSheet(
|
child: CreateTabSheetWidget(
|
||||||
key: ValueKey(parameter),
|
key: ValueKey(parameter),
|
||||||
parameter: parameter,
|
parameter: parameter,
|
||||||
onSubmit: (url) async {
|
onSubmit: (url) async {
|
||||||
await ref
|
await ref
|
||||||
.read(switchNewTabControllerProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
.add(url);
|
.addTab(url: url);
|
||||||
|
|
||||||
ref.read(bottomSheetProvider.notifier).dismiss();
|
ref
|
||||||
|
.read(bottomSheetControllerProvider.notifier)
|
||||||
|
.dismiss();
|
||||||
},
|
},
|
||||||
onActiveToolChanged: (tool) {
|
onActiveToolChanged: (tool) {
|
||||||
activeKagiTool.value = tool;
|
activeKagiTool.value = tool;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:lensai/features/search_browser/domain/entities/sheet.dart';
|
import 'package:lensai/features/geckoview/features/browser/domain/entities/sheet.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/services/create_tab.dart';
|
import 'package:lensai/features/geckoview/features/browser/domain/services/create_tab.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';
|
||||||
|
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'find_in_page.g.dart';
|
||||||
|
|
||||||
|
@Riverpod()
|
||||||
|
class FindInPageRepository extends _$FindInPageRepository {
|
||||||
|
late GeckoFindInPageService _service;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void build(String? tabId) {
|
||||||
|
_service = (tabId != null)
|
||||||
|
? GeckoFindInPageService(tabId: tabId)
|
||||||
|
: GeckoFindInPageService.forActiveTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> findAll({required String text}) {
|
||||||
|
return _service.findAll(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> findNext({bool forward = true}) {
|
||||||
|
return _service.findNext(forward);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> clearMatches() {
|
||||||
|
return _service.clearMatches();
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
-52
@@ -1,13 +1,13 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
part of 'readerability_script.dart';
|
part of 'find_in_page.dart';
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$readerabilityScriptServiceHash() =>
|
String _$findInPageRepositoryHash() =>
|
||||||
r'85f0de50516cadb1f2d1efa8161a8cf45868b9d9';
|
r'a307a7169cfc559a687483962bd595d808c159bf';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -30,36 +30,36 @@ class _SystemHash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _$ReaderabilityScriptService
|
abstract class _$FindInPageRepository
|
||||||
extends BuildlessAutoDisposeAsyncNotifier<void> {
|
extends BuildlessAutoDisposeNotifier<void> {
|
||||||
late final String tabId;
|
late final String? tabId;
|
||||||
|
|
||||||
FutureOr<void> build(
|
void build(
|
||||||
String tabId,
|
String? tabId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [ReaderabilityScriptService].
|
/// See also [FindInPageRepository].
|
||||||
@ProviderFor(ReaderabilityScriptService)
|
@ProviderFor(FindInPageRepository)
|
||||||
const readerabilityScriptServiceProvider = ReaderabilityScriptServiceFamily();
|
const findInPageRepositoryProvider = FindInPageRepositoryFamily();
|
||||||
|
|
||||||
/// See also [ReaderabilityScriptService].
|
/// See also [FindInPageRepository].
|
||||||
class ReaderabilityScriptServiceFamily extends Family<AsyncValue<void>> {
|
class FindInPageRepositoryFamily extends Family<void> {
|
||||||
/// See also [ReaderabilityScriptService].
|
/// See also [FindInPageRepository].
|
||||||
const ReaderabilityScriptServiceFamily();
|
const FindInPageRepositoryFamily();
|
||||||
|
|
||||||
/// See also [ReaderabilityScriptService].
|
/// See also [FindInPageRepository].
|
||||||
ReaderabilityScriptServiceProvider call(
|
FindInPageRepositoryProvider call(
|
||||||
String tabId,
|
String? tabId,
|
||||||
) {
|
) {
|
||||||
return ReaderabilityScriptServiceProvider(
|
return FindInPageRepositoryProvider(
|
||||||
tabId,
|
tabId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ReaderabilityScriptServiceProvider getProviderOverride(
|
FindInPageRepositoryProvider getProviderOverride(
|
||||||
covariant ReaderabilityScriptServiceProvider provider,
|
covariant FindInPageRepositoryProvider provider,
|
||||||
) {
|
) {
|
||||||
return call(
|
return call(
|
||||||
provider.tabId,
|
provider.tabId,
|
||||||
@@ -78,31 +78,30 @@ class ReaderabilityScriptServiceFamily extends Family<AsyncValue<void>> {
|
|||||||
_allTransitiveDependencies;
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get name => r'readerabilityScriptServiceProvider';
|
String? get name => r'findInPageRepositoryProvider';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [ReaderabilityScriptService].
|
/// See also [FindInPageRepository].
|
||||||
class ReaderabilityScriptServiceProvider
|
class FindInPageRepositoryProvider
|
||||||
extends AutoDisposeAsyncNotifierProviderImpl<ReaderabilityScriptService,
|
extends AutoDisposeNotifierProviderImpl<FindInPageRepository, void> {
|
||||||
void> {
|
/// See also [FindInPageRepository].
|
||||||
/// See also [ReaderabilityScriptService].
|
FindInPageRepositoryProvider(
|
||||||
ReaderabilityScriptServiceProvider(
|
String? tabId,
|
||||||
String tabId,
|
|
||||||
) : this._internal(
|
) : this._internal(
|
||||||
() => ReaderabilityScriptService()..tabId = tabId,
|
() => FindInPageRepository()..tabId = tabId,
|
||||||
from: readerabilityScriptServiceProvider,
|
from: findInPageRepositoryProvider,
|
||||||
name: r'readerabilityScriptServiceProvider',
|
name: r'findInPageRepositoryProvider',
|
||||||
debugGetCreateSourceHash:
|
debugGetCreateSourceHash:
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
? null
|
? null
|
||||||
: _$readerabilityScriptServiceHash,
|
: _$findInPageRepositoryHash,
|
||||||
dependencies: ReaderabilityScriptServiceFamily._dependencies,
|
dependencies: FindInPageRepositoryFamily._dependencies,
|
||||||
allTransitiveDependencies:
|
allTransitiveDependencies:
|
||||||
ReaderabilityScriptServiceFamily._allTransitiveDependencies,
|
FindInPageRepositoryFamily._allTransitiveDependencies,
|
||||||
tabId: tabId,
|
tabId: tabId,
|
||||||
);
|
);
|
||||||
|
|
||||||
ReaderabilityScriptServiceProvider._internal(
|
FindInPageRepositoryProvider._internal(
|
||||||
super._createNotifier, {
|
super._createNotifier, {
|
||||||
required super.name,
|
required super.name,
|
||||||
required super.dependencies,
|
required super.dependencies,
|
||||||
@@ -112,11 +111,11 @@ class ReaderabilityScriptServiceProvider
|
|||||||
required this.tabId,
|
required this.tabId,
|
||||||
}) : super.internal();
|
}) : super.internal();
|
||||||
|
|
||||||
final String tabId;
|
final String? tabId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<void> runNotifierBuild(
|
void runNotifierBuild(
|
||||||
covariant ReaderabilityScriptService notifier,
|
covariant FindInPageRepository notifier,
|
||||||
) {
|
) {
|
||||||
return notifier.build(
|
return notifier.build(
|
||||||
tabId,
|
tabId,
|
||||||
@@ -124,10 +123,10 @@ class ReaderabilityScriptServiceProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Override overrideWith(ReaderabilityScriptService Function() create) {
|
Override overrideWith(FindInPageRepository Function() create) {
|
||||||
return ProviderOverride(
|
return ProviderOverride(
|
||||||
origin: this,
|
origin: this,
|
||||||
override: ReaderabilityScriptServiceProvider._internal(
|
override: FindInPageRepositoryProvider._internal(
|
||||||
() => create()..tabId = tabId,
|
() => create()..tabId = tabId,
|
||||||
from: from,
|
from: from,
|
||||||
name: null,
|
name: null,
|
||||||
@@ -140,14 +139,14 @@ class ReaderabilityScriptServiceProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AutoDisposeAsyncNotifierProviderElement<ReaderabilityScriptService, void>
|
AutoDisposeNotifierProviderElement<FindInPageRepository, void>
|
||||||
createElement() {
|
createElement() {
|
||||||
return _ReaderabilityScriptServiceProviderElement(this);
|
return _FindInPageRepositoryProviderElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return other is ReaderabilityScriptServiceProvider && other.tabId == tabId;
|
return other is FindInPageRepositoryProvider && other.tabId == tabId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -159,19 +158,18 @@ class ReaderabilityScriptServiceProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin ReaderabilityScriptServiceRef
|
mixin FindInPageRepositoryRef on AutoDisposeNotifierProviderRef<void> {
|
||||||
on AutoDisposeAsyncNotifierProviderRef<void> {
|
|
||||||
/// The parameter `tabId` of this provider.
|
/// The parameter `tabId` of this provider.
|
||||||
String get tabId;
|
String? get tabId;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ReaderabilityScriptServiceProviderElement
|
class _FindInPageRepositoryProviderElement
|
||||||
extends AutoDisposeAsyncNotifierProviderElement<ReaderabilityScriptService,
|
extends AutoDisposeNotifierProviderElement<FindInPageRepository, void>
|
||||||
void> with ReaderabilityScriptServiceRef {
|
with FindInPageRepositoryRef {
|
||||||
_ReaderabilityScriptServiceProviderElement(super.provider);
|
_FindInPageRepositoryProviderElement(super.provider);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get tabId => (origin as ReaderabilityScriptServiceProvider).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
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'find_in_page_visibility.g.dart';
|
||||||
|
|
||||||
|
@Riverpod()
|
||||||
|
class FindInPageVisibilityController extends _$FindInPageVisibilityController {
|
||||||
|
void show() {
|
||||||
|
state = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hide() {
|
||||||
|
state = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool build() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'find_in_page_visibility.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$findInPageVisibilityControllerHash() =>
|
||||||
|
r'365819c6b181ff2cefc022360413a918457e06d7';
|
||||||
|
|
||||||
|
/// See also [FindInPageVisibilityController].
|
||||||
|
@ProviderFor(FindInPageVisibilityController)
|
||||||
|
final findInPageVisibilityControllerProvider =
|
||||||
|
AutoDisposeNotifierProvider<FindInPageVisibilityController, bool>.internal(
|
||||||
|
FindInPageVisibilityController.new,
|
||||||
|
name: r'findInPageVisibilityControllerProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$findInPageVisibilityControllerHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$FindInPageVisibilityController = AutoDisposeNotifier<bool>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/find_in_page/domain/repositories/find_in_page.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/find_in_page/presentation/controllers/find_in_page_visibility.dart';
|
||||||
|
|
||||||
|
class FindInPageWidget extends HookConsumerWidget {
|
||||||
|
final EdgeInsetsGeometry padding;
|
||||||
|
|
||||||
|
const FindInPageWidget({this.padding = EdgeInsets.zero});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final showFindInPage = ref.watch(findInPageVisibilityControllerProvider);
|
||||||
|
final findInteractionController =
|
||||||
|
ref.watch(findInPageRepositoryProvider(null).notifier);
|
||||||
|
|
||||||
|
final textController = useTextEditingController();
|
||||||
|
|
||||||
|
return Visibility(
|
||||||
|
visible: showFindInPage,
|
||||||
|
child: Padding(
|
||||||
|
padding: padding,
|
||||||
|
child: Material(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
controller: textController,
|
||||||
|
autofocus: true,
|
||||||
|
autocorrect: false,
|
||||||
|
decoration: const InputDecoration.collapsed(
|
||||||
|
hintText: 'Find in page',
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.text,
|
||||||
|
onSubmitted: (value) async {
|
||||||
|
if (value == '') {
|
||||||
|
await findInteractionController.clearMatches();
|
||||||
|
} else {
|
||||||
|
await findInteractionController.findAll(text: value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
HookConsumer(
|
||||||
|
builder: (context, ref, child) {
|
||||||
|
final searchResult = ref.watch(
|
||||||
|
selectedTabStateProvider
|
||||||
|
.select((state) => state?.findResultState),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (searchResult != null) {
|
||||||
|
if (searchResult.numberOfMatches == 0) {
|
||||||
|
return const Text('Not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
'${searchResult.activeMatchOrdinal + 1} of ${searchResult.numberOfMatches}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.arrow_upward),
|
||||||
|
onPressed: () async {
|
||||||
|
await findInteractionController.findNext(forward: false);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.arrow_downward),
|
||||||
|
onPressed: () async {
|
||||||
|
await findInteractionController.findNext();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.clear),
|
||||||
|
onPressed: () async {
|
||||||
|
ref
|
||||||
|
.read(findInPageVisibilityControllerProvider.notifier)
|
||||||
|
.hide();
|
||||||
|
|
||||||
|
await findInteractionController.clearMatches();
|
||||||
|
textController.clear();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'readerable.g.dart';
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
GeckoReaderableService readerableService(ReaderableServiceRef ref) {
|
||||||
|
final service = GeckoReaderableService.setUp();
|
||||||
|
|
||||||
|
ref.onDispose(() {
|
||||||
|
service.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Riverpod()
|
||||||
|
Stream<bool> appearanceButtonVisibility(AppearanceButtonVisibilityRef ref) {
|
||||||
|
final service = ref.watch(readerableServiceProvider);
|
||||||
|
return service.appearanceVisibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Riverpod()
|
||||||
|
Stream<bool> readerButtonVisibility(ReaderButtonVisibilityRef ref) {
|
||||||
|
final service = ref.watch(readerableServiceProvider);
|
||||||
|
return service.readerVisibility;
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'readerable.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$readerableServiceHash() => r'aad722c3869b4ce8dbe336fada733b7d102434c5';
|
||||||
|
|
||||||
|
/// See also [readerableService].
|
||||||
|
@ProviderFor(readerableService)
|
||||||
|
final readerableServiceProvider = Provider<GeckoReaderableService>.internal(
|
||||||
|
readerableService,
|
||||||
|
name: r'readerableServiceProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$readerableServiceHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ReaderableServiceRef = ProviderRef<GeckoReaderableService>;
|
||||||
|
String _$appearanceButtonVisibilityHash() =>
|
||||||
|
r'996ec32ee111cfa713230a50fea3ae3a9984df7c';
|
||||||
|
|
||||||
|
/// See also [appearanceButtonVisibility].
|
||||||
|
@ProviderFor(appearanceButtonVisibility)
|
||||||
|
final appearanceButtonVisibilityProvider =
|
||||||
|
AutoDisposeStreamProvider<bool>.internal(
|
||||||
|
appearanceButtonVisibility,
|
||||||
|
name: r'appearanceButtonVisibilityProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$appearanceButtonVisibilityHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef AppearanceButtonVisibilityRef = AutoDisposeStreamProviderRef<bool>;
|
||||||
|
String _$readerButtonVisibilityHash() =>
|
||||||
|
r'd58132aa4e9a5ba311a0b5d99b9f8416e952b1ab';
|
||||||
|
|
||||||
|
/// See also [readerButtonVisibility].
|
||||||
|
@ProviderFor(readerButtonVisibility)
|
||||||
|
final readerButtonVisibilityProvider = AutoDisposeStreamProvider<bool>.internal(
|
||||||
|
readerButtonVisibility,
|
||||||
|
name: r'readerButtonVisibilityProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$readerButtonVisibilityHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef ReaderButtonVisibilityRef = AutoDisposeStreamProviderRef<bool>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/readerview/domain/providers/readerable.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'readerable.g.dart';
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class ReaderableScreenController extends _$ReaderableScreenController {
|
||||||
|
late GeckoReaderableService _service;
|
||||||
|
|
||||||
|
Future<void> toggleReaderView(bool enable) async {
|
||||||
|
state = const AsyncValue.loading();
|
||||||
|
final eventChange = ref.read(eventServiceProvider).readerableEvents.first;
|
||||||
|
final toggle = _service.toggleReaderView(enable);
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(() => Future.wait([toggle, eventChange]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> build() {
|
||||||
|
_service = ref.watch(readerableServiceProvider);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-11
@@ -1,27 +1,27 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
part of 'switch_new_tab.dart';
|
part of 'readerable.dart';
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$switchNewTabControllerHash() =>
|
String _$readerableScreenControllerHash() =>
|
||||||
r'7ebfea953aeb81c279ea11254ff0ad558e6a949f';
|
r'463c032a6d07936954fead58589101ccb31c2765';
|
||||||
|
|
||||||
/// See also [SwitchNewTabController].
|
/// See also [ReaderableScreenController].
|
||||||
@ProviderFor(SwitchNewTabController)
|
@ProviderFor(ReaderableScreenController)
|
||||||
final switchNewTabControllerProvider =
|
final readerableScreenControllerProvider =
|
||||||
AsyncNotifierProvider<SwitchNewTabController, void>.internal(
|
AsyncNotifierProvider<ReaderableScreenController, void>.internal(
|
||||||
SwitchNewTabController.new,
|
ReaderableScreenController.new,
|
||||||
name: r'switchNewTabControllerProvider',
|
name: r'readerableScreenControllerProvider',
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
? null
|
? null
|
||||||
: _$switchNewTabControllerHash,
|
: _$readerableScreenControllerHash,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef _$SwitchNewTabController = 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
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/readerview/domain/providers/readerable.dart';
|
||||||
|
|
||||||
|
class ReaderAppearanceButton extends HookConsumerWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final buttonVisible = ref.watch(
|
||||||
|
appearanceButtonVisibilityProvider
|
||||||
|
.select((value) => value.valueOrNull ?? false),
|
||||||
|
);
|
||||||
|
|
||||||
|
return FloatingActionButton(
|
||||||
|
onPressed: buttonVisible
|
||||||
|
? () async {
|
||||||
|
await ref.read(readerableServiceProvider).onAppearanceButtonTap();
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: const Icon(MdiIcons.formatFont),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/entities/readerable_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/readerview/domain/providers/readerable.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/readerview/presentation/controllers/readerable.dart';
|
||||||
|
import 'package:lensai/presentation/widgets/animate_gradient_shader.dart';
|
||||||
|
|
||||||
|
class ReaderButton extends HookConsumerWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final colorScheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
|
final readerChanging = ref.watch(readerableScreenControllerProvider);
|
||||||
|
|
||||||
|
final readerabilityState = ref.watch(
|
||||||
|
selectedTabStateProvider.select(
|
||||||
|
(state) => state?.readerableState ?? ReaderableState.$default(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final readerButtonVisible = ref.watch(
|
||||||
|
readerButtonVisibilityProvider
|
||||||
|
.select((value) => value.valueOrNull ?? false),
|
||||||
|
);
|
||||||
|
|
||||||
|
final icon = useMemoized(
|
||||||
|
() => readerabilityState.active
|
||||||
|
? Icon(
|
||||||
|
MdiIcons.bookOpen,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
)
|
||||||
|
: const Icon(
|
||||||
|
MdiIcons.bookOpenOutline,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
[readerabilityState.active],
|
||||||
|
);
|
||||||
|
|
||||||
|
return Visibility(
|
||||||
|
visible: readerButtonVisible,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 15.0,
|
||||||
|
horizontal: 8.0,
|
||||||
|
),
|
||||||
|
child: readerChanging.when(
|
||||||
|
data: (_) => Visibility(
|
||||||
|
visible: readerButtonVisible,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: readerChanging.isLoading
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
await ref
|
||||||
|
.read(readerableScreenControllerProvider.notifier)
|
||||||
|
.toggleReaderView(!readerabilityState.active);
|
||||||
|
},
|
||||||
|
child: icon,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
error: (error, stackTrace) => SizedBox.shrink(),
|
||||||
|
loading: () => AnimateGradientShader(
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
primaryEnd: Alignment.bottomLeft,
|
||||||
|
secondaryEnd: Alignment.topRight,
|
||||||
|
primaryColors: [
|
||||||
|
colorScheme.primary,
|
||||||
|
colorScheme.primaryContainer,
|
||||||
|
],
|
||||||
|
secondaryColors: [
|
||||||
|
colorScheme.secondary,
|
||||||
|
colorScheme.secondaryContainer,
|
||||||
|
],
|
||||||
|
child: icon,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,14 +8,22 @@ class TabLinkDao extends DatabaseAccessor<TabDatabase> with _$TabLinkDaoMixin {
|
|||||||
TabLinkDao(super.db);
|
TabLinkDao(super.db);
|
||||||
|
|
||||||
Selectable<String> topicTabIds(String? topicId) {
|
Selectable<String> topicTabIds(String? topicId) {
|
||||||
final query = (selectOnly(db.tabLink)
|
final query = selectOnly(db.tabLink)
|
||||||
..addColumns([db.tabLink.id])
|
..addColumns([db.tabLink.id])
|
||||||
..where(
|
..where(
|
||||||
(topicId == null)
|
(topicId == null)
|
||||||
? db.tabLink.topicId.isNull()
|
? db.tabLink.topicId.isNull()
|
||||||
: db.tabLink.topicId.equals(topicId),
|
: db.tabLink.topicId.equals(topicId),
|
||||||
)
|
)
|
||||||
..orderBy([OrderingTerm.asc(db.tabLink.id)]));
|
..orderBy([OrderingTerm.asc(db.tabLink.id)]);
|
||||||
|
|
||||||
|
return query.map((row) => row.read(db.tabLink.id)!);
|
||||||
|
}
|
||||||
|
|
||||||
|
SingleOrNullSelectable<String> tabTopicId(String tabId) {
|
||||||
|
final query = selectOnly(db.tabLink)
|
||||||
|
..addColumns([db.tabLink.topicId])
|
||||||
|
..where(db.tabLink.id.equals(tabId));
|
||||||
|
|
||||||
return query.map((row) => row.read(db.tabLink.id)!);
|
return query.map((row) => row.read(db.tabLink.id)!);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,42 +9,6 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||||||
|
|
||||||
part 'providers.g.dart';
|
part 'providers.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
|
||||||
class SelectedTopic extends _$SelectedTopic {
|
|
||||||
void setTopic(String id) {
|
|
||||||
state = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void toggleTopic(String id) {
|
|
||||||
if (state == id) {
|
|
||||||
clearTopic();
|
|
||||||
} else {
|
|
||||||
setTopic(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearTopic() {
|
|
||||||
state = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? build() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod()
|
|
||||||
Stream<TopicData?> selectedTopicData(SelectedTopicDataRef ref) {
|
|
||||||
final db = ref.watch(tabDatabaseProvider);
|
|
||||||
final selectedTopic = ref.watch(selectedTopicProvider);
|
|
||||||
|
|
||||||
if (selectedTopic != null) {
|
|
||||||
return db.topicDao.getTopicData(selectedTopic).watchSingleOrNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Stream.value(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Future<Color> unusedRandomTopicColor(UnusedRandomTopicColorRef ref) async {
|
Future<Color> unusedRandomTopicColor(UnusedRandomTopicColorRef ref) async {
|
||||||
final repository = ref.watch(topicRepositoryProvider.notifier);
|
final repository = ref.watch(topicRepositoryProvider.notifier);
|
||||||
@@ -67,7 +31,13 @@ Stream<List<TopicDataWithCount>> topicsWithCount(TopicsWithCountRef ref) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod()
|
@Riverpod()
|
||||||
Stream<List<String>> topicTabIds(TopicTabIdsRef ref, String topicId) {
|
Stream<List<String>> topicTabIds(TopicTabIdsRef ref, String? topicId) {
|
||||||
final db = ref.watch(tabDatabaseProvider);
|
final db = ref.watch(tabDatabaseProvider);
|
||||||
return db.tabLinkDao.topicTabIds(topicId).watch();
|
return db.tabLinkDao.topicTabIds(topicId).watch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Riverpod()
|
||||||
|
Stream<String?> tabTopicId(TabTopicIdRef ref, String tabId) {
|
||||||
|
final db = ref.watch(tabDatabaseProvider);
|
||||||
|
return db.tabLinkDao.tabTopicId(tabId).watchSingleOrNull();
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,22 +6,6 @@ part of 'providers.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$selectedTopicDataHash() => r'fa450784052498014f592c356bde4ff5ec675281';
|
|
||||||
|
|
||||||
/// See also [selectedTopicData].
|
|
||||||
@ProviderFor(selectedTopicData)
|
|
||||||
final selectedTopicDataProvider =
|
|
||||||
AutoDisposeStreamProvider<TopicData?>.internal(
|
|
||||||
selectedTopicData,
|
|
||||||
name: r'selectedTopicDataProvider',
|
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$selectedTopicDataHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef SelectedTopicDataRef = AutoDisposeStreamProviderRef<TopicData?>;
|
|
||||||
String _$unusedRandomTopicColorHash() =>
|
String _$unusedRandomTopicColorHash() =>
|
||||||
r'099730b0d987cc37bcae4ef5c999cbebfa67d7da';
|
r'099730b0d987cc37bcae4ef5c999cbebfa67d7da';
|
||||||
|
|
||||||
@@ -56,7 +40,7 @@ final topicsWithCountProvider =
|
|||||||
|
|
||||||
typedef TopicsWithCountRef
|
typedef TopicsWithCountRef
|
||||||
= AutoDisposeStreamProviderRef<List<TopicDataWithCount>>;
|
= AutoDisposeStreamProviderRef<List<TopicDataWithCount>>;
|
||||||
String _$topicTabIdsHash() => r'43719c70e01cf9e030d75171405ab9650936ddf8';
|
String _$topicTabIdsHash() => r'f7ce2633804421a22df1efc42eb4d19d440d9fd3';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -90,7 +74,7 @@ class TopicTabIdsFamily extends Family<AsyncValue<List<String>>> {
|
|||||||
|
|
||||||
/// See also [topicTabIds].
|
/// See also [topicTabIds].
|
||||||
TopicTabIdsProvider call(
|
TopicTabIdsProvider call(
|
||||||
String topicId,
|
String? topicId,
|
||||||
) {
|
) {
|
||||||
return TopicTabIdsProvider(
|
return TopicTabIdsProvider(
|
||||||
topicId,
|
topicId,
|
||||||
@@ -125,7 +109,7 @@ class TopicTabIdsFamily extends Family<AsyncValue<List<String>>> {
|
|||||||
class TopicTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
class TopicTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
||||||
/// See also [topicTabIds].
|
/// See also [topicTabIds].
|
||||||
TopicTabIdsProvider(
|
TopicTabIdsProvider(
|
||||||
String topicId,
|
String? topicId,
|
||||||
) : this._internal(
|
) : this._internal(
|
||||||
(ref) => topicTabIds(
|
(ref) => topicTabIds(
|
||||||
ref as TopicTabIdsRef,
|
ref as TopicTabIdsRef,
|
||||||
@@ -153,7 +137,7 @@ class TopicTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
|||||||
required this.topicId,
|
required this.topicId,
|
||||||
}) : super.internal();
|
}) : super.internal();
|
||||||
|
|
||||||
final String topicId;
|
final String? topicId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Override overrideWith(
|
Override overrideWith(
|
||||||
@@ -194,7 +178,7 @@ class TopicTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
|||||||
|
|
||||||
mixin TopicTabIdsRef on AutoDisposeStreamProviderRef<List<String>> {
|
mixin TopicTabIdsRef on AutoDisposeStreamProviderRef<List<String>> {
|
||||||
/// The parameter `topicId` of this provider.
|
/// The parameter `topicId` of this provider.
|
||||||
String get topicId;
|
String? get topicId;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TopicTabIdsProviderElement
|
class _TopicTabIdsProviderElement
|
||||||
@@ -202,23 +186,135 @@ class _TopicTabIdsProviderElement
|
|||||||
_TopicTabIdsProviderElement(super.provider);
|
_TopicTabIdsProviderElement(super.provider);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get topicId => (origin as TopicTabIdsProvider).topicId;
|
String? get topicId => (origin as TopicTabIdsProvider).topicId;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$selectedTopicHash() => r'f4e1c0620971a0b7501ee9aff0d5b41da3130ba0';
|
String _$tabTopicIdHash() => r'284164ac3acd9be3ba4e15eba99fc8d97602ee84';
|
||||||
|
|
||||||
/// See also [SelectedTopic].
|
/// See also [tabTopicId].
|
||||||
@ProviderFor(SelectedTopic)
|
@ProviderFor(tabTopicId)
|
||||||
final selectedTopicProvider = NotifierProvider<SelectedTopic, String?>.internal(
|
const tabTopicIdProvider = TabTopicIdFamily();
|
||||||
SelectedTopic.new,
|
|
||||||
name: r'selectedTopicProvider',
|
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$selectedTopicHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef _$SelectedTopic = Notifier<String?>;
|
/// See also [tabTopicId].
|
||||||
|
class TabTopicIdFamily extends Family<AsyncValue<String?>> {
|
||||||
|
/// See also [tabTopicId].
|
||||||
|
const TabTopicIdFamily();
|
||||||
|
|
||||||
|
/// See also [tabTopicId].
|
||||||
|
TabTopicIdProvider call(
|
||||||
|
String tabId,
|
||||||
|
) {
|
||||||
|
return TabTopicIdProvider(
|
||||||
|
tabId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TabTopicIdProvider getProviderOverride(
|
||||||
|
covariant TabTopicIdProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
provider.tabId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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'tabTopicIdProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [tabTopicId].
|
||||||
|
class TabTopicIdProvider extends AutoDisposeStreamProvider<String?> {
|
||||||
|
/// See also [tabTopicId].
|
||||||
|
TabTopicIdProvider(
|
||||||
|
String tabId,
|
||||||
|
) : this._internal(
|
||||||
|
(ref) => tabTopicId(
|
||||||
|
ref as TabTopicIdRef,
|
||||||
|
tabId,
|
||||||
|
),
|
||||||
|
from: tabTopicIdProvider,
|
||||||
|
name: r'tabTopicIdProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$tabTopicIdHash,
|
||||||
|
dependencies: TabTopicIdFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
TabTopicIdFamily._allTransitiveDependencies,
|
||||||
|
tabId: tabId,
|
||||||
|
);
|
||||||
|
|
||||||
|
TabTopicIdProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.tabId,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String tabId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(
|
||||||
|
Stream<String?> Function(TabTopicIdRef provider) create,
|
||||||
|
) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: TabTopicIdProvider._internal(
|
||||||
|
(ref) => create(ref as TabTopicIdRef),
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
tabId: tabId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeStreamProviderElement<String?> createElement() {
|
||||||
|
return _TabTopicIdProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is TabTopicIdProvider && other.tabId == tabId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, tabId.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin TabTopicIdRef on AutoDisposeStreamProviderRef<String?> {
|
||||||
|
/// The parameter `tabId` of this provider.
|
||||||
|
String get tabId;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TabTopicIdProviderElement
|
||||||
|
extends AutoDisposeStreamProviderElement<String?> with TabTopicIdRef {
|
||||||
|
_TabTopicIdProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tabId => (origin as TabTopicIdProvider).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
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import 'package:lensai/features/geckoview/features/topics/data/models/topic_data.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'selected_topic.g.dart';
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class SelectedTopic extends _$SelectedTopic {
|
||||||
|
void setTopic(String id) {
|
||||||
|
state = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleTopic(String id) {
|
||||||
|
if (state == id) {
|
||||||
|
clearTopic();
|
||||||
|
} else {
|
||||||
|
setTopic(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearTopic() {
|
||||||
|
state = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? build() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Riverpod()
|
||||||
|
Stream<TopicData?> selectedTopicData(SelectedTopicDataRef ref) {
|
||||||
|
final db = ref.watch(tabDatabaseProvider);
|
||||||
|
final selectedTopic = ref.watch(selectedTopicProvider);
|
||||||
|
|
||||||
|
if (selectedTopic != null) {
|
||||||
|
return db.topicDao.getTopicData(selectedTopic).watchSingleOrNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stream.value(null);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'selected_topic.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$selectedTopicDataHash() => r'fa450784052498014f592c356bde4ff5ec675281';
|
||||||
|
|
||||||
|
/// See also [selectedTopicData].
|
||||||
|
@ProviderFor(selectedTopicData)
|
||||||
|
final selectedTopicDataProvider =
|
||||||
|
AutoDisposeStreamProvider<TopicData?>.internal(
|
||||||
|
selectedTopicData,
|
||||||
|
name: r'selectedTopicDataProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$selectedTopicDataHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef SelectedTopicDataRef = AutoDisposeStreamProviderRef<TopicData?>;
|
||||||
|
String _$selectedTopicHash() => r'f4e1c0620971a0b7501ee9aff0d5b41da3130ba0';
|
||||||
|
|
||||||
|
/// See also [SelectedTopic].
|
||||||
|
@ProviderFor(SelectedTopic)
|
||||||
|
final selectedTopicProvider = NotifierProvider<SelectedTopic, String?>.internal(
|
||||||
|
SelectedTopic.new,
|
||||||
|
name: r'selectedTopicProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$selectedTopicHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$SelectedTopic = Notifier<String?>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:lensai/features/geckoview/domain/repositories/selected_tab.dart';
|
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
|
||||||
|
import 'package:lensai/features/geckoview/domain/providers/tab_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/topics/data/database/database.dart';
|
import 'package:lensai/features/geckoview/features/topics/data/database/database.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
||||||
@@ -17,7 +18,7 @@ class TabLinkRepository extends _$TabLinkRepository {
|
|||||||
|
|
||||||
//Sync existing tabs
|
//Sync existing tabs
|
||||||
ref.listen(
|
ref.listen(
|
||||||
tabRepositoryProvider.select((tabs) => tabs.keys.toList()),
|
tabStatesProvider.select((tabs) => tabs.keys.toList()),
|
||||||
(previous, next) async {
|
(previous, next) async {
|
||||||
//No empty list to avoid data loss
|
//No empty list to avoid data loss
|
||||||
if (next.isNotEmpty) {
|
if (next.isNotEmpty) {
|
||||||
@@ -27,7 +28,7 @@ class TabLinkRepository extends _$TabLinkRepository {
|
|||||||
);
|
);
|
||||||
|
|
||||||
ref.listen(
|
ref.listen(
|
||||||
selectedTabControllerProvider,
|
selectedTabProvider,
|
||||||
(previous, next) async {
|
(previous, next) async {
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
await _db.tabLinkDao.touchTabLink(next, timestamp: DateTime.now());
|
await _db.tabLinkDao.touchTabLink(next, timestamp: DateTime.now());
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'tab_link.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$tabLinkRepositoryHash() => r'e85d88fadb8133c3ef1e38f0176694a12a749397';
|
String _$tabLinkRepositoryHash() => r'c4944c1f6792bd725f889b1d6e12946b1439be11';
|
||||||
|
|
||||||
/// See also [TabLinkRepository].
|
/// See also [TabLinkRepository].
|
||||||
@ProviderFor(TabLinkRepository)
|
@ProviderFor(TabLinkRepository)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/data/models/topic_data.dart';
|
import 'package:lensai/features/geckoview/features/topics/data/models/topic_data.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/topics/domain/providers/selected_topic.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/repositories/topic.dart';
|
import 'package:lensai/features/geckoview/features/topics/domain/repositories/topic.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/presentation/widgets/topic_dialog.dart';
|
import 'package:lensai/features/geckoview/features/topics/presentation/widgets/topic_dialog.dart';
|
||||||
import 'package:skeletonizer/skeletonizer.dart';
|
import 'package:skeletonizer/skeletonizer.dart';
|
||||||
@@ -148,7 +149,7 @@ class TopicListScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
body: HookConsumer(
|
body: HookConsumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
final topicsAsync = ref.watch(topicRepositoryProvider);
|
final topicsAsync = ref.watch(topicsWithCountProvider);
|
||||||
final selectedTopic = ref.watch(selectedTopicProvider);
|
final selectedTopic = ref.watch(selectedTopicProvider);
|
||||||
|
|
||||||
return Skeletonizer(
|
return Skeletonizer(
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ 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/routing/routes.dart';
|
import 'package:lensai/core/routing/routes.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/repositories/topic.dart';
|
import 'package:lensai/features/geckoview/features/topics/domain/providers/selected_topic.dart';
|
||||||
import 'package:lensai/presentation/widgets/selectable_chips.dart';
|
import 'package:lensai/presentation/widgets/selectable_chips.dart';
|
||||||
|
|
||||||
class TopicChips extends HookConsumerWidget {
|
class TopicChips extends HookConsumerWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final topicsAsync = ref.watch(topicRepositoryProvider);
|
final topicsAsync = ref.watch(topicsWithCountProvider);
|
||||||
final selectedTopic = ref
|
final selectedTopic = ref
|
||||||
.watch(selectedTopicDataProvider.select((value) => value.valueOrNull));
|
.watch(selectedTopicDataProvider.select((value) => value.valueOrNull));
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ bool useWhiteForeground(Color backgroundColor, {double bias = 0.0}) {
|
|||||||
|
|
||||||
// New:
|
// New:
|
||||||
final v = sqrt(
|
final v = sqrt(
|
||||||
pow(backgroundColor.red, 2) * 0.299 +
|
pow(backgroundColor.r, 2) * 0.299 +
|
||||||
pow(backgroundColor.green, 2) * 0.587 +
|
pow(backgroundColor.g, 2) * 0.587 +
|
||||||
pow(backgroundColor.blue, 2) * 0.114,
|
pow(backgroundColor.b, 2) * 0.114,
|
||||||
).round();
|
).round();
|
||||||
return v < (130 + bias);
|
return v < (130 + bias);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -3,12 +3,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/sheets/create_tab.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/speech_to_text_button.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/providers.dart';
|
import 'package:lensai/features/kagi/utils/url_builder.dart' as uri_builder;
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/sheets/shared_content_sheet.dart';
|
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/speech_to_text_button.dart';
|
|
||||||
import 'package:lensai/features/search_browser/utils/url_builder.dart'
|
|
||||||
as uri_builder;
|
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
||||||
+3
-3
@@ -8,9 +8,9 @@ import 'package:lensai/features/bangs/domain/providers.dart';
|
|||||||
import 'package:lensai/features/bangs/domain/repositories/data.dart';
|
import 'package:lensai/features/bangs/domain/repositories/data.dart';
|
||||||
import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart';
|
import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart';
|
||||||
import 'package:lensai/features/bangs/presentation/widgets/search_field.dart';
|
import 'package:lensai/features/bangs/presentation/widgets/search_field.dart';
|
||||||
import 'package:lensai/features/search_browser/domain/providers.dart';
|
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/controllers/bottom_sheet.dart';
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/sheets/create_tab.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/sheets/shared_content_sheet.dart';
|
import 'package:lensai/features/geckoview/features/controllers/bottom_sheet.dart';
|
||||||
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
||||||
import 'package:lensai/presentation/widgets/selectable_chips.dart';
|
import 'package:lensai/presentation/widgets/selectable_chips.dart';
|
||||||
|
|
||||||
+2
-3
@@ -6,10 +6,9 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
import 'package:flutter_pdf_text/flutter_pdf_text.dart';
|
import 'package:flutter_pdf_text/flutter_pdf_text.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/sheets/create_tab.dart';
|
||||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||||
import 'package:lensai/features/search_browser/presentation/widgets/sheets/shared_content_sheet.dart';
|
import 'package:lensai/features/kagi/utils/url_builder.dart' as uri_builder;
|
||||||
import 'package:lensai/features/search_browser/utils/url_builder.dart'
|
|
||||||
as uri_builder;
|
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||||
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
import 'package:lensai/features/share_intent/domain/entities/shared_content.dart';
|
||||||
@@ -8,7 +8,7 @@ Set<HostSource>? parseHostSources(List<String>? input) => input
|
|||||||
(list) =>
|
(list) =>
|
||||||
HostSource.values.firstWhereOrNull((source) => source.name == list),
|
HostSource.values.firstWhereOrNull((source) => source.name == list),
|
||||||
)
|
)
|
||||||
.whereNotNull()
|
.nonNulls
|
||||||
.toSet();
|
.toSet();
|
||||||
|
|
||||||
ThemeMode? parseThemeMode(int? index) {
|
ThemeMode? parseThemeMode(int? index) {
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
|
|
||||||
abstract interface class ITab {
|
|
||||||
String get id;
|
|
||||||
Uri get url;
|
|
||||||
String? get title;
|
|
||||||
String? get topicId;
|
|
||||||
Favicon? get favicon;
|
|
||||||
Uint8List? get screenshot;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
class ConsistentController {
|
|
||||||
final InAppWebViewController? value;
|
|
||||||
|
|
||||||
const ConsistentController(this.value);
|
|
||||||
|
|
||||||
@override
|
|
||||||
// ignore: avoid_dynamic_calls
|
|
||||||
int get hashCode => value?.platform.id.hashCode ?? -1;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
if (identical(this, other)) return true;
|
|
||||||
if (other is! ConsistentController) return false;
|
|
||||||
return hashCode == other.hashCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import 'package:copy_with_extension/copy_with_extension.dart';
|
|
||||||
import 'package:fast_equatable/fast_equatable.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
|
||||||
import 'package:lensai/core/uuid.dart';
|
|
||||||
import 'package:lensai/data/models/web_page_info.dart';
|
|
||||||
|
|
||||||
part 'web_view_page.g.dart';
|
|
||||||
|
|
||||||
typedef PageHistory = ({bool canGoBack, bool canGoForward});
|
|
||||||
|
|
||||||
@CopyWith()
|
|
||||||
class WebViewPage extends WebPageInfo with FastEquatable implements ITab {
|
|
||||||
@override
|
|
||||||
@CopyWithField(immutable: true)
|
|
||||||
final String id;
|
|
||||||
|
|
||||||
final InAppWebViewController? controller;
|
|
||||||
|
|
||||||
// ignore: missing_field_in_equatable_props
|
|
||||||
final SslError? sslError;
|
|
||||||
|
|
||||||
@override
|
|
||||||
final String? topicId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
final Uint8List? screenshot;
|
|
||||||
|
|
||||||
final PageHistory pageHistory;
|
|
||||||
|
|
||||||
WebViewPage({
|
|
||||||
required this.id,
|
|
||||||
required this.controller,
|
|
||||||
required super.url,
|
|
||||||
required this.sslError,
|
|
||||||
required super.title,
|
|
||||||
required this.topicId,
|
|
||||||
required super.favicon,
|
|
||||||
required this.screenshot,
|
|
||||||
required this.pageHistory,
|
|
||||||
});
|
|
||||||
|
|
||||||
WebViewPage.create({
|
|
||||||
String? id,
|
|
||||||
this.controller,
|
|
||||||
required super.url,
|
|
||||||
this.sslError,
|
|
||||||
super.title,
|
|
||||||
this.topicId,
|
|
||||||
super.favicon,
|
|
||||||
this.screenshot,
|
|
||||||
this.pageHistory = (canGoBack: false, canGoForward: false),
|
|
||||||
}) : id = id ?? uuid.v7();
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get cacheHash => true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get hashParameters => [
|
|
||||||
id,
|
|
||||||
controller,
|
|
||||||
super.url,
|
|
||||||
sslError?.toString(),
|
|
||||||
title,
|
|
||||||
topicId,
|
|
||||||
favicon?.toString(),
|
|
||||||
screenshot,
|
|
||||||
pageHistory,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'web_view_page.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// CopyWithGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
abstract class _$WebViewPageCWProxy {
|
|
||||||
WebViewPage controller(InvalidType controller);
|
|
||||||
|
|
||||||
WebViewPage url(Uri url);
|
|
||||||
|
|
||||||
WebViewPage sslError(InvalidType sslError);
|
|
||||||
|
|
||||||
WebViewPage title(String? title);
|
|
||||||
|
|
||||||
WebViewPage topicId(String? topicId);
|
|
||||||
|
|
||||||
WebViewPage favicon(BrowserIcon? favicon);
|
|
||||||
|
|
||||||
WebViewPage screenshot(Uint8List? screenshot);
|
|
||||||
|
|
||||||
WebViewPage pageHistory(({bool canGoBack, bool canGoForward}) pageHistory);
|
|
||||||
|
|
||||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `WebViewPage(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
|
||||||
///
|
|
||||||
/// Usage
|
|
||||||
/// ```dart
|
|
||||||
/// WebViewPage(...).copyWith(id: 12, name: "My name")
|
|
||||||
/// ````
|
|
||||||
WebViewPage call({
|
|
||||||
InvalidType? controller,
|
|
||||||
Uri? url,
|
|
||||||
InvalidType? sslError,
|
|
||||||
String? title,
|
|
||||||
String? topicId,
|
|
||||||
BrowserIcon? favicon,
|
|
||||||
Uint8List? screenshot,
|
|
||||||
({bool canGoBack, bool canGoForward})? pageHistory,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfWebViewPage.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfWebViewPage.copyWith.fieldName(...)`
|
|
||||||
class _$WebViewPageCWProxyImpl implements _$WebViewPageCWProxy {
|
|
||||||
const _$WebViewPageCWProxyImpl(this._value);
|
|
||||||
|
|
||||||
final WebViewPage _value;
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage controller(InvalidType controller) =>
|
|
||||||
this(controller: controller);
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage url(Uri url) => this(url: url);
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage sslError(InvalidType sslError) => this(sslError: sslError);
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage title(String? title) => this(title: title);
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage topicId(String? topicId) => this(topicId: topicId);
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage favicon(BrowserIcon? favicon) => this(favicon: favicon);
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage screenshot(Uint8List? screenshot) => this(screenshot: screenshot);
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage pageHistory(({bool canGoBack, bool canGoForward}) pageHistory) =>
|
|
||||||
this(pageHistory: pageHistory);
|
|
||||||
|
|
||||||
@override
|
|
||||||
|
|
||||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `WebViewPage(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
|
||||||
///
|
|
||||||
/// Usage
|
|
||||||
/// ```dart
|
|
||||||
/// WebViewPage(...).copyWith(id: 12, name: "My name")
|
|
||||||
/// ````
|
|
||||||
WebViewPage call({
|
|
||||||
Object? controller = const $CopyWithPlaceholder(),
|
|
||||||
Object? url = const $CopyWithPlaceholder(),
|
|
||||||
Object? sslError = const $CopyWithPlaceholder(),
|
|
||||||
Object? title = const $CopyWithPlaceholder(),
|
|
||||||
Object? topicId = const $CopyWithPlaceholder(),
|
|
||||||
Object? favicon = const $CopyWithPlaceholder(),
|
|
||||||
Object? screenshot = const $CopyWithPlaceholder(),
|
|
||||||
Object? pageHistory = const $CopyWithPlaceholder(),
|
|
||||||
}) {
|
|
||||||
return WebViewPage(
|
|
||||||
id: _value.id,
|
|
||||||
controller:
|
|
||||||
controller == const $CopyWithPlaceholder() || controller == null
|
|
||||||
? _value.controller
|
|
||||||
// ignore: cast_nullable_to_non_nullable
|
|
||||||
: controller as InvalidType,
|
|
||||||
url: url == const $CopyWithPlaceholder() || url == null
|
|
||||||
? _value.url
|
|
||||||
// ignore: cast_nullable_to_non_nullable
|
|
||||||
: url as Uri,
|
|
||||||
sslError: sslError == const $CopyWithPlaceholder() || sslError == null
|
|
||||||
? _value.sslError
|
|
||||||
// ignore: cast_nullable_to_non_nullable
|
|
||||||
: sslError as InvalidType,
|
|
||||||
title: title == const $CopyWithPlaceholder()
|
|
||||||
? _value.title
|
|
||||||
// ignore: cast_nullable_to_non_nullable
|
|
||||||
: title as String?,
|
|
||||||
topicId: topicId == const $CopyWithPlaceholder()
|
|
||||||
? _value.topicId
|
|
||||||
// ignore: cast_nullable_to_non_nullable
|
|
||||||
: topicId as String?,
|
|
||||||
favicon: favicon == const $CopyWithPlaceholder()
|
|
||||||
? _value.favicon
|
|
||||||
// ignore: cast_nullable_to_non_nullable
|
|
||||||
: favicon as BrowserIcon?,
|
|
||||||
screenshot: screenshot == const $CopyWithPlaceholder()
|
|
||||||
? _value.screenshot
|
|
||||||
// ignore: cast_nullable_to_non_nullable
|
|
||||||
: screenshot as Uint8List?,
|
|
||||||
pageHistory:
|
|
||||||
pageHistory == const $CopyWithPlaceholder() || pageHistory == null
|
|
||||||
? _value.pageHistory
|
|
||||||
// ignore: cast_nullable_to_non_nullable
|
|
||||||
: pageHistory as ({bool canGoBack, bool canGoForward}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension $WebViewPageCopyWith on WebViewPage {
|
|
||||||
/// Returns a callable class that can be used as follows: `instanceOfWebViewPage.copyWith(...)` or like so:`instanceOfWebViewPage.copyWith.fieldName(...)`.
|
|
||||||
// ignore: library_private_types_in_public_api
|
|
||||||
_$WebViewPageCWProxy get copyWith => _$WebViewPageCWProxyImpl(this);
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/services.dart' show rootBundle;
|
|
||||||
import 'package:lensai/features/content_block/domain/repositories/host.dart';
|
|
||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/repositories/tab_link.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
import 'package:universal_io/io.dart';
|
|
||||||
|
|
||||||
part 'providers.g.dart';
|
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
|
||||||
Stream<Set<String>?> blockContentHosts(BlockContentHostsRef ref) {
|
|
||||||
final hostRepository = ref.watch(hostRepositoryProvider.notifier);
|
|
||||||
final enableContentBlocking = ref.watch(
|
|
||||||
settingsRepositoryProvider.select(
|
|
||||||
(value) =>
|
|
||||||
(value.valueOrNull ?? Settings.withDefaults()).enableContentBlocking,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
final enableHostList = ref.watch(
|
|
||||||
settingsRepositoryProvider.select(
|
|
||||||
(value) => (value.valueOrNull ?? Settings.withDefaults()).enableHostList,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!enableContentBlocking || enableHostList.isEmpty) {
|
|
||||||
return Stream.value(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostRepository
|
|
||||||
.watchHosts(sources: enableHostList)
|
|
||||||
.map((hosts) => hosts.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
|
||||||
Future<String> readerabilityScript(ReaderabilityScriptRef ref) {
|
|
||||||
return rootBundle.load('assets/scripts/readability.min.js.gz').then(
|
|
||||||
(value) => compute(
|
|
||||||
(message) => utf8.decode(gzip.decode(message)),
|
|
||||||
value.buffer.asUint8List(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod()
|
|
||||||
List<String> activeTabs(ActiveTabsRef ref) {
|
|
||||||
final topic = ref.watch(selectedTopicProvider);
|
|
||||||
return ref.watch(
|
|
||||||
topicTabRepositoryProvider(topic)
|
|
||||||
.select((value) => value.valueOrNull ?? []),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'providers.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
String _$blockContentHostsHash() => r'41855093d8376152244ae37f98e66eea7c74aa32';
|
|
||||||
|
|
||||||
/// See also [blockContentHosts].
|
|
||||||
@ProviderFor(blockContentHosts)
|
|
||||||
final blockContentHostsProvider = StreamProvider<Set<String>?>.internal(
|
|
||||||
blockContentHosts,
|
|
||||||
name: r'blockContentHostsProvider',
|
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$blockContentHostsHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef BlockContentHostsRef = StreamProviderRef<Set<String>?>;
|
|
||||||
String _$readerabilityScriptHash() =>
|
|
||||||
r'6fdd1aa920bc58c35ef9888158e572e25793870a';
|
|
||||||
|
|
||||||
/// See also [readerabilityScript].
|
|
||||||
@ProviderFor(readerabilityScript)
|
|
||||||
final readerabilityScriptProvider = FutureProvider<String>.internal(
|
|
||||||
readerabilityScript,
|
|
||||||
name: r'readerabilityScriptProvider',
|
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$readerabilityScriptHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef ReaderabilityScriptRef = FutureProviderRef<String>;
|
|
||||||
String _$activeTabsHash() => r'd1ef2ae32d8707f7cc0902dd031e8302a63f50d4';
|
|
||||||
|
|
||||||
/// See also [activeTabs].
|
|
||||||
@ProviderFor(activeTabs)
|
|
||||||
final activeTabsProvider = AutoDisposeProvider<List<String>>.internal(
|
|
||||||
activeTabs,
|
|
||||||
name: r'activeTabsProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product') ? null : _$activeTabsHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef ActiveTabsRef = AutoDisposeProviderRef<List<String>>;
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
import 'package:copy_with_extension/copy_with_extension.dart';
|
|
||||||
import 'package:drift/drift.dart';
|
|
||||||
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:lensai/core/logger.dart';
|
|
||||||
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/repositories/tab_link.dart';
|
|
||||||
import 'package:lensai/features/web_view/domain/entities/consistent_controller.dart';
|
|
||||||
import 'package:lensai/features/web_view/domain/entities/web_view_page.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
|
|
||||||
part 'web_view.g.dart';
|
|
||||||
|
|
||||||
abstract class _TabStateCopyProxy {
|
|
||||||
Future<void> copyWith({
|
|
||||||
InAppWebViewController? controller,
|
|
||||||
Uri? url,
|
|
||||||
SslError? sslError,
|
|
||||||
String? title,
|
|
||||||
String? topicId,
|
|
||||||
Favicon? favicon,
|
|
||||||
Uint8List? screenshot,
|
|
||||||
({bool canGoBack, bool canGoForward})? pageHistory,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod()
|
|
||||||
class WebViewTabController extends _$WebViewTabController {
|
|
||||||
String? _requestedTab;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? build() {
|
|
||||||
final webViewTabs = ref.watch(
|
|
||||||
tabRepositoryProvider.select(
|
|
||||||
(value) => value.value ?? [],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (_requestedTab != null) {
|
|
||||||
if (webViewTabs.any((tab) => tab.id == _requestedTab)) {
|
|
||||||
return _requestedTab;
|
|
||||||
} else if (webViewTabs.isNotEmpty) {
|
|
||||||
final topic = ref.read(selectedTopicProvider);
|
|
||||||
return webViewTabs.where((tab) => tab.topicId == topic).lastOrNull?.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void showTab(String? id) {
|
|
||||||
_requestedTab = id;
|
|
||||||
ref.invalidateSelf();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod()
|
|
||||||
class TabState extends _$TabState implements _TabStateCopyProxy {
|
|
||||||
KeepAliveLink? _aliveLink;
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage? build(String tabId) {
|
|
||||||
final tabAsync = ref.watch(tabDataProvider(tabId));
|
|
||||||
|
|
||||||
if (tabAsync.hasValue) {
|
|
||||||
final tab = tabAsync.valueOrNull;
|
|
||||||
|
|
||||||
final current = stateOrNull ??
|
|
||||||
WebViewPage.create(
|
|
||||||
id: tabId,
|
|
||||||
url: tab?.url ?? Uri.https('localhost'),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (tab != null) {
|
|
||||||
_aliveLink ??= ref.keepAlive();
|
|
||||||
|
|
||||||
return current.copyWith(
|
|
||||||
topicId: tab.topicId,
|
|
||||||
url: tab.url,
|
|
||||||
title: tab.title,
|
|
||||||
screenshot: tab.screenshot,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
_aliveLink?.close();
|
|
||||||
_aliveLink = null;
|
|
||||||
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> updateScreenshot() async {
|
|
||||||
final screenshot = await state?.controller
|
|
||||||
?.takeScreenshot(
|
|
||||||
screenshotConfiguration: ScreenshotConfiguration(
|
|
||||||
compressFormat: CompressFormat.JPEG,
|
|
||||||
quality: 20,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.timeout(
|
|
||||||
const Duration(milliseconds: 1500),
|
|
||||||
onTimeout: () {
|
|
||||||
logger.w('Screenshot timed out');
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
await copyWith(screenshot: screenshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> copyWith({
|
|
||||||
Object? controller = const $CopyWithPlaceholder(),
|
|
||||||
Object? url = const $CopyWithPlaceholder(),
|
|
||||||
Object? sslError = const $CopyWithPlaceholder(),
|
|
||||||
Object? title = const $CopyWithPlaceholder(),
|
|
||||||
Object? topicId = const $CopyWithPlaceholder(),
|
|
||||||
Object? favicon = const $CopyWithPlaceholder(),
|
|
||||||
Object? screenshot = const $CopyWithPlaceholder(),
|
|
||||||
Object? pageHistory = const $CopyWithPlaceholder(),
|
|
||||||
}) async {
|
|
||||||
if (state != null) {
|
|
||||||
final current = state!;
|
|
||||||
|
|
||||||
state = WebViewPage(
|
|
||||||
id: current.id,
|
|
||||||
controller: controller == const $CopyWithPlaceholder()
|
|
||||||
? current.controller
|
|
||||||
: controller as InAppWebViewController?,
|
|
||||||
url: current.url,
|
|
||||||
sslError: sslError == const $CopyWithPlaceholder()
|
|
||||||
? current.sslError
|
|
||||||
: sslError as SslError?,
|
|
||||||
title: current.title,
|
|
||||||
topicId: current.topicId,
|
|
||||||
favicon: favicon == const $CopyWithPlaceholder()
|
|
||||||
? current.favicon
|
|
||||||
: favicon as Favicon?,
|
|
||||||
screenshot: current.screenshot,
|
|
||||||
pageHistory:
|
|
||||||
pageHistory == const $CopyWithPlaceholder() || pageHistory == null
|
|
||||||
? current.pageHistory
|
|
||||||
: pageHistory as ({bool canGoBack, bool canGoForward}),
|
|
||||||
);
|
|
||||||
|
|
||||||
await ref.read(tabRepositoryProvider.notifier).updateTab(
|
|
||||||
current.id,
|
|
||||||
url: url == const $CopyWithPlaceholder() || url == null
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(url as Uri),
|
|
||||||
title: title == const $CopyWithPlaceholder()
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(title as String?),
|
|
||||||
topicId: topicId == const $CopyWithPlaceholder()
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(topicId as String?),
|
|
||||||
screenshot: screenshot == const $CopyWithPlaceholder()
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(screenshot as Uint8List?),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod()
|
|
||||||
InAppWebViewController? webViewController(
|
|
||||||
WebViewControllerRef ref,
|
|
||||||
String tabId,
|
|
||||||
) {
|
|
||||||
return ref
|
|
||||||
.watch(
|
|
||||||
tabStateProvider(tabId)
|
|
||||||
.select((value) => ConsistentController(value?.controller)),
|
|
||||||
)
|
|
||||||
.value;
|
|
||||||
}
|
|
||||||
@@ -1,318 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'web_view.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
String _$webViewControllerHash() => r'f35fb13d46fcb04cee5676089f0cb8d5ca21e89b';
|
|
||||||
|
|
||||||
/// 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [webViewController].
|
|
||||||
@ProviderFor(webViewController)
|
|
||||||
const webViewControllerProvider = WebViewControllerFamily();
|
|
||||||
|
|
||||||
/// See also [webViewController].
|
|
||||||
class WebViewControllerFamily extends Family<InAppWebViewController?> {
|
|
||||||
/// See also [webViewController].
|
|
||||||
const WebViewControllerFamily();
|
|
||||||
|
|
||||||
/// See also [webViewController].
|
|
||||||
WebViewControllerProvider call(
|
|
||||||
String tabId,
|
|
||||||
) {
|
|
||||||
return WebViewControllerProvider(
|
|
||||||
tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewControllerProvider getProviderOverride(
|
|
||||||
covariant WebViewControllerProvider provider,
|
|
||||||
) {
|
|
||||||
return call(
|
|
||||||
provider.tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'webViewControllerProvider';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [webViewController].
|
|
||||||
class WebViewControllerProvider
|
|
||||||
extends AutoDisposeProvider<InAppWebViewController?> {
|
|
||||||
/// See also [webViewController].
|
|
||||||
WebViewControllerProvider(
|
|
||||||
String tabId,
|
|
||||||
) : this._internal(
|
|
||||||
(ref) => webViewController(
|
|
||||||
ref as WebViewControllerRef,
|
|
||||||
tabId,
|
|
||||||
),
|
|
||||||
from: webViewControllerProvider,
|
|
||||||
name: r'webViewControllerProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$webViewControllerHash,
|
|
||||||
dependencies: WebViewControllerFamily._dependencies,
|
|
||||||
allTransitiveDependencies:
|
|
||||||
WebViewControllerFamily._allTransitiveDependencies,
|
|
||||||
tabId: tabId,
|
|
||||||
);
|
|
||||||
|
|
||||||
WebViewControllerProvider._internal(
|
|
||||||
super._createNotifier, {
|
|
||||||
required super.name,
|
|
||||||
required super.dependencies,
|
|
||||||
required super.allTransitiveDependencies,
|
|
||||||
required super.debugGetCreateSourceHash,
|
|
||||||
required super.from,
|
|
||||||
required this.tabId,
|
|
||||||
}) : super.internal();
|
|
||||||
|
|
||||||
final String tabId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Override overrideWith(
|
|
||||||
InAppWebViewController? Function(WebViewControllerRef provider) create,
|
|
||||||
) {
|
|
||||||
return ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
override: WebViewControllerProvider._internal(
|
|
||||||
(ref) => create(ref as WebViewControllerRef),
|
|
||||||
from: from,
|
|
||||||
name: null,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
debugGetCreateSourceHash: null,
|
|
||||||
tabId: tabId,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
AutoDisposeProviderElement<InAppWebViewController?> createElement() {
|
|
||||||
return _WebViewControllerProviderElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is WebViewControllerProvider && other.tabId == tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, tabId.hashCode);
|
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mixin WebViewControllerRef on AutoDisposeProviderRef<InAppWebViewController?> {
|
|
||||||
/// The parameter `tabId` of this provider.
|
|
||||||
String get tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WebViewControllerProviderElement
|
|
||||||
extends AutoDisposeProviderElement<InAppWebViewController?>
|
|
||||||
with WebViewControllerRef {
|
|
||||||
_WebViewControllerProviderElement(super.provider);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get tabId => (origin as WebViewControllerProvider).tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
String _$webViewTabControllerHash() =>
|
|
||||||
r'cf1b766aa84472040b56a7b4d9ce1fd1606ed5e1';
|
|
||||||
|
|
||||||
/// See also [WebViewTabController].
|
|
||||||
@ProviderFor(WebViewTabController)
|
|
||||||
final webViewTabControllerProvider =
|
|
||||||
AutoDisposeNotifierProvider<WebViewTabController, String?>.internal(
|
|
||||||
WebViewTabController.new,
|
|
||||||
name: r'webViewTabControllerProvider',
|
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$webViewTabControllerHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef _$WebViewTabController = AutoDisposeNotifier<String?>;
|
|
||||||
String _$tabStateHash() => r'9ce6b0d99e5032f534c97482d6140dda4b14fb07';
|
|
||||||
|
|
||||||
abstract class _$TabState extends BuildlessAutoDisposeNotifier<WebViewPage?> {
|
|
||||||
late final String tabId;
|
|
||||||
|
|
||||||
WebViewPage? build(
|
|
||||||
String tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [TabState].
|
|
||||||
@ProviderFor(TabState)
|
|
||||||
const tabStateProvider = TabStateFamily();
|
|
||||||
|
|
||||||
/// See also [TabState].
|
|
||||||
class TabStateFamily extends Family<WebViewPage?> {
|
|
||||||
/// See also [TabState].
|
|
||||||
const TabStateFamily();
|
|
||||||
|
|
||||||
/// See also [TabState].
|
|
||||||
TabStateProvider call(
|
|
||||||
String tabId,
|
|
||||||
) {
|
|
||||||
return TabStateProvider(
|
|
||||||
tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
TabStateProvider getProviderOverride(
|
|
||||||
covariant TabStateProvider provider,
|
|
||||||
) {
|
|
||||||
return call(
|
|
||||||
provider.tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'tabStateProvider';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [TabState].
|
|
||||||
class TabStateProvider
|
|
||||||
extends AutoDisposeNotifierProviderImpl<TabState, WebViewPage?> {
|
|
||||||
/// See also [TabState].
|
|
||||||
TabStateProvider(
|
|
||||||
String tabId,
|
|
||||||
) : this._internal(
|
|
||||||
() => TabState()..tabId = tabId,
|
|
||||||
from: tabStateProvider,
|
|
||||||
name: r'tabStateProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$tabStateHash,
|
|
||||||
dependencies: TabStateFamily._dependencies,
|
|
||||||
allTransitiveDependencies: TabStateFamily._allTransitiveDependencies,
|
|
||||||
tabId: tabId,
|
|
||||||
);
|
|
||||||
|
|
||||||
TabStateProvider._internal(
|
|
||||||
super._createNotifier, {
|
|
||||||
required super.name,
|
|
||||||
required super.dependencies,
|
|
||||||
required super.allTransitiveDependencies,
|
|
||||||
required super.debugGetCreateSourceHash,
|
|
||||||
required super.from,
|
|
||||||
required this.tabId,
|
|
||||||
}) : super.internal();
|
|
||||||
|
|
||||||
final String tabId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
WebViewPage? runNotifierBuild(
|
|
||||||
covariant TabState notifier,
|
|
||||||
) {
|
|
||||||
return notifier.build(
|
|
||||||
tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Override overrideWith(TabState Function() create) {
|
|
||||||
return ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
override: TabStateProvider._internal(
|
|
||||||
() => create()..tabId = tabId,
|
|
||||||
from: from,
|
|
||||||
name: null,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
debugGetCreateSourceHash: null,
|
|
||||||
tabId: tabId,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
AutoDisposeNotifierProviderElement<TabState, WebViewPage?> createElement() {
|
|
||||||
return _TabStateProviderElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is TabStateProvider && other.tabId == tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, tabId.hashCode);
|
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mixin TabStateRef on AutoDisposeNotifierProviderRef<WebViewPage?> {
|
|
||||||
/// The parameter `tabId` of this provider.
|
|
||||||
String get tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TabStateProviderElement
|
|
||||||
extends AutoDisposeNotifierProviderElement<TabState, WebViewPage?>
|
|
||||||
with TabStateRef {
|
|
||||||
_TabStateProviderElement(super.provider);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get tabId => (origin as TabStateProvider).tabId;
|
|
||||||
}
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
|
||||||
import 'package:lensai/features/web_view/domain/repositories/web_view.dart';
|
|
||||||
import 'package:lensai/features/web_view/presentation/services/readerability_script.dart';
|
|
||||||
import 'package:riverpod/riverpod.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
|
|
||||||
part 'readerability.g.dart';
|
|
||||||
|
|
||||||
@Riverpod()
|
|
||||||
class ReaderabilityController extends _$ReaderabilityController {
|
|
||||||
late ReaderabilityScriptService _service;
|
|
||||||
late KeepAliveLink _aliveLink;
|
|
||||||
|
|
||||||
@override
|
|
||||||
AsyncValue<({bool readerable, bool applied})> build(
|
|
||||||
String tabId,
|
|
||||||
) {
|
|
||||||
_service = ref.watch(readerabilityScriptServiceProvider(tabId).notifier);
|
|
||||||
_aliveLink = ref.keepAlive();
|
|
||||||
|
|
||||||
ref.listen(
|
|
||||||
isTabExistingProvider(tabId),
|
|
||||||
(previous, next) {
|
|
||||||
if (next.valueOrNull == false) {
|
|
||||||
_aliveLink.close();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return const AsyncLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> checkReaderable() async {
|
|
||||||
final applied = state.valueOrNull?.applied ?? false;
|
|
||||||
|
|
||||||
state = const AsyncLoading();
|
|
||||||
final result = await AsyncValue.guard(() async {
|
|
||||||
return (readerable: await _service.isReaderable(), applied: applied);
|
|
||||||
});
|
|
||||||
state = result;
|
|
||||||
|
|
||||||
return result.valueOrNull?.readerable ?? false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> toggleReaderable() async {
|
|
||||||
final applied = state.valueOrNull?.applied ?? false;
|
|
||||||
final readerable = state.valueOrNull?.readerable ?? false;
|
|
||||||
|
|
||||||
state = const AsyncLoading();
|
|
||||||
state = await AsyncValue.guard(() async {
|
|
||||||
if (applied) {
|
|
||||||
await ref.read(webViewControllerProvider(tabId))?.reload();
|
|
||||||
} else {
|
|
||||||
await _service.applyReaderable();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (readerable: readerable, applied: !applied);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
state = const AsyncLoading();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'readerability.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
String _$readerabilityControllerHash() =>
|
|
||||||
r'a1c8da3a9cf48300089e390a4fcae89862a6ec1a';
|
|
||||||
|
|
||||||
/// 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 _$ReaderabilityController extends BuildlessAutoDisposeNotifier<
|
|
||||||
AsyncValue<({bool readerable, bool applied})>> {
|
|
||||||
late final String tabId;
|
|
||||||
|
|
||||||
AsyncValue<({bool readerable, bool applied})> build(
|
|
||||||
String tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [ReaderabilityController].
|
|
||||||
@ProviderFor(ReaderabilityController)
|
|
||||||
const readerabilityControllerProvider = ReaderabilityControllerFamily();
|
|
||||||
|
|
||||||
/// See also [ReaderabilityController].
|
|
||||||
class ReaderabilityControllerFamily
|
|
||||||
extends Family<AsyncValue<({bool readerable, bool applied})>> {
|
|
||||||
/// See also [ReaderabilityController].
|
|
||||||
const ReaderabilityControllerFamily();
|
|
||||||
|
|
||||||
/// See also [ReaderabilityController].
|
|
||||||
ReaderabilityControllerProvider call(
|
|
||||||
String tabId,
|
|
||||||
) {
|
|
||||||
return ReaderabilityControllerProvider(
|
|
||||||
tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
ReaderabilityControllerProvider getProviderOverride(
|
|
||||||
covariant ReaderabilityControllerProvider provider,
|
|
||||||
) {
|
|
||||||
return call(
|
|
||||||
provider.tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'readerabilityControllerProvider';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [ReaderabilityController].
|
|
||||||
class ReaderabilityControllerProvider extends AutoDisposeNotifierProviderImpl<
|
|
||||||
ReaderabilityController, AsyncValue<({bool readerable, bool applied})>> {
|
|
||||||
/// See also [ReaderabilityController].
|
|
||||||
ReaderabilityControllerProvider(
|
|
||||||
String tabId,
|
|
||||||
) : this._internal(
|
|
||||||
() => ReaderabilityController()..tabId = tabId,
|
|
||||||
from: readerabilityControllerProvider,
|
|
||||||
name: r'readerabilityControllerProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$readerabilityControllerHash,
|
|
||||||
dependencies: ReaderabilityControllerFamily._dependencies,
|
|
||||||
allTransitiveDependencies:
|
|
||||||
ReaderabilityControllerFamily._allTransitiveDependencies,
|
|
||||||
tabId: tabId,
|
|
||||||
);
|
|
||||||
|
|
||||||
ReaderabilityControllerProvider._internal(
|
|
||||||
super._createNotifier, {
|
|
||||||
required super.name,
|
|
||||||
required super.dependencies,
|
|
||||||
required super.allTransitiveDependencies,
|
|
||||||
required super.debugGetCreateSourceHash,
|
|
||||||
required super.from,
|
|
||||||
required this.tabId,
|
|
||||||
}) : super.internal();
|
|
||||||
|
|
||||||
final String tabId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
AsyncValue<({bool readerable, bool applied})> runNotifierBuild(
|
|
||||||
covariant ReaderabilityController notifier,
|
|
||||||
) {
|
|
||||||
return notifier.build(
|
|
||||||
tabId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Override overrideWith(ReaderabilityController Function() create) {
|
|
||||||
return ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
override: ReaderabilityControllerProvider._internal(
|
|
||||||
() => create()..tabId = tabId,
|
|
||||||
from: from,
|
|
||||||
name: null,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
debugGetCreateSourceHash: null,
|
|
||||||
tabId: tabId,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
AutoDisposeNotifierProviderElement<ReaderabilityController,
|
|
||||||
AsyncValue<({bool readerable, bool applied})>> createElement() {
|
|
||||||
return _ReaderabilityControllerProviderElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is ReaderabilityControllerProvider && other.tabId == tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, tabId.hashCode);
|
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mixin ReaderabilityControllerRef on AutoDisposeNotifierProviderRef<
|
|
||||||
AsyncValue<({bool readerable, bool applied})>> {
|
|
||||||
/// The parameter `tabId` of this provider.
|
|
||||||
String get tabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ReaderabilityControllerProviderElement
|
|
||||||
extends AutoDisposeNotifierProviderElement<ReaderabilityController,
|
|
||||||
AsyncValue<({bool readerable, bool applied})>>
|
|
||||||
with ReaderabilityControllerRef {
|
|
||||||
_ReaderabilityControllerProviderElement(super.provider);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get tabId => (origin as ReaderabilityControllerProvider).tabId;
|
|
||||||
}
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
|
||||||
import 'package:lensai/features/geckoview/features/topics/domain/repositories/tab_link.dart';
|
|
||||||
import 'package:lensai/features/web_view/domain/entities/web_view_page.dart';
|
|
||||||
import 'package:lensai/features/web_view/domain/repositories/web_view.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
|
|
||||||
part 'switch_new_tab.g.dart';
|
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
|
||||||
class SwitchNewTabController extends _$SwitchNewTabController {
|
|
||||||
@override
|
|
||||||
FutureOr<void> build() {}
|
|
||||||
|
|
||||||
Future<void> add(Uri url) async {
|
|
||||||
state = const AsyncLoading();
|
|
||||||
state = await AsyncValue.guard(
|
|
||||||
() async {
|
|
||||||
final topic = ref.read(selectedTopicProvider);
|
|
||||||
final newTab = WebViewPage.create(
|
|
||||||
url: WebUri.uri(url),
|
|
||||||
topicId: topic,
|
|
||||||
);
|
|
||||||
|
|
||||||
await ref
|
|
||||||
.read(topicTabRepositoryProvider(topic).notifier)
|
|
||||||
.addTab(newTab);
|
|
||||||
|
|
||||||
ref.read(webViewTabControllerProvider.notifier).showTab(newTab.id);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
|
||||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
|
||||||
import 'package:lensai/features/web_view/domain/providers.dart';
|
|
||||||
import 'package:lensai/features/web_view/domain/repositories/web_view.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
|
|
||||||
part 'readerability_script.g.dart';
|
|
||||||
|
|
||||||
@Riverpod()
|
|
||||||
class ReaderabilityScriptService extends _$ReaderabilityScriptService {
|
|
||||||
late InAppWebViewController? _controller;
|
|
||||||
late Future<String> _readerabilityScript;
|
|
||||||
late bool _enableReadability;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> build(String tabId) async {
|
|
||||||
_controller = ref.watch(webViewControllerProvider(tabId));
|
|
||||||
_readerabilityScript = ref.watch(readerabilityScriptProvider.future);
|
|
||||||
_enableReadability = ref.watch(
|
|
||||||
settingsRepositoryProvider.select(
|
|
||||||
(value) =>
|
|
||||||
(value.valueOrNull ?? Settings.withDefaults()).enableReadability,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _injectScript() async {
|
|
||||||
if (_controller != null) {
|
|
||||||
await _readerabilityScript
|
|
||||||
.then((script) => _controller!.evaluateJavascript(source: script));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _ensureScriptInjected() async {
|
|
||||||
if (_controller != null) {
|
|
||||||
final injected = await _controller!.evaluateJavascript(
|
|
||||||
source:
|
|
||||||
"(typeof window !== 'undefined' && typeof window.isReaderable === 'function')",
|
|
||||||
) as bool;
|
|
||||||
|
|
||||||
if (!injected) {
|
|
||||||
await _injectScript();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> isReaderable() async {
|
|
||||||
if (_enableReadability) {
|
|
||||||
await _ensureScriptInjected();
|
|
||||||
|
|
||||||
if (_controller != null) {
|
|
||||||
return await _controller!.evaluateJavascript(
|
|
||||||
source: 'isReaderable();',
|
|
||||||
) as bool;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> applyReaderable() async {
|
|
||||||
if (_enableReadability) {
|
|
||||||
await _ensureScriptInjected();
|
|
||||||
|
|
||||||
if (_controller != null) {
|
|
||||||
await _controller!.evaluateJavascript(source: 'applyReaderable();');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -20,10 +20,10 @@ class WebsiteTitleTile extends HookConsumerWidget {
|
|||||||
child: pageInfoAsync.when(
|
child: pageInfoAsync.when(
|
||||||
data: (info) {
|
data: (info) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: FaviconImage(
|
leading: RawImage(
|
||||||
favicon: info.favicon,
|
image: info.favicon?.image.value,
|
||||||
url: info.url,
|
height: 24,
|
||||||
size: 24,
|
width: 24,
|
||||||
),
|
),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
title: Text(info.title ?? 'Unknown Title'),
|
title: Text(info.title ?? 'Unknown Title'),
|
||||||
@@ -38,10 +38,10 @@ class WebsiteTitleTile extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
loading: () => (precachedInfo != null)
|
loading: () => (precachedInfo != null)
|
||||||
? ListTile(
|
? ListTile(
|
||||||
leading: FaviconImage(
|
leading: RawImage(
|
||||||
favicon: precachedInfo!.favicon,
|
image: precachedInfo!.favicon?.image.value,
|
||||||
url: precachedInfo!.url,
|
height: 24,
|
||||||
size: 24,
|
width: 24,
|
||||||
),
|
),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
title: Text(precachedInfo!.title ?? 'Unknown Title'),
|
title: Text(precachedInfo!.title ?? 'Unknown Title'),
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/home/fafre/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/
|
/home/fafre/.pub-cache/hosted/pub.dev/package_info_plus-8.0.3/
|
||||||
@@ -1 +1 @@
|
|||||||
/home/fafre/.pub-cache/hosted/pub.dev/share_plus-10.0.2/
|
/home/fafre/.pub-cache/hosted/pub.dev/share_plus-10.0.3/
|
||||||
+93
-88
@@ -5,10 +5,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "72.0.0"
|
version: "73.0.0"
|
||||||
_macros:
|
_macros:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: dart
|
description: dart
|
||||||
@@ -18,10 +18,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.7.0"
|
version: "6.8.0"
|
||||||
analyzer_plugin:
|
analyzer_plugin:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -106,10 +106,10 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04
|
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.12"
|
version: "2.4.13"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -250,18 +250,18 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: custom_lint
|
name: custom_lint
|
||||||
sha256: "4939d89e580c36215e48a7de8fd92f22c79dcc3eb11fda84f3402b3b45aec663"
|
sha256: "832fcdc676171205201c9cffafd6b5add19393962f6598af8472b48b413026e6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.5"
|
version: "0.6.8"
|
||||||
custom_lint_builder:
|
custom_lint_builder:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: custom_lint_builder
|
name: custom_lint_builder
|
||||||
sha256: d9e5bb63ed52c1d006f5a1828992ba6de124c27a531e8fba0a31afffa81621b3
|
sha256: c3d82779026f91b8e00c9ac18934595cbc9b490094ea682052beeafdb2bd50ac
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.5"
|
version: "0.6.8"
|
||||||
custom_lint_core:
|
custom_lint_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -274,34 +274,34 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
|
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.6"
|
version: "2.3.7"
|
||||||
dependency_validator:
|
dependency_validator:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: dependency_validator
|
name: dependency_validator
|
||||||
sha256: "16906f2137a312d0ffe754aee156436563a63d6ab7faaded83d401b5385d5d35"
|
sha256: "81b5dc4cc34a1c05d2fa24aa8d658cb8f048ca23e63d5aaec420200190f1c4b0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.1.1"
|
||||||
drift:
|
drift:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: drift
|
name: drift
|
||||||
sha256: "15b51e0ee1970455c0c3f7e560f3ac02ecb9c04711a9657586e470b234659dba"
|
sha256: d6ff1ec6a0f3fa097dda6b776cf601f1f3d88b53b287288e09c1306f394fb1b3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.20.0"
|
version: "2.20.3"
|
||||||
drift_dev:
|
drift_dev:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: drift_dev
|
name: drift_dev
|
||||||
sha256: b9ec6159a731288e805a44225ccbebad507dd84d52ab71352c52584f13199d2d
|
sha256: "3ee987578ca2281b5ff91eadd757cd6dd36001458d6e33784f990d67ff38f756"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.20.1"
|
version: "2.20.3"
|
||||||
dynamic_color:
|
dynamic_color:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -370,10 +370,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: file
|
name: file
|
||||||
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "7.0.1"
|
||||||
file_picker:
|
file_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -407,18 +407,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_inappwebview
|
name: flutter_inappwebview
|
||||||
sha256: "3e9a443a18ecef966fb930c3a76ca5ab6a7aafc0c7b5e14a4a850cf107b09959"
|
sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.0"
|
version: "6.1.5"
|
||||||
flutter_inappwebview_android:
|
flutter_inappwebview_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_inappwebview_android
|
name: flutter_inappwebview_android
|
||||||
sha256: d247f6ed417f1f8c364612fa05a2ecba7f775c8d0c044c1d3b9ee33a6515c421
|
sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.13"
|
version: "1.1.3"
|
||||||
flutter_inappwebview_internal_annotations:
|
flutter_inappwebview_internal_annotations:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -431,50 +431,58 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_inappwebview_ios
|
name: flutter_inappwebview_ios
|
||||||
sha256: f363577208b97b10b319cd0c428555cd8493e88b468019a8c5635a0e4312bd0f
|
sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.13"
|
version: "1.1.2"
|
||||||
flutter_inappwebview_macos:
|
flutter_inappwebview_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_inappwebview_macos
|
name: flutter_inappwebview_macos
|
||||||
sha256: b55b9e506c549ce88e26580351d2c71d54f4825901666bd6cfa4be9415bb2636
|
sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.11"
|
version: "1.1.2"
|
||||||
flutter_inappwebview_platform_interface:
|
flutter_inappwebview_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_inappwebview_platform_interface
|
name: flutter_inappwebview_platform_interface
|
||||||
sha256: "545fd4c25a07d2775f7d5af05a979b2cac4fbf79393b0a7f5d33ba39ba4f6187"
|
sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.10"
|
version: "1.3.0+1"
|
||||||
flutter_inappwebview_web:
|
flutter_inappwebview_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_inappwebview_web
|
name: flutter_inappwebview_web
|
||||||
sha256: d8c680abfb6fec71609a700199635d38a744df0febd5544c5a020bd73de8ee07
|
sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
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:
|
||||||
name: flutter_launcher_icons
|
name: flutter_launcher_icons
|
||||||
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
|
sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.13.1"
|
version: "0.14.1"
|
||||||
flutter_markdown:
|
flutter_markdown:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: a23c41ee57573e62fc2190a1f36a0480c4d90bde3a8a8d7126e5d5992fb53fb7
|
sha256: e17575ca576a34b46c58c91f9948891117a1bd97815d2e661813c7f90c647a78
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.3+1"
|
version: "0.7.3+2"
|
||||||
flutter_material_design_icons:
|
flutter_material_design_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -493,19 +501,18 @@ packages:
|
|||||||
flutter_pdf_text:
|
flutter_pdf_text:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_pdf_text
|
path: "/home/fafre/Repos/flutter-pdf-text"
|
||||||
sha256: "97a49ecba6cf711a607642785758bf74fe0aaa3a2223524fa0c142e3966c56a0"
|
relative: false
|
||||||
url: "https://pub.dev"
|
source: path
|
||||||
source: hosted
|
|
||||||
version: "0.6.0"
|
version: "0.6.0"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_plugin_android_lifecycle
|
name: flutter_plugin_android_lifecycle
|
||||||
sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda"
|
sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.22"
|
version: "2.0.23"
|
||||||
flutter_riverpod:
|
flutter_riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -608,10 +615,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: "2ddb88e9ad56ae15ee144ed10e33886777eb5ca2509a914850a5faa7b52ff459"
|
sha256: "6f1b756f6e863259a99135ff3c95026c3cdca17d10ebef2bba2261a25ddc8bbc"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.2.7"
|
version: "14.3.0"
|
||||||
go_router_builder:
|
go_router_builder:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@@ -640,10 +647,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: home_widget
|
name: home_widget
|
||||||
sha256: "2a0fdd6267ff975bd07bedf74686bd5577200f504f5de36527ac1b56bdbe68e3"
|
sha256: b313e3304c0429669fddf1286e1fbf61a64b873f38ba30b3eb890ef0d7560b12
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.7.0"
|
||||||
hooks_riverpod:
|
hooks_riverpod:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -688,10 +695,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http_parser
|
name: http_parser
|
||||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
sha256: "40f592dd352890c3b60fec1b68e786cefb9603e05ff303dbc4dda49b304ecdf4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.1.0"
|
||||||
image:
|
image:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -832,10 +839,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: mime
|
name: mime
|
||||||
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
|
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.6"
|
version: "2.0.0"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -848,10 +855,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: package_info_plus
|
name: package_info_plus
|
||||||
sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918
|
sha256: "894f37107424311bdae3e476552229476777b8752c5a2a2369c0cb9a2d5442ef"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.2"
|
version: "8.0.3"
|
||||||
package_info_plus_platform_interface:
|
package_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -880,10 +887,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7"
|
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.10"
|
version: "2.2.12"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1024,18 +1031,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: share_plus
|
name: share_plus
|
||||||
sha256: "468c43f285207c84bcabf5737f33b914ceb8eb38398b91e5e3ad1698d1b72a52"
|
sha256: fec12c3c39f01e4df1ec6ad92b6e85503c5ca64ffd6e28d18c9ffe53fcc4cb11
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.2"
|
version: "10.0.3"
|
||||||
share_plus_platform_interface:
|
share_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: share_plus_platform_interface
|
name: share_plus_platform_interface
|
||||||
sha256: "6ababf341050edff57da8b6990f11f4e99eaba837865e2e6defe16d039619db5"
|
sha256: c57c0bbfec7142e3a0f55633be504b796af72e60e3c791b44d5a017b985f7a48
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.0.1"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1048,18 +1055,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e"
|
sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.2"
|
version: "2.3.3"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_foundation
|
name: shared_preferences_foundation
|
||||||
sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
|
sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.2"
|
version: "2.5.3"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1096,10 +1103,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf
|
name: shelf
|
||||||
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.1"
|
version: "1.4.2"
|
||||||
shelf_web_socket:
|
shelf_web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1148,10 +1155,9 @@ packages:
|
|||||||
speech_to_text_google_dialog:
|
speech_to_text_google_dialog:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: speech_to_text_google_dialog
|
path: "../../speech_to_text_google_dialog"
|
||||||
sha256: f156aaf3b39416161310fb27a33a4e4da1b4bfeecd643635f28d5cac405a00da
|
relative: true
|
||||||
url: "https://pub.dev"
|
source: path
|
||||||
source: hosted
|
|
||||||
version: "0.0.6"
|
version: "0.0.6"
|
||||||
sprintf:
|
sprintf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
@@ -1181,10 +1187,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqlparser
|
name: sqlparser
|
||||||
sha256: "3be52b4968fc2f098ba735863404756d2fe3ea0729cf006a5b5612618f74ca04"
|
sha256: "852cf80f9e974ac8e1b613758a8aa640215f7701352b66a7f468e95711eb570b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.37.1"
|
version: "0.38.1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1284,27 +1290,26 @@ packages:
|
|||||||
uri_to_file:
|
uri_to_file:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: uri_to_file
|
path: "../../uri-to-file"
|
||||||
sha256: cbbb38f975d22311efacc9a53cdcb806708606666d8092314b81c5cb7983b700
|
relative: true
|
||||||
url: "https://pub.dev"
|
source: path
|
||||||
source: hosted
|
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
|
sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.0"
|
version: "6.3.1"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab
|
sha256: "8fc3bae0b68c02c47c5c86fa8bfa74471d42687b0eded01b78de87872db745e2"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.10"
|
version: "6.3.12"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1325,10 +1330,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_macos
|
name: url_launcher_macos
|
||||||
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
|
sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.0"
|
version: "3.2.1"
|
||||||
url_launcher_platform_interface:
|
url_launcher_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1357,10 +1362,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
|
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.2"
|
version: "4.5.1"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1389,10 +1394,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
|
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.0"
|
||||||
web_socket:
|
web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1413,18 +1418,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
|
sha256: "4d45dc9069dba4619dc0ebd93c7cec5e66d8482cb625a370ac806dcc8165f2ec"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.5.4"
|
version: "5.5.5"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.1.0"
|
||||||
xml:
|
xml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user