diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 1a66e95..0805028 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -6,7 +6,7 @@ /// Locales: 2 /// Strings: 54 (27 per locale) /// -/// Built on 2024-02-22 at 17:30 UTC +/// Built on 2024-02-22 at 17:42 UTC // coverage:ignore-file // ignore_for_file: type=lint diff --git a/lib/router/paths.dart b/lib/router/paths.dart index c6dff73..d1b1598 100644 --- a/lib/router/paths.dart +++ b/lib/router/paths.dart @@ -1,6 +1,7 @@ class RoutesPaths { static const onboarding = "/onboarding"; static const links = "/links"; + static const webview = "/webview"; static const search = "/search"; static const settings = "/settings"; } diff --git a/lib/router/routes.dart b/lib/router/routes.dart index 167c5ba..d8b45a0 100644 --- a/lib/router/routes.dart +++ b/lib/router/routes.dart @@ -5,8 +5,10 @@ import 'package:my_linkding/screens/links/ui/links.dart'; import 'package:my_linkding/screens/onboarding/ui/onboarding.dart'; import 'package:my_linkding/screens/search/ui/search.dart'; import 'package:my_linkding/screens/settings/ui/settings.dart'; +import 'package:my_linkding/screens/webview/ui/webview.dart'; import 'package:my_linkding/widgets/layout.dart'; +import 'package:my_linkding/models/data/bookmarks.dart'; import 'package:my_linkding/router/paths.dart'; final rootNavigatorKey = GlobalKey(); @@ -32,6 +34,10 @@ final List appRoutes = [ path: RoutesPaths.links, builder: (context, state) => const Links(), ), + GoRoute( + path: RoutesPaths.webview, + builder: (context, state) => WebView(bookmark: state.extra as Bookmark), + ), ], ), StatefulShellBranch( diff --git a/lib/screens/links/ui/links.dart b/lib/screens/links/ui/links.dart index b7ed9db..e072e3f 100644 --- a/lib/screens/links/ui/links.dart +++ b/lib/screens/links/ui/links.dart @@ -3,6 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:my_linkding/screens/links/provider/links.provider.dart'; +import 'package:my_linkding/providers/router_provider.dart'; +import 'package:my_linkding/router/paths.dart'; import 'package:my_linkding/i18n/strings.g.dart'; class Links extends ConsumerWidget { @@ -90,6 +92,7 @@ class Links extends ConsumerWidget { return Column( children: [ ListTile( + onTap: () => ref.watch(routerProvider).push(RoutesPaths.webview, extra: link), isThreeLine: true, title: Text( validateStrings(link?.title, link?.websiteTitle), diff --git a/lib/screens/webview/model/webview.model.dart b/lib/screens/webview/model/webview.model.dart new file mode 100644 index 0000000..b81c2e8 --- /dev/null +++ b/lib/screens/webview/model/webview.model.dart @@ -0,0 +1,9 @@ +import 'package:webview_flutter/webview_flutter.dart'; + +class WebViewModel { + final WebViewController webViewController; + + WebViewModel({ + required this.webViewController, + }); +} diff --git a/lib/screens/webview/provider/webview.provider.dart b/lib/screens/webview/provider/webview.provider.dart new file mode 100644 index 0000000..7613955 --- /dev/null +++ b/lib/screens/webview/provider/webview.provider.dart @@ -0,0 +1,33 @@ +import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'package:my_linkding/screens/webview/model/webview.model.dart'; + +part 'webview.provider.g.dart'; + +@riverpod +class WebView extends _$WebView { + @override + WebViewModel build() { + return WebViewModel( + webViewController: WebViewController( + onPermissionRequest: (request) => request.deny(), + ) + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setNavigationDelegate( + NavigationDelegate( + onProgress: (int progress) { + // Update loading bar. + }, + onPageStarted: (String url) {}, + onPageFinished: (String url) {}, + onWebResourceError: (WebResourceError error) {}, + ), + ), + ); + } + + void initialize(String url) { + state.webViewController.loadRequest(Uri.parse(url)); + } +} diff --git a/lib/screens/webview/provider/webview.provider.g.dart b/lib/screens/webview/provider/webview.provider.g.dart new file mode 100644 index 0000000..8e9dc92 --- /dev/null +++ b/lib/screens/webview/provider/webview.provider.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'webview.provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$webViewHash() => r'9eb114ec97e04b92aa1e2ec9fc8948b1443c948c'; + +/// See also [WebView]. +@ProviderFor(WebView) +final webViewProvider = + AutoDisposeNotifierProvider.internal( + WebView.new, + name: r'webViewProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$webViewHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$WebView = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/screens/webview/ui/webview.dart b/lib/screens/webview/ui/webview.dart new file mode 100644 index 0000000..344647d --- /dev/null +++ b/lib/screens/webview/ui/webview.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:my_linkding/models/data/bookmarks.dart'; +import 'package:my_linkding/screens/webview/provider/webview.provider.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class WebView extends ConsumerWidget { + final Bookmark bookmark; + + const WebView({ + Key? key, + required this.bookmark, + }) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ref.read(webViewProvider.notifier).initialize(bookmark.url!); + }); + + final webViewController = ref.watch(webViewProvider).webViewController; + + return Scaffold( + appBar: AppBar( + title: Text(bookmark.title != "" ? bookmark.title! : bookmark.websiteTitle!), + ), + body: webViewController != null ? WebViewWidget(controller: ref.watch(webViewProvider).webViewController!) : null, + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 088bcce..4314346 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1082,6 +1082,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932" + url: "https://pub.dev" + source: hosted + version: "4.7.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: "3e5f4e9d818086b0d01a66fb1ff9cc72ab0cc58c71980e3d3661c5685ea0efb0" + url: "https://pub.dev" + source: hosted + version: "3.15.0" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + url: "https://pub.dev" + source: hosted + version: "2.10.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: "9bf168bccdf179ce90450b5f37e36fe263f591c9338828d6bf09b6f8d0f57f86" + url: "https://pub.dev" + source: hosted + version: "3.12.0" win32: dependency: transitive description: @@ -1116,4 +1148,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.2.6 <4.0.0" - flutter: ">=3.16.0" + flutter: ">=3.16.6" diff --git a/pubspec.yaml b/pubspec.yaml index c07c768..5660e33 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,6 +47,7 @@ dependencies: slang_flutter: ^3.29.0 flutter_svg: ^2.0.9 flutter_custom_tabs: ^2.0.0+1 + webview_flutter: ^4.7.0 dev_dependencies: build_runner: ^2.4.8