1import { useCallback, useRef, useState, type ComponentProps } from "react";
2import {
3 useWindowDimensions,
4 View,
5 type NativeScrollEvent,
6 type NativeSyntheticEvent,
7} from "react-native";
8import { useSafeAreaInsets } from "react-native-safe-area-context";
9import { MaterialNewThreadButton } from "../../components/MaterialNewThreadButton";
10import type { AndroidHomeFabLayout as SharedAndroidHomeFabLayout } from "./AndroidHomeFab.shared";
11import { useWorkspaceState } from "../../state/workspace";
12import { MaterialFabScrollContext } from "./MaterialFabScrollContext";
13import { updateMaterialFabScroll } from "./material-fab-scroll";
14import { useAppearancePreferences } from "../settings/appearance/AppearancePreferencesProvider";
15
16export function AndroidHomeFabLayout(props: ComponentProps<typeof SharedAndroidHomeFabLayout>) {
17 const insets = useSafeAreaInsets();
18 const { appearance } = useAppearancePreferences();
19 const { fontScale } = useWindowDimensions();
20 const [layoutWidth, setLayoutWidth] = useState<number | null>(null);
21 const { state } = useWorkspaceState();
22 const [expanded, setExpanded] = useState(true);
23 const scrollState = useRef({ anchor: 0, expanded: true });
24 const onScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
25 const { contentOffset, contentSize, layoutMeasurement } = event.nativeEvent;
26 const next = updateMaterialFabScroll(
27 scrollState.current,
28 contentOffset.y,
29 contentSize.height - layoutMeasurement.height,
30 );
31 if (next.expanded !== scrollState.current.expanded) setExpanded(next.expanded);
32 scrollState.current = next;
33 }, []);
34
35 // Remount only the FAB when its font or pane changes to clear the cached expanded width.
36 return (
37 <View className="flex-1" onLayout={(event) => setLayoutWidth(event.nativeEvent.layout.width)}>
38 <MaterialFabScrollContext value={onScroll}>{props.children}</MaterialFabScrollContext>
39 {!props.disabled && state.hasConnections && layoutWidth !== null ? (
40 <MaterialNewThreadButton
41 key={`${appearance.baseFontSize}:${fontScale}:${layoutWidth}`}
42 extended
43 expanded={expanded}
44 onPress={props.onStartNewTask}
45 className="absolute right-5"
46 style={{
47 bottom: props.sidebar
48 ? Math.max(insets.bottom, 12) + 6
49 : Math.max(insets.bottom, 16) + 16,
50 }}
51 />
52 ) : null}
53 </View>
54 );
55}