From c90f9c71807da3ca79d8d5c7f9f72115f99de0e3 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 6 Jun 2026 19:23:59 +0200 Subject: [PATCH] Fix back button sometimes failing on Android --- web/components/widgets/pagination.tsx | 3 ++- web/pages/_app.tsx | 14 ++++++++++---- web/pages/signup.tsx | 8 ++++++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/web/components/widgets/pagination.tsx b/web/components/widgets/pagination.tsx index 84ac294d..f3bb3a60 100644 --- a/web/components/widgets/pagination.tsx +++ b/web/components/widgets/pagination.tsx @@ -1,7 +1,8 @@ import {ChevronLeftIcon, ChevronRightIcon} from '@heroicons/react/24/solid' import clsx from 'clsx' import {range} from 'lodash' -import {usePathname, useRouter} from 'next/navigation' +import {usePathname} from 'next/navigation' +import {useRouter} from 'next/router' import {useEffect} from 'react' import {buttonClass} from 'web/components/buttons/button' import {LoadingIndicator} from 'web/components/widgets/loading-indicator' diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index 4f182784..a3671532 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -14,8 +14,7 @@ import {isUrl} from 'common/parsing' import type {AppProps} from 'next/app' import {Major_Mono_Display} from 'next/font/google' import Head from 'next/head' -import {useRouter} from 'next/navigation' -import {Router} from 'next/router' +import {Router, useRouter} from 'next/router' import posthog from 'posthog-js' import {PostHogProvider} from 'posthog-js/react' import {useEffect, useState} from 'react' @@ -43,8 +42,15 @@ if (Capacitor.isNativePlatform()) { // Note sure it's doing anything, though. Need to check StatusBar.setOverlaysWebView({overlay: false}).catch(console.warn) - App.addListener('backButton', () => { - window.dispatchEvent(new CustomEvent('appBackButton')) + App.addListener('backButton', ({canGoBack}) => { + // Only navigate back when the WebView actually has history to pop; + // otherwise exit the app so the back button doesn't become a dead no-op + // at the root of the stack. + if (canGoBack) { + window.dispatchEvent(new CustomEvent('appBackButton')) + } else { + App.exitApp() + } }) // Remove live update as the free plan is very limited (100 live updates per year). Do releases on Play Store instead. diff --git a/web/pages/signup.tsx b/web/pages/signup.tsx index 0a6a0d21..ec41726f 100644 --- a/web/pages/signup.tsx +++ b/web/pages/signup.tsx @@ -57,7 +57,11 @@ export default function SignupPage() { } window.addEventListener('popstate', handlePopState) - window.history.replaceState({signupStep: 0}, '') + // Spread the existing state so we don't clobber Next.js's own routing + // bookkeeping (__N/key/idx). Overwriting it desyncs the history index and + // breaks back navigation for the rest of the session (notably the native + // Android back button, which has no fallback). + window.history.replaceState({...window.history.state, signupStep: 0}, '') return () => { window.removeEventListener('popstate', handlePopState) @@ -69,7 +73,7 @@ export default function SignupPage() { }, [auth.currentUser?.uid]) const advanceToStep = (nextStep: number) => { - window.history.pushState({signupStep: nextStep}, '') + window.history.pushState({...window.history.state, signupStep: nextStep}, '') setStep(nextStep) scrollTo(0, 0) }