diff --git a/kraken/lib/src/widget/kraken.dart b/kraken/lib/src/widget/kraken.dart index 3cd2c24982..d8d00bf4b1 100644 --- a/kraken/lib/src/widget/kraken.dart +++ b/kraken/lib/src/widget/kraken.dart @@ -11,6 +11,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/scheduler.dart'; import 'package:kraken/kraken.dart'; import 'package:kraken/rendering.dart'; import 'package:kraken/dom.dart' as dom; @@ -79,6 +80,11 @@ class Kraken extends StatefulWidget { // A method channel for receiving messaged from JavaScript code and sending message to JavaScript. final KrakenMethodChannel? javaScriptChannel; + // Register the RouteObserver to observer page navigation. + // This is useful if you wants to pause kraken timers and callbacks when kraken widget are hidden by page route. + // https://api.flutter.dev/flutter/widgets/RouteObserver-class.html + final RouteObserver>? routeObserver; + final LoadErrorHandler? onLoadError; final LoadHandler? onLoad; @@ -200,6 +206,7 @@ class Kraken extends StatefulWidget { // Kraken's http client interceptor. this.httpClientInterceptor, this.uriParser, + this.routeObserver, // Kraken's viewportWidth options only works fine when viewportWidth is equal to window.physicalSize.width / window.devicePixelRatio. // Maybe got unexpected error when change to other values, use this at your own risk! // We will fixed this on next version released. (v0.6.0) @@ -227,7 +234,7 @@ class Kraken extends StatefulWidget { _KrakenState createState() => _KrakenState(); } -class _KrakenState extends State { +class _KrakenState extends State with RouteAware { Map>? _actionMap; final FocusNode _focusNode = FocusNode(); @@ -269,15 +276,15 @@ class _KrakenState extends State { @override Widget build(BuildContext context) { return RepaintBoundary( - child: FocusableActionDetector( - actions: _actionMap, - focusNode: _focusNode, - onFocusChange: _handleFocusChange, - child: _KrakenRenderObjectWidget( - context.widget as Kraken, - widgetDelegate, + child: FocusableActionDetector( + actions: _actionMap, + focusNode: _focusNode, + onFocusChange: _handleFocusChange, + child: _KrakenRenderObjectWidget( + context.widget as Kraken, + widgetDelegate, + ) ) - ) ); } @@ -303,6 +310,37 @@ class _KrakenState extends State { _focusNode.requestFocus(); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (widget.routeObserver != null) { + widget.routeObserver!.subscribe(this, ModalRoute.of(context)!); + } + } + + // Resume call timer and callbacks when kraken widget change to visible. + @override + void didPopNext() { + assert(widget.controller != null); + widget.controller!.resume(); + } + + // Pause all timer and callbacks when kraken widget has been invisible. + @override + void didPushNext() { + assert(widget.controller != null); + widget.controller!.pause(); + } + + @override + void dispose() { + if (widget.routeObserver != null) { + widget.routeObserver!.unsubscribe(this); + } + super.dispose(); + } + + // Get the target platform. TargetPlatform _getTargetPlatform() { final ThemeData theme = Theme.of(context); @@ -780,7 +818,7 @@ class _KrakenState extends State { } class _KrakenRenderObjectWidget extends SingleChildRenderObjectWidget { - /// Creates a widget that visually hides its child. + // Creates a widget that visually hides its child. const _KrakenRenderObjectWidget( Kraken widget, WidgetDelegate widgetDelegate, @@ -807,31 +845,28 @@ This situation often happened when you trying creating kraken when FlutterView n } KrakenController controller = KrakenController( - shortHash(_krakenWidget.hashCode), - viewportWidth, - viewportHeight, - background: _krakenWidget.background, - showPerformanceOverlay: Platform.environment[ENABLE_PERFORMANCE_OVERLAY] != null, - bundle: _krakenWidget.bundle, - onLoad: _krakenWidget.onLoad, - onLoadError: _krakenWidget.onLoadError, - onJSError: _krakenWidget.onJSError, - methodChannel: _krakenWidget.javaScriptChannel, - gestureListener: _krakenWidget.gestureListener, - navigationDelegate: _krakenWidget.navigationDelegate, - devToolsService: _krakenWidget.devToolsService, - httpClientInterceptor: _krakenWidget.httpClientInterceptor, - widgetDelegate: _widgetDelegate, - uriParser: _krakenWidget.uriParser + shortHash(_krakenWidget.hashCode), + viewportWidth, + viewportHeight, + background: _krakenWidget.background, + showPerformanceOverlay: Platform.environment[ENABLE_PERFORMANCE_OVERLAY] != null, + bundle: _krakenWidget.bundle, + onLoad: _krakenWidget.onLoad, + onLoadError: _krakenWidget.onLoadError, + onJSError: _krakenWidget.onJSError, + methodChannel: _krakenWidget.javaScriptChannel, + gestureListener: _krakenWidget.gestureListener, + navigationDelegate: _krakenWidget.navigationDelegate, + devToolsService: _krakenWidget.devToolsService, + httpClientInterceptor: _krakenWidget.httpClientInterceptor, + widgetDelegate: _widgetDelegate, + uriParser: _krakenWidget.uriParser ); if (kProfileMode) { PerformanceTiming.instance().mark(PERF_CONTROLLER_INIT_END); } - // FIXME: reset href when dart hot reload that href is prev href - controller.href = ''; - return controller.view.getRootRenderObject(); } @@ -847,6 +882,8 @@ This situation often happened when you trying creating kraken when FlutterView n double viewportWidth = _krakenWidget.viewportWidth ?? window.physicalSize.width / window.devicePixelRatio; double viewportHeight = _krakenWidget.viewportHeight ?? window.physicalSize.height / window.devicePixelRatio; + if (controller.view.document.documentElement == null) return; + if (viewportWidthHasChanged) { controller.view.viewportWidth = viewportWidth; controller.view.document.documentElement!.renderStyle.width = CSSLengthValue(viewportWidth, CSSLengthType.PX);