diff --git a/lib/app_flavored.dart b/lib/app_flavored.dart index 3a107c3..0d8d1d0 100644 --- a/lib/app_flavored.dart +++ b/lib/app_flavored.dart @@ -34,6 +34,7 @@ class FlavoredAppState extends ConsumerState { builder: (overrideLocale) => Builder( builder: (context) => MaterialApp( scaffoldMessengerKey: Keys.scaffoldMessengerStateKey, + navigatorObservers: [routeObserver], debugShowCheckedModeBanner: false, initialRoute: '/', routes: RouterF.routes, diff --git a/lib/app_opener.dart b/lib/app_opener.dart index 6d47f72..d4c06dc 100644 --- a/lib/app_opener.dart +++ b/lib/app_opener.dart @@ -28,6 +28,7 @@ class OpenerApp extends ConsumerWidget { child: OverrideLocale( builder: (overrideLocale) => MaterialApp( navigatorKey: Keys.navigatorKey, + navigatorObservers: [routeObserver], scaffoldMessengerKey: Keys.scaffoldMessengerStateKey, debugShowCheckedModeBanner: false, initialRoute: AppRouter.initRoute, diff --git a/lib/flavored/web_view.f.dart b/lib/flavored/web_view.f.dart index af5f736..e15a0f7 100644 --- a/lib/flavored/web_view.f.dart +++ b/lib/flavored/web_view.f.dart @@ -36,12 +36,13 @@ class WebViewF extends ConsumerStatefulWidget { FlavoredWebViewState createState() => FlavoredWebViewState(); } -class FlavoredWebViewState extends ConsumerState { +class FlavoredWebViewState extends ConsumerState with RouteAware { HeadlessInAppWebView? headlessWebView; late HumHubF instance; final _scaffoldKey = GlobalKey(); late PullToRefreshController pullToRefreshController; late double downloadProgress = 0; + bool _isRouteObserverSubscribed = false; @override void initState() { @@ -62,6 +63,27 @@ class FlavoredWebViewState extends ConsumerState { ); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (!_isRouteObserverSubscribed) { + routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute); + _isRouteObserverSubscribed = true; + } + } + + /// Called when a route pushed on top of WebViewF (e.g. AuthWebView) is popped. + /// That screen locks orientation to portrait, and since popping back doesn't + /// re-run WebViewF's own route builder, the lock would otherwise persist. + @override + void didPopNext() { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.landscapeLeft, + DeviceOrientation.landscapeRight, + ]); + } + @override Widget build(BuildContext context) { ref.watch(humHubFRemoteConfigProvider); @@ -435,6 +457,7 @@ class FlavoredWebViewState extends ConsumerState { @override void dispose() { + routeObserver.unsubscribe(this); super.dispose(); if (headlessWebView != null) { headlessWebView!.dispose(); diff --git a/lib/pages/web_view.dart b/lib/pages/web_view.dart index d6bbec7..d072d00 100644 --- a/lib/pages/web_view.dart +++ b/lib/pages/web_view.dart @@ -43,7 +43,7 @@ class WebView extends ConsumerStatefulWidget { WebViewAppState createState() => WebViewAppState(); } -class WebViewAppState extends ConsumerState { +class WebViewAppState extends ConsumerState with RouteAware { final _scaffoldKey = GlobalKey(); late Manifest _manifest; late URLRequest _initialRequest; @@ -88,10 +88,25 @@ class WebViewAppState extends ConsumerState { headers: ref.read(humHubProvider).customHeaders)); }, ); + routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute); _isInit = true; } } + /// Called when a route pushed on top of WebView (e.g. Settings, Console, Help, + /// AuthWebView) is popped. Those screens lock orientation to portrait, and since + /// popping back doesn't re-run WebView's own route builder, the lock would + /// otherwise persist indefinitely. + @override + void didPopNext() { + logInfo('VERIFY_PROBE: WebView.didPopNext firing, restoring landscape+portrait orientation'); + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.landscapeLeft, + DeviceOrientation.landscapeRight, + ]); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -592,6 +607,7 @@ class WebViewAppState extends ConsumerState { logInfo('Disposing WebView and controllers'); if (_headlessWebView != null) _headlessWebView!.dispose(); _keyboardSubscription?.cancel(); + routeObserver.unsubscribe(this); super.dispose(); } } diff --git a/lib/util/const.dart b/lib/util/const.dart index dc78d17..1ed8cdd 100644 --- a/lib/util/const.dart +++ b/lib/util/const.dart @@ -4,6 +4,10 @@ class Keys{ static GlobalKey navigatorKey = GlobalKey(); } +/// Notifies [RouteAware] pages (e.g. WebView) when a route pushed on top of them is popped, +/// so they can restore orientation/UI state that the popped route may have overridden. +final RouteObserver routeObserver = RouteObserver(); + class Assets { static String logo = "assets/images/logo.png"; static String settings = "assets/images/icons/settings.svg";