Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
36 changes: 35 additions & 1 deletion screens/MainScreen.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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";
Expand All @@ -31,6 +39,7 @@ export default function MainScreen({
const insets = useSafeAreaInsets();
const { activeServer, targetPath, clearTargetPath } = useAppContext();
const webViewRef = useRef<WebView>(null);
const canGoBackRef = useRef(false);
const [isConnected, setIsConnected] = useState(false);
const [webViewKey, setWebViewKey] = useState(0);
const [downloadedFile, setDownloadedFile] = useState<string | null>(null);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -200,6 +225,13 @@ export default function MainScreen({
setIsConnected(false);
}, []);

const onNavigationStateChange = useCallback(
(navState: WebViewNavigation) => {
canGoBackRef.current = navState.canGoBack;
},
[],
);

const LayoutMemoized = useMemo(
() => (
<View style={{ flex: 1, backgroundColor: colors.background }}>
Expand Down Expand Up @@ -237,6 +269,7 @@ export default function MainScreen({
onContentProcessDidTerminate={onTerminate}
onMessage={handleMessage}
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
onNavigationStateChange={onNavigationStateChange}
/>
</Animated.View>
<Animated.View
Expand Down Expand Up @@ -282,6 +315,7 @@ export default function MainScreen({
isConnected,
onError,
onShouldStartLoadWithRequest,
onNavigationStateChange,
onTerminate,
handleMessage,
openSettings,
Expand Down
Loading