diff --git a/AGENTS.md b/AGENTS.md index 2910b18..aa5e1db 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -128,4 +128,4 @@ Avoid file paths, line numbers, or code listings reproduced from the diff. Inclu ## Git Workflow - Main branch: `main` -- Conventional-ish prefixes are common in history: `feat:`, `fix:`, `chore:`, `test(e2e):`, `chore(deps):`. Keep messages short. +- Commit and PR subjects: `prefix: short description`, no trailing period. Platform-specific changes use `Android: …` / `iOS: …`; everything else is prefixed with the affected part of the app (`onboarding: …`, `widget: …`) or `chore:` / `fix:` / `docs:` for non-feature changes. Same pattern as the main evcc repo. Keep messages short. diff --git a/screens/MainScreen.tsx b/screens/MainScreen.tsx index 6112633..0785d29 100644 --- a/screens/MainScreen.tsx +++ b/screens/MainScreen.tsx @@ -1,6 +1,13 @@ import { useState, useEffect, useRef, useCallback, useMemo } from "react"; import { WebView, WebViewMessageEvent } from "react-native-webview"; -import { StyleSheet, Animated, View, Text } from "react-native"; +import { + StyleSheet, + Animated, + View, + Text, + Platform, + BackHandler, +} from "react-native"; import * as Linking from "expo-linking"; import * as Haptics from "expo-haptics"; import AppText from "components/AppText"; @@ -13,6 +20,7 @@ import { ShouldStartLoadRequest, WebViewErrorEvent, WebViewHttpErrorEvent, + WebViewNavigation, } from "react-native-webview/lib/WebViewTypes"; import { NativeStackScreenProps } from "@react-navigation/native-stack"; import { RootStackParamList } from "types"; @@ -31,6 +39,7 @@ export default function MainScreen({ const insets = useSafeAreaInsets(); const { activeServer, targetPath, clearTargetPath } = useAppContext(); const webViewRef = useRef(null); + const canGoBackRef = useRef(false); const [isConnected, setIsConnected] = useState(false); const [webViewKey, setWebViewKey] = useState(0); const [downloadedFile, setDownloadedFile] = useState(null); @@ -61,6 +70,22 @@ export default function MainScreen({ } }, [targetPath, isConnected, clearTargetPath]); + // Android back button navigates the web UI's history instead of leaving the app + useEffect(() => { + if (Platform.OS !== "android") return; + const subscription = BackHandler.addEventListener( + "hardwareBackPress", + () => { + if (navigation.isFocused() && canGoBackRef.current) { + webViewRef.current?.goBack(); + return true; + } + return false; + }, + ); + return () => subscription.remove(); + }, [navigation]); + // Reconnect if connection is lost useEffect(() => { let intervalId: NodeJS.Timeout | undefined; @@ -200,6 +225,13 @@ export default function MainScreen({ setIsConnected(false); }, []); + const onNavigationStateChange = useCallback( + (navState: WebViewNavigation) => { + canGoBackRef.current = navState.canGoBack; + }, + [], + ); + const LayoutMemoized = useMemo( () => ( @@ -237,6 +269,7 @@ export default function MainScreen({ onContentProcessDidTerminate={onTerminate} onMessage={handleMessage} onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} + onNavigationStateChange={onNavigationStateChange} />