From 1f92de0dbfdae4e687357367619b7434ba5643cc Mon Sep 17 00:00:00 2001 From: David Djordjevic Date: Thu, 10 Mar 2022 23:31:47 +0100 Subject: [PATCH 1/3] Fix webview issue where content wouldn't load due to page navigating due to (mostly) adds --- lib/screens/webview_screen.dart | 57 ++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/lib/screens/webview_screen.dart b/lib/screens/webview_screen.dart index bf56eb4..6bf84af 100644 --- a/lib/screens/webview_screen.dart +++ b/lib/screens/webview_screen.dart @@ -20,10 +20,17 @@ class _WebViewScreenState extends State { var isLandScape = true.obs; final GlobalKey webViewKey = GlobalKey(); WebViewController? _webViewController; + + /// The initial url to start with + late final String _initialUrl; + @override void initState() { super.initState(); + _initialUrl = Get.arguments['mediaUrl'].toString(); + if (Platform.isAndroid) WebView.platform = AndroidWebView(); + if (Platform.isIOS) WebView.platform = CupertinoWebView(); SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]); @@ -93,29 +100,43 @@ class _WebViewScreenState extends State { }, onPageFinished: (_) async { await Future.delayed(const Duration(seconds: 1)); - // - for (var i = 0; i < 8; i++) { - await _webViewController!.runJavascriptReturningResult( - "document.getElementsByTagName('iframe')[$i].style.display='none';"); - await _webViewController!.runJavascriptReturningResult( - "document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].click();"); - } - // - for (var i = 0; i < 8; i++) { + + try { + // + for (var i = 0; i < 8; i++) { + await _webViewController!.runJavascriptReturningResult( + "document.getElementsByTagName('iframe')[$i].style.display='none';"); + await _webViewController!.runJavascriptReturningResult( + "document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].click();"); + } + // + for (var i = 0; i < 8; i++) { + await _webViewController!.runJavascriptReturningResult( + "document.getElementsByTagName('iframe')[$i].style.display='none';"); + } await _webViewController!.runJavascriptReturningResult( - "document.getElementsByTagName('iframe')[$i].style.display='none';"); - } - await _webViewController!.runJavascriptReturningResult( - "document.getElementsByClassName('jw-icon jw-icon-inline jw-button-color jw-reset jw-icon-fullscreen')[1].click();"); - await _webViewController!.runJavascriptReturningResult( - "if(document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].ariaLabel == 'Play'){document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].click();}"); - // - for (var i = 0; i < 8; i++) { + "document.getElementsByClassName('jw-icon jw-icon-inline jw-button-color jw-reset jw-icon-fullscreen')[1].click();"); await _webViewController!.runJavascriptReturningResult( - "document.getElementsByTagName('iframe')[$i].style.display='none';"); + "if(document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].ariaLabel == 'Play'){document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].click();}"); + // + for (var i = 0; i < 8; i++) { + await _webViewController!.runJavascriptReturningResult( + "document.getElementsByTagName('iframe')[$i].style.display='none';"); + } + } catch (e) { + print( + 'An error occurred while parsing data from webview:'); + print(e.toString()); + rethrow; } }, navigationDelegate: (NavigationRequest request) { + // If we are navigating to the destination url, allow it. + if (request.url == _initialUrl) { + return NavigationDecision.navigate; + } + + // Otherwise, reject any navigation to other web urls return NavigationDecision.prevent; }, backgroundColor: const Color(0x00000000), From 09f20f3dd350bd32ab4db5069b8a04b7927eee4b Mon Sep 17 00:00:00 2001 From: David Djordjevic Date: Thu, 10 Mar 2022 23:45:07 +0100 Subject: [PATCH 2/3] Fix webview needing to be manually toggled every time the app is restarted --- lib/screens/main_screen.dart | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/screens/main_screen.dart b/lib/screens/main_screen.dart index 0068a50..536dcb2 100644 --- a/lib/screens/main_screen.dart +++ b/lib/screens/main_screen.dart @@ -16,9 +16,9 @@ class MainScreen extends StatefulWidget { } class _MainScreenState extends State { + late final WebViewManager webViewManagerController; var currentIndex = 0.obs; var title = 'Home'.obs; - final webViewManagerController = Get.find(); final List _pages = [ const HomeScreen(), @@ -27,6 +27,17 @@ class _MainScreenState extends State { BookMarksScreen(), ]; + @override + void initState() { + super.initState(); + + webViewManagerController = Get.find(); + + // Make sure we only call this once during main screen initialization to + // also properly initialize the webView status + webViewManagerController.getVideoPlayerType(); + } + @override Widget build(BuildContext context) { return Scaffold( From 2261eed17518b4a6b188944e4cb048e094a91eea Mon Sep 17 00:00:00 2001 From: David Djordjevic Date: Fri, 11 Mar 2022 00:30:50 +0100 Subject: [PATCH 3/3] Add TakoPlayWebView widget --- lib/screens/media_fetch_screen.dart | 27 +++++---------- lib/screens/webview_screen.dart | 41 ++++++----------------- lib/widgets/tako_play_web_view.dart | 51 +++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 49 deletions(-) create mode 100644 lib/widgets/tako_play_web_view.dart diff --git a/lib/screens/media_fetch_screen.dart b/lib/screens/media_fetch_screen.dart index 7a19050..2cc6c73 100644 --- a/lib/screens/media_fetch_screen.dart +++ b/lib/screens/media_fetch_screen.dart @@ -10,6 +10,7 @@ import '../services/anime_service.dart'; import '../theme/tako_theme.dart'; import '../utils/constants.dart'; import '../utils/routes.dart'; +import '../widgets/tako_play_web_view.dart'; class MediaFetchScreen extends StatefulWidget { const MediaFetchScreen({Key? key}) : super(key: key); @@ -20,7 +21,6 @@ class MediaFetchScreen extends StatefulWidget { class _MediaFetchScreenState extends State { final GlobalKey webViewKey = GlobalKey(); - WebViewController? _webViewController; final webViewManagerController = Get.find(); final _random = Random(); var hasError = false.obs; @@ -67,26 +67,21 @@ class _MediaFetchScreenState extends State { if (snapshot.connectionState == ConnectionState.done) { return SizedBox.fromSize( size: Size(screenWidth / 1.5, screenHeight / 1.5), - child: WebView( + child: TakoPlayWebView( initialUrl: 'https:${snapshot.data}', - javascriptMode: JavascriptMode.unrestricted, - allowsInlineMediaPlayback: true, - onWebViewCreated: (controller) async { - _webViewController = controller; - }, - onPageFinished: (_) async { + onLoadingFinished: (_webViewController) async { mediaUrl = snapshot.data!; // Ads Block for (var i = 0; i < 8; i++) { - await _webViewController! + await _webViewController .runJavascriptReturningResult( "document.getElementsByTagName('iframe')[$i].style.display='none';"); - await _webViewController! + await _webViewController .runJavascriptReturningResult( "document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].click();"); } // Fetching VidStreaming Url - String rawUrl = await _webViewController! + String rawUrl = await _webViewController .runJavascriptReturningResult( "document.getElementsByClassName('jw-video jw-reset')[0].attributes.src.value;"); if (rawUrl == 'null') { @@ -94,16 +89,16 @@ class _MediaFetchScreenState extends State { } else { String url = rawUrl.split('"').toList()[1]; - await _webViewController! + await _webViewController .runJavascriptReturningResult( "if(document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].ariaLabel == 'Play'){document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].click();}"); - String resolutionCount = await _webViewController! + String resolutionCount = await _webViewController .runJavascriptReturningResult( "document.getElementsByClassName('jw-reset jw-settings-submenu-items')[1].getElementsByClassName('jw-reset-text jw-settings-content-item')['length'];"); for (var j = 0; j < double.parse(resolutionCount) - 1; j++) { - String rawResolution = await _webViewController! + String rawResolution = await _webViewController .runJavascriptReturningResult( "document.getElementsByClassName('jw-reset jw-settings-submenu-items')[1].getElementsByClassName('jw-reset-text jw-settings-content-item')[$j].textContent;"); String resolution = rawResolution @@ -126,10 +121,6 @@ class _MediaFetchScreenState extends State { }); } }, - navigationDelegate: (NavigationRequest request) { - return NavigationDecision.prevent; - }, - backgroundColor: const Color(0x00000000), ), ); } else { diff --git a/lib/screens/webview_screen.dart b/lib/screens/webview_screen.dart index 6bf84af..5c9dee8 100644 --- a/lib/screens/webview_screen.dart +++ b/lib/screens/webview_screen.dart @@ -8,6 +8,7 @@ import 'package:get/get.dart'; import 'package:webview_flutter/webview_flutter.dart'; import '../utils/constants.dart'; +import '../widgets/tako_play_web_view.dart'; class WebViewScreen extends StatefulWidget { const WebViewScreen({Key? key}) : super(key: key); @@ -19,16 +20,10 @@ class WebViewScreen extends StatefulWidget { class _WebViewScreenState extends State { var isLandScape = true.obs; final GlobalKey webViewKey = GlobalKey(); - WebViewController? _webViewController; - - /// The initial url to start with - late final String _initialUrl; @override void initState() { super.initState(); - _initialUrl = Get.arguments['mediaUrl'].toString(); - if (Platform.isAndroid) WebView.platform = AndroidWebView(); if (Platform.isIOS) WebView.platform = CupertinoWebView(); SystemChrome.setPreferredOrientations([ @@ -91,55 +86,39 @@ class _WebViewScreenState extends State { children: [ SizedBox.fromSize( size: Size(screenWidth, screenHeight), - child: WebView( + child: TakoPlayWebView( initialUrl: Get.arguments['mediaUrl'].toString(), - javascriptMode: JavascriptMode.unrestricted, - allowsInlineMediaPlayback: true, - onWebViewCreated: (controller) async { - _webViewController = controller; - }, - onPageFinished: (_) async { + onLoadingFinished: (_webViewController) async { await Future.delayed(const Duration(seconds: 1)); - try { // for (var i = 0; i < 8; i++) { - await _webViewController!.runJavascriptReturningResult( + await _webViewController.runJavascriptReturningResult( "document.getElementsByTagName('iframe')[$i].style.display='none';"); - await _webViewController!.runJavascriptReturningResult( + await _webViewController.runJavascriptReturningResult( "document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].click();"); } // for (var i = 0; i < 8; i++) { - await _webViewController!.runJavascriptReturningResult( + await _webViewController.runJavascriptReturningResult( "document.getElementsByTagName('iframe')[$i].style.display='none';"); } - await _webViewController!.runJavascriptReturningResult( + await _webViewController.runJavascriptReturningResult( "document.getElementsByClassName('jw-icon jw-icon-inline jw-button-color jw-reset jw-icon-fullscreen')[1].click();"); - await _webViewController!.runJavascriptReturningResult( + await _webViewController.runJavascriptReturningResult( "if(document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].ariaLabel == 'Play'){document.getElementsByClassName('jw-icon jw-icon-display jw-button-color jw-reset')[0].click();}"); // for (var i = 0; i < 8; i++) { - await _webViewController!.runJavascriptReturningResult( + await _webViewController.runJavascriptReturningResult( "document.getElementsByTagName('iframe')[$i].style.display='none';"); } } catch (e) { print( - 'An error occurred while parsing data from webview:'); + 'An error occurred while parsing data from webView:'); print(e.toString()); rethrow; } }, - navigationDelegate: (NavigationRequest request) { - // If we are navigating to the destination url, allow it. - if (request.url == _initialUrl) { - return NavigationDecision.navigate; - } - - // Otherwise, reject any navigation to other web urls - return NavigationDecision.prevent; - }, - backgroundColor: const Color(0x00000000), ), ), Positioned( diff --git a/lib/widgets/tako_play_web_view.dart b/lib/widgets/tako_play_web_view.dart new file mode 100644 index 0000000..6beb1c7 --- /dev/null +++ b/lib/widgets/tako_play_web_view.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +/// [TakoPlayWebView] is a webview specifically tailored for the needs of the +/// Tako Play app. Rather than always creating a webview and assigning it same +/// values each time, this widget can be instantiated without going though that +/// hassle. +class TakoPlayWebView extends StatefulWidget { + const TakoPlayWebView({ + required this.initialUrl, + this.onLoadingFinished, + Key? key, + }) : super(key: key); + + /// Initial url of the web view + final String initialUrl; + + /// Callback triggered once the page has finished loading + final Function(WebViewController)? onLoadingFinished; + + @override + State createState() => _TakoPlayWebViewState(); +} + +class _TakoPlayWebViewState extends State { + WebViewController? _webViewController; + + @override + Widget build(BuildContext context) => WebView( + initialUrl: widget.initialUrl, + javascriptMode: JavascriptMode.unrestricted, + allowsInlineMediaPlayback: true, + backgroundColor: const Color(0x00000000), + onWebViewCreated: (controller) async { + _webViewController = controller; + }, + onPageFinished: (_) async { + if (_webViewController == null) return; + widget.onLoadingFinished?.call(_webViewController!); + }, + navigationDelegate: (NavigationRequest request) { + // If we are navigating to the destination url, allow it. + if (request.url == widget.initialUrl) { + return NavigationDecision.navigate; + } + + // Otherwise, reject any navigation to other web urls + return NavigationDecision.prevent; + }, + ); +}