From fcf9f12f952242ec482943a0b2e7fb3b36acd026 Mon Sep 17 00:00:00 2001 From: Jganenokk Date: Thu, 20 Aug 2026 22:22:35 +0700 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE?= =?UTF-8?q?=D0=B4=20=D0=BF=D0=BE=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B0?= =?UTF-8?q?=D0=BC=20=D0=B8=20=D0=B4=D0=B8=D0=BF=D0=BB=D0=B8=D0=BD=D0=BA?= =?UTF-8?q?=D0=B8=20=D1=81=20=D0=BC=D0=B8=D0=BD=D0=B8=D0=B0=D0=BF=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/utils/link_opener.dart | 15 ++++++++ .../screens/webapp/web_app_screen.dart | 9 +++-- test/webview_scheme_test.dart | 36 +++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 test/webview_scheme_test.dart diff --git a/lib/core/utils/link_opener.dart b/lib/core/utils/link_opener.dart index 5937900..42ef5af 100644 --- a/lib/core/utils/link_opener.dart +++ b/lib/core/utils/link_opener.dart @@ -6,6 +6,21 @@ import 'package:url_launcher/url_launcher.dart'; import '../../frontend/widgets/custom_notification.dart'; import '../../frontend/widgets/max_link_handler.dart'; +const Set _webViewSchemes = { + 'http', + 'https', + 'about', + 'data', + 'blob', + 'javascript', + 'file', +}; + +bool leavesWebView(String? scheme) { + if (scheme == null || scheme.isEmpty) return false; + return !_webViewSchemes.contains(scheme.toLowerCase()); +} + Future openExternalUrl(BuildContext context, String url) async { if (await tryHandleMaxLink(context, url)) return; if (!context.mounted) return; diff --git a/lib/frontend/screens/webapp/web_app_screen.dart b/lib/frontend/screens/webapp/web_app_screen.dart index 93453f1..ad410e5 100644 --- a/lib/frontend/screens/webapp/web_app_screen.dart +++ b/lib/frontend/screens/webapp/web_app_screen.dart @@ -182,8 +182,13 @@ class _WebAppScreenState extends State { return NavigationActionPolicy.CANCEL; } final handler = widget.shouldOverrideUrlLoading; - if (handler == null) return NavigationActionPolicy.ALLOW; - return handler(controller, action, _launch?.url); + if (handler != null) return handler(controller, action, _launch?.url); + + if (uri != null && leavesWebView(uri.scheme)) { + if (mounted) await openExternalUrl(context, uri.toString()); + return NavigationActionPolicy.CANCEL; + } + return NavigationActionPolicy.ALLOW; } @override diff --git a/test/webview_scheme_test.dart b/test/webview_scheme_test.dart new file mode 100644 index 0000000..0c23bda --- /dev/null +++ b/test/webview_scheme_test.dart @@ -0,0 +1,36 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:komet/core/links/max_link.dart'; +import 'package:komet/core/utils/link_opener.dart'; + +void main() { + group('leavesWebView', () { + test('keeps page navigation inside the web view', () { + for (final scheme in [ + 'http', + 'https', + 'HTTPS', + 'about', + 'data', + 'blob', + ]) { + expect(leavesWebView(scheme), isFalse, reason: scheme); + } + }); + + test('hands app schemes over to the app', () { + for (final scheme in ['max', 'MAX', 'komet', 'tel', 'mailto', 'intent']) { + expect(leavesWebView(scheme), isTrue, reason: scheme); + } + }); + + test('treats a missing scheme as in-page', () { + expect(leavesWebView(null), isFalse); + expect(leavesWebView(''), isFalse); + }); + }); + + test('a max deep link from a web view resolves to in-app content', () { + expect(MaxLink.parse('max://max.ru/somechannel'), isA()); + expect(MaxLink.isMaxLink('max://max.ru/?cid=424242'), isTrue); + }); +}