everything build but untested & migration not finished
This commit is contained in:
@@ -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,27 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'switch_new_tab.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$switchNewTabControllerHash() =>
|
||||
r'7ebfea953aeb81c279ea11254ff0ad558e6a949f';
|
||||
|
||||
/// See also [SwitchNewTabController].
|
||||
@ProviderFor(SwitchNewTabController)
|
||||
final switchNewTabControllerProvider =
|
||||
AsyncNotifierProvider<SwitchNewTabController, void>.internal(
|
||||
SwitchNewTabController.new,
|
||||
name: r'switchNewTabControllerProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$switchNewTabControllerHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$SwitchNewTabController = AsyncNotifier<void>;
|
||||
// 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,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();');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'readerability_script.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$readerabilityScriptServiceHash() =>
|
||||
r'85f0de50516cadb1f2d1efa8161a8cf45868b9d9';
|
||||
|
||||
/// 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 _$ReaderabilityScriptService
|
||||
extends BuildlessAutoDisposeAsyncNotifier<void> {
|
||||
late final String tabId;
|
||||
|
||||
FutureOr<void> build(
|
||||
String tabId,
|
||||
);
|
||||
}
|
||||
|
||||
/// See also [ReaderabilityScriptService].
|
||||
@ProviderFor(ReaderabilityScriptService)
|
||||
const readerabilityScriptServiceProvider = ReaderabilityScriptServiceFamily();
|
||||
|
||||
/// See also [ReaderabilityScriptService].
|
||||
class ReaderabilityScriptServiceFamily extends Family<AsyncValue<void>> {
|
||||
/// See also [ReaderabilityScriptService].
|
||||
const ReaderabilityScriptServiceFamily();
|
||||
|
||||
/// See also [ReaderabilityScriptService].
|
||||
ReaderabilityScriptServiceProvider call(
|
||||
String tabId,
|
||||
) {
|
||||
return ReaderabilityScriptServiceProvider(
|
||||
tabId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ReaderabilityScriptServiceProvider getProviderOverride(
|
||||
covariant ReaderabilityScriptServiceProvider 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'readerabilityScriptServiceProvider';
|
||||
}
|
||||
|
||||
/// See also [ReaderabilityScriptService].
|
||||
class ReaderabilityScriptServiceProvider
|
||||
extends AutoDisposeAsyncNotifierProviderImpl<ReaderabilityScriptService,
|
||||
void> {
|
||||
/// See also [ReaderabilityScriptService].
|
||||
ReaderabilityScriptServiceProvider(
|
||||
String tabId,
|
||||
) : this._internal(
|
||||
() => ReaderabilityScriptService()..tabId = tabId,
|
||||
from: readerabilityScriptServiceProvider,
|
||||
name: r'readerabilityScriptServiceProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$readerabilityScriptServiceHash,
|
||||
dependencies: ReaderabilityScriptServiceFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ReaderabilityScriptServiceFamily._allTransitiveDependencies,
|
||||
tabId: tabId,
|
||||
);
|
||||
|
||||
ReaderabilityScriptServiceProvider._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
|
||||
FutureOr<void> runNotifierBuild(
|
||||
covariant ReaderabilityScriptService notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
tabId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(ReaderabilityScriptService Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: ReaderabilityScriptServiceProvider._internal(
|
||||
() => create()..tabId = tabId,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
tabId: tabId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<ReaderabilityScriptService, void>
|
||||
createElement() {
|
||||
return _ReaderabilityScriptServiceProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ReaderabilityScriptServiceProvider && 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 ReaderabilityScriptServiceRef
|
||||
on AutoDisposeAsyncNotifierProviderRef<void> {
|
||||
/// The parameter `tabId` of this provider.
|
||||
String get tabId;
|
||||
}
|
||||
|
||||
class _ReaderabilityScriptServiceProviderElement
|
||||
extends AutoDisposeAsyncNotifierProviderElement<ReaderabilityScriptService,
|
||||
void> with ReaderabilityScriptServiceRef {
|
||||
_ReaderabilityScriptServiceProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get tabId => (origin as ReaderabilityScriptServiceProvider).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,215 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.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/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/kagi/data/entities/modes.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/repositories/settings_repository.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/website_title_tile.dart';
|
||||
import 'package:lensai/utils/ui_helper.dart' as ui_helper;
|
||||
import 'package:lensai/utils/uri_parser.dart' as uri_parser;
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class WebPageDialog extends HookConsumerWidget {
|
||||
final Uri url;
|
||||
final WebPageInfo? precachedInfo;
|
||||
|
||||
final void Function()? onDismiss;
|
||||
|
||||
const WebPageDialog({
|
||||
required this.url,
|
||||
this.precachedInfo,
|
||||
this.onDismiss,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final incognitoEnabled = ref.watch(
|
||||
settingsRepositoryProvider.select(
|
||||
(value) => (value.valueOrNull ?? Settings.withDefaults()).incognitoMode,
|
||||
),
|
||||
);
|
||||
|
||||
final availableBangsAsync = ref.watch(
|
||||
bangDataListProvider(
|
||||
filter: (
|
||||
domain: url.host,
|
||||
groups: null,
|
||||
categoryFilter: null,
|
||||
orderMostFrequentFirst: true,
|
||||
),
|
||||
),
|
||||
);
|
||||
final availableBangCount = availableBangsAsync.valueOrNull?.length;
|
||||
|
||||
final formKey = useMemoized(() => GlobalKey<FormState>());
|
||||
final urlTextController = useTextEditingController(text: url.toString());
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
ModalBarrier(
|
||||
color: Theme.of(context).dialogTheme.barrierColor ?? Colors.black54,
|
||||
onDismiss: onDismiss,
|
||||
),
|
||||
SimpleDialog(
|
||||
titlePadding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 0.0),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
insetPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 20.0,
|
||||
vertical: 24.0,
|
||||
),
|
||||
title: WebsiteTitleTile(url, precachedInfo: precachedInfo),
|
||||
children: [
|
||||
SizedBox(
|
||||
//We need this to stretch the dialog, then padding from dialog is applied
|
||||
width: double.maxFinite,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: TextFormField(
|
||||
controller: urlTextController,
|
||||
enableIMEPersonalizedLearning: !incognitoEnabled,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'URL',
|
||||
suffixIcon: (webViewController != null)
|
||||
? IconButton(
|
||||
onPressed: () async {
|
||||
if (formKey.currentState?.validate() ?? false) {
|
||||
await webViewController!.loadUrl(
|
||||
urlRequest: URLRequest(
|
||||
url: WebUri.uri(
|
||||
uri_parser.tryParseUrl(
|
||||
urlTextController.text,
|
||||
eagerParsing: true,
|
||||
)!,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
onDismiss?.call();
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.send),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
validator: (value) {
|
||||
if (uri_parser.tryParseUrl(value, eagerParsing: true) !=
|
||||
null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return 'Invalid URL';
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: availableBangsAsync.when(
|
||||
data: (availableBangs) {
|
||||
if (availableBangs.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SiteSearch(
|
||||
domain: url.host,
|
||||
availableBangs: availableBangs,
|
||||
);
|
||||
},
|
||||
error: (error, stackTrace) => FailureWidget(
|
||||
title: 'Could not load bangs',
|
||||
exception: error,
|
||||
),
|
||||
loading: () => SiteSearch(
|
||||
domain: url.host,
|
||||
availableBangs: [
|
||||
BangData(
|
||||
websiteName: 'websiteName',
|
||||
domain: 'domain',
|
||||
trigger: 'trigger',
|
||||
urlTemplate: 'urlTemplate',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (availableBangsAsync.isLoading ||
|
||||
availableBangCount == null ||
|
||||
availableBangCount > 0)
|
||||
const Divider(),
|
||||
ListTile(
|
||||
leading: const Icon(MdiIcons.contentCopy),
|
||||
title: const Text('Copy address'),
|
||||
onTap: () async {
|
||||
await Clipboard.setData(
|
||||
ClipboardData(text: url.toString()),
|
||||
);
|
||||
onDismiss?.call();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
await ui_helper.launchUrlFeedback(context, url);
|
||||
},
|
||||
leading: const Icon(Icons.open_in_browser),
|
||||
title: const Text('Launch External'),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(MdiIcons.tabPlus),
|
||||
title: const Text('Open in new tab'),
|
||||
onTap: () async {
|
||||
await ref
|
||||
.read(switchNewTabControllerProvider.notifier)
|
||||
.add(url);
|
||||
|
||||
onDismiss?.call();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.share),
|
||||
title: const Text('Share link'),
|
||||
onTap: () async {
|
||||
await Share.shareUri(url);
|
||||
|
||||
onDismiss?.call();
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
leading: Icon(KagiTool.summarizer.icon),
|
||||
title: const Text('Summarize'),
|
||||
onTap: () async {
|
||||
final summarizerUrl = uri_builder.summarizerUri(
|
||||
document: SharedUrl(url),
|
||||
mode: SummarizerMode.keyMoments,
|
||||
);
|
||||
|
||||
await ref
|
||||
.read(switchNewTabControllerProvider.notifier)
|
||||
.add(summarizerUrl);
|
||||
|
||||
onDismiss?.call();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,107 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lensai/features/web_view/domain/entities/abstract/tab.dart';
|
||||
import 'package:lensai/features/search_browser/presentation/widgets/favicon.dart';
|
||||
|
||||
class WebViewTab extends StatelessWidget {
|
||||
final ITab tab;
|
||||
final bool isActive;
|
||||
|
||||
final VoidCallback? onTap;
|
||||
final VoidCallback? onLongPress;
|
||||
final VoidCallback? onDelete;
|
||||
|
||||
const WebViewTab({
|
||||
required this.tab,
|
||||
required this.isActive,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.onDelete,
|
||||
super.key,
|
||||
});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: isActive ? colorScheme.primary : colorScheme.outline,
|
||||
width: isActive ? 2.0 : 1.0,
|
||||
),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
|
||||
),
|
||||
child: Material(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
|
||||
child: InkWell(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 6.0),
|
||||
child: Text(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
tab.title ?? 'New Tab',
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
visualDensity:
|
||||
const VisualDensity(horizontal: -4.0, vertical: -4.0),
|
||||
onPressed: onDelete,
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
width: 6.0,
|
||||
),
|
||||
FaviconImage(
|
||||
url: tab.url,
|
||||
favicon: tab.favicon,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 6.0,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
tab.url.authority,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
if (tab.screenshot != null)
|
||||
Expanded(
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(16.0),
|
||||
bottomRight: Radius.circular(16.0),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: Image.memory(
|
||||
fit: BoxFit.fitWidth,
|
||||
tab.screenshot!,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user