getting there
This commit is contained in:
@@ -2,8 +2,11 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:lensai/data/models/equatable_iterable.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/domain/repositories/data.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
@@ -80,3 +83,29 @@ class ShowFindInPage extends _$ShowFindInPage {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
Stream<List<String>> availableTabIds(AvailableTabIdsRef ref, String? topicId) {
|
||||
final db = ref.watch(tabDatabaseProvider);
|
||||
final openTabs = ref
|
||||
.watch(
|
||||
tabStatesProvider.select(
|
||||
(states) =>
|
||||
EquatableCollection(states.keys.toSet(), immutable: false),
|
||||
),
|
||||
)
|
||||
.collection;
|
||||
|
||||
if (topicId != null) {
|
||||
return db.tabLinkDao.topicTabIds(topicId).watch().map(
|
||||
(tabIds) =>
|
||||
tabIds.where((tabId) => openTabs.contains(tabId)).toList(),
|
||||
);
|
||||
} else {
|
||||
return db.tabLinkDao.allTabIds().watch().map(
|
||||
(assignedTabIds) => openTabs
|
||||
.where((tabId) => !assignedTabIds.contains(tabId))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +156,135 @@ class _SelectedBangDataProviderElement
|
||||
String? get domain => (origin as SelectedBangDataProvider).domain;
|
||||
}
|
||||
|
||||
String _$availableTabIdsHash() => r'bea231cdf6211fc876b8031b5d72999eae5d7b15';
|
||||
|
||||
/// See also [availableTabIds].
|
||||
@ProviderFor(availableTabIds)
|
||||
const availableTabIdsProvider = AvailableTabIdsFamily();
|
||||
|
||||
/// See also [availableTabIds].
|
||||
class AvailableTabIdsFamily extends Family<AsyncValue<List<String>>> {
|
||||
/// See also [availableTabIds].
|
||||
const AvailableTabIdsFamily();
|
||||
|
||||
/// See also [availableTabIds].
|
||||
AvailableTabIdsProvider call(
|
||||
String? topicId,
|
||||
) {
|
||||
return AvailableTabIdsProvider(
|
||||
topicId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AvailableTabIdsProvider getProviderOverride(
|
||||
covariant AvailableTabIdsProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.topicId,
|
||||
);
|
||||
}
|
||||
|
||||
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'availableTabIdsProvider';
|
||||
}
|
||||
|
||||
/// See also [availableTabIds].
|
||||
class AvailableTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
||||
/// See also [availableTabIds].
|
||||
AvailableTabIdsProvider(
|
||||
String? topicId,
|
||||
) : this._internal(
|
||||
(ref) => availableTabIds(
|
||||
ref as AvailableTabIdsRef,
|
||||
topicId,
|
||||
),
|
||||
from: availableTabIdsProvider,
|
||||
name: r'availableTabIdsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$availableTabIdsHash,
|
||||
dependencies: AvailableTabIdsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
AvailableTabIdsFamily._allTransitiveDependencies,
|
||||
topicId: topicId,
|
||||
);
|
||||
|
||||
AvailableTabIdsProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.topicId,
|
||||
}) : super.internal();
|
||||
|
||||
final String? topicId;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
Stream<List<String>> Function(AvailableTabIdsRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: AvailableTabIdsProvider._internal(
|
||||
(ref) => create(ref as AvailableTabIdsRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
topicId: topicId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeStreamProviderElement<List<String>> createElement() {
|
||||
return _AvailableTabIdsProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is AvailableTabIdsProvider && other.topicId == topicId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, topicId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
mixin AvailableTabIdsRef on AutoDisposeStreamProviderRef<List<String>> {
|
||||
/// The parameter `topicId` of this provider.
|
||||
String? get topicId;
|
||||
}
|
||||
|
||||
class _AvailableTabIdsProviderElement
|
||||
extends AutoDisposeStreamProviderElement<List<String>>
|
||||
with AvailableTabIdsRef {
|
||||
_AvailableTabIdsProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String? get topicId => (origin as AvailableTabIdsProvider).topicId;
|
||||
}
|
||||
|
||||
String _$selectedBangTriggerHash() =>
|
||||
r'b0e12bc95e93d50d04f1c658230cea9f15ff0385';
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/data/models/equatable_iterable.dart';
|
||||
import 'package:lensai/features/geckoview/domain/entities/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
||||
@@ -25,8 +26,14 @@ class TabActionDialog extends HookConsumerWidget {
|
||||
tabTopicIdProvider(initialTab.id).select((value) => value.valueOrNull),
|
||||
);
|
||||
|
||||
final topics =
|
||||
ref.watch(topicsWithCountProvider.select((value) => value.valueOrNull));
|
||||
final topics = ref
|
||||
.watch(
|
||||
topicsWithCountProvider.select(
|
||||
(value) => EquatableCollection(value.valueOrNull, immutable: true),
|
||||
),
|
||||
)
|
||||
.collection;
|
||||
|
||||
final selectedTopic =
|
||||
topics?.firstWhereOrNull((topic) => topic.id == tabTopicId);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
@@ -7,6 +9,7 @@ import 'package:lensai/data/models/web_page_info.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/domain/providers.dart';
|
||||
import 'package:lensai/features/bangs/presentation/widgets/site_search.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers.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';
|
||||
@@ -55,6 +58,7 @@ class WebPageDialog extends HookConsumerWidget {
|
||||
|
||||
final formKey = useMemoized(() => GlobalKey<FormState>());
|
||||
final urlTextController = useTextEditingController(text: url.toString());
|
||||
final urlTextFocusNode = useFocusNode();
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
@@ -80,6 +84,7 @@ class WebPageDialog extends HookConsumerWidget {
|
||||
key: formKey,
|
||||
child: TextFormField(
|
||||
controller: urlTextController,
|
||||
focusNode: urlTextFocusNode,
|
||||
enableIMEPersonalizedLearning: !incognitoEnabled,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'URL',
|
||||
@@ -109,6 +114,15 @@ class WebPageDialog extends HookConsumerWidget {
|
||||
|
||||
return 'Invalid URL';
|
||||
},
|
||||
onTap: () {
|
||||
if (!urlTextFocusNode.hasFocus) {
|
||||
// Select all text when the field is tapped
|
||||
urlTextController.selection = TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: urlTextController.text.length,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -183,6 +197,40 @@ class WebPageDialog extends HookConsumerWidget {
|
||||
onDismiss?.call();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.mobile_screen_share),
|
||||
title: const Text('Share screenshot'),
|
||||
onTap: () async {
|
||||
final screenshot = await ref
|
||||
.read(selectedTabSessionNotifierProvider)
|
||||
.requestScreenshot();
|
||||
|
||||
if (screenshot != null) {
|
||||
ui.decodeImageFromList(
|
||||
screenshot,
|
||||
(result) async {
|
||||
final png = await result.toByteData(
|
||||
format: ui.ImageByteFormat.png,
|
||||
);
|
||||
|
||||
if (png != null) {
|
||||
final file = XFile.fromData(
|
||||
png.buffer.asUint8List(),
|
||||
mimeType: 'image/png',
|
||||
);
|
||||
|
||||
await Share.shareXFiles(
|
||||
[file],
|
||||
subject: precachedInfo?.title,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onDismiss?.call();
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
leading: Icon(KagiTool.summarizer.icon),
|
||||
|
||||
+11
-4
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/data/models/equatable_iterable.dart';
|
||||
import 'package:lensai/domain/services/app_initialization.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/error_container.dart';
|
||||
@@ -51,10 +52,16 @@ class LandingContent extends HookConsumerWidget {
|
||||
const LandingAction(),
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final errors = ref.watch(
|
||||
appInitializationServiceProvider
|
||||
.select((result) => result.valueOrNull?.errors),
|
||||
);
|
||||
final errors = ref
|
||||
.watch(
|
||||
appInitializationServiceProvider.select(
|
||||
(result) => EquatableCollection(
|
||||
result.valueOrNull?.errors,
|
||||
immutable: false,
|
||||
),
|
||||
),
|
||||
)
|
||||
.collection;
|
||||
|
||||
if (errors == null || errors.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
|
||||
+121
-123
@@ -1,16 +1,16 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fading_scroll/fading_scroll.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/data/models/equatable_iterable.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/domain/providers.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/selected_topic.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';
|
||||
@@ -116,135 +116,133 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return FadingScroll(
|
||||
fadingSize: 25,
|
||||
shaderPadding:
|
||||
const EdgeInsets.only(top: _SliverHeaderDelagate._headerSize),
|
||||
return CustomScrollView(
|
||||
controller: sheetScrollController,
|
||||
builder: (context, controller) {
|
||||
return CustomScrollView(
|
||||
controller: controller,
|
||||
slivers: [
|
||||
SliverPersistentHeader(
|
||||
pinned: true,
|
||||
delegate: _SliverHeaderDelagate(onClose: onClose),
|
||||
),
|
||||
HookConsumer(
|
||||
builder: (context, ref, child) {
|
||||
final topic = ref.watch(selectedTopicProvider);
|
||||
final availableTabs = ref.watch(
|
||||
topicTabIdsProvider(topic)
|
||||
.select((value) => value.valueOrNull ?? []),
|
||||
);
|
||||
final activeTab = ref.watch(selectedTabProvider);
|
||||
|
||||
final itemHeight = useMemoized(
|
||||
() => _calculateItemHeight(
|
||||
screenWidth: MediaQuery.of(context).size.width,
|
||||
childAspectRatio: 0.75,
|
||||
horizontalPadding: 4.0,
|
||||
mainAxisSpacing: 8.0,
|
||||
crossAxisSpacing: 8.0,
|
||||
crossAxisCount: 2,
|
||||
slivers: [
|
||||
SliverPersistentHeader(
|
||||
pinned: true,
|
||||
delegate: _SliverHeaderDelagate(onClose: onClose),
|
||||
),
|
||||
HookConsumer(
|
||||
builder: (context, ref, child) {
|
||||
final topic = ref.watch(selectedTopicProvider);
|
||||
final availableTabs = ref
|
||||
.watch(
|
||||
availableTabIdsProvider(topic).select(
|
||||
(value) => EquatableCollection(
|
||||
value.valueOrNull ?? [],
|
||||
immutable: true,
|
||||
),
|
||||
),
|
||||
[MediaQuery.of(context).size.width],
|
||||
);
|
||||
)
|
||||
.collection;
|
||||
final activeTab = ref.watch(selectedTabProvider);
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
final index = availableTabs
|
||||
.indexWhere((webView) => webView == activeTab);
|
||||
final itemHeight = useMemoized(
|
||||
() => _calculateItemHeight(
|
||||
screenWidth: MediaQuery.of(context).size.width,
|
||||
childAspectRatio: 0.75,
|
||||
horizontalPadding: 4.0,
|
||||
mainAxisSpacing: 8.0,
|
||||
crossAxisSpacing: 8.0,
|
||||
crossAxisCount: 2,
|
||||
),
|
||||
[MediaQuery.of(context).size.width],
|
||||
);
|
||||
|
||||
if (index > -1) {
|
||||
final reversedIndex = availableTabs.length - 1 - index;
|
||||
final offset = (reversedIndex ~/ 2) * itemHeight;
|
||||
useEffect(
|
||||
() {
|
||||
final index =
|
||||
availableTabs.indexWhere((webView) => webView == activeTab);
|
||||
|
||||
if (offset != controller.offset) {
|
||||
unawaited(
|
||||
controller.animateTo(
|
||||
offset,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (index > -1) {
|
||||
final reversedIndex = availableTabs.length - 1 - index;
|
||||
final offset = (reversedIndex ~/ 2) * itemHeight;
|
||||
|
||||
return null;
|
||||
},
|
||||
[],
|
||||
);
|
||||
if (offset != sheetScrollController.offset) {
|
||||
unawaited(
|
||||
sheetScrollController.animateTo(
|
||||
offset,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
sliver: SliverGrid.count(
|
||||
//Sync values for itemHeight calculation _calculateItemHeight
|
||||
childAspectRatio: 0.75,
|
||||
mainAxisSpacing: 8.0,
|
||||
crossAxisSpacing: 8.0,
|
||||
crossAxisCount: 2,
|
||||
children: availableTabs.reversed
|
||||
.map(
|
||||
(tabId) => Consumer(
|
||||
key: ValueKey(tabId),
|
||||
builder: (context, ref, child) {
|
||||
final tab = ref.watch(tabStateProvider(tabId));
|
||||
|
||||
return (tab != null)
|
||||
? TabPreview(
|
||||
tab: tab,
|
||||
isActive: tabId == activeTab,
|
||||
onTap: () async {
|
||||
if (tabId != activeTab) {
|
||||
//Close first to avoid rebuilds
|
||||
onClose();
|
||||
await ref
|
||||
.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
)
|
||||
.selectTab(tab.id);
|
||||
} else {
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
ref
|
||||
.read(
|
||||
overlayDialogControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.show(
|
||||
TabActionDialog(
|
||||
initialTab: tab,
|
||||
onDismiss: ref
|
||||
.read(
|
||||
overlayDialogControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.dismiss,
|
||||
),
|
||||
);
|
||||
},
|
||||
onDelete: () async {
|
||||
await ref
|
||||
.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
)
|
||||
.closeTab(tab.id);
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
return null;
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
[availableTabs, activeTab],
|
||||
);
|
||||
|
||||
return SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
sliver: SliverGrid.count(
|
||||
//Sync values for itemHeight calculation _calculateItemHeight
|
||||
childAspectRatio: 0.75,
|
||||
mainAxisSpacing: 8.0,
|
||||
crossAxisSpacing: 8.0,
|
||||
crossAxisCount: 2,
|
||||
children: availableTabs.reversed
|
||||
.map(
|
||||
(tabId) => Consumer(
|
||||
key: ValueKey(tabId),
|
||||
builder: (context, ref, child) {
|
||||
final tab = ref.watch(tabStateProvider(tabId));
|
||||
|
||||
return (tab != null)
|
||||
? TabPreview(
|
||||
tab: tab,
|
||||
isActive: tabId == activeTab,
|
||||
onTap: () async {
|
||||
if (tabId != activeTab) {
|
||||
//Close first to avoid rebuilds
|
||||
onClose();
|
||||
await ref
|
||||
.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
)
|
||||
.selectTab(tab.id);
|
||||
} else {
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
ref
|
||||
.read(
|
||||
overlayDialogControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.show(
|
||||
TabActionDialog(
|
||||
initialTab: tab,
|
||||
onDismiss: ref
|
||||
.read(
|
||||
overlayDialogControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.dismiss,
|
||||
),
|
||||
);
|
||||
},
|
||||
onDelete: () async {
|
||||
await ref
|
||||
.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
)
|
||||
.closeTab(tab.id);
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ 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:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/core/logger.dart';
|
||||
import 'package:lensai/core/routing/routes.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers.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';
|
||||
@@ -22,6 +24,7 @@ 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_appearance_button.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/services/session.dart';
|
||||
@@ -546,7 +549,23 @@ class BrowserScreen extends HookConsumerWidget {
|
||||
SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
const GeckoView(),
|
||||
GeckoView(
|
||||
preInitializationStep: () async {
|
||||
await ref
|
||||
.read(eventServiceProvider)
|
||||
.fragmentReadyStateEvents
|
||||
.firstWhere((state) => state == true)
|
||||
.timeout(
|
||||
const Duration(seconds: 3),
|
||||
onTimeout: () {
|
||||
logger.e(
|
||||
'Browser fragement not reported ready, trying to intitialize anyways',
|
||||
);
|
||||
return true;
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
@@ -604,6 +623,7 @@ class BrowserScreen extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: ReaderAppearanceButton(),
|
||||
bottomSheet: (displayedSheet != null)
|
||||
? NotificationListener<DraggableScrollableNotification>(
|
||||
onNotification: (notification) {
|
||||
|
||||
Reference in New Issue
Block a user