127 lines
3.9 KiB
TypeScript
127 lines
3.9 KiB
TypeScript
import { useAppTheme } from "@/hooks/use-app-theme";
|
|
import { useI18n } from "@/hooks/use-i18n";
|
|
import { convertToDMS, kmhToKnot } from "@/utils/geom";
|
|
import { MaterialIcons } from "@expo/vector-icons";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { Animated, TouchableOpacity, View } from "react-native";
|
|
import ButtonCreateNewHaulOrTrip from "../ButtonCreateNewHaulOrTrip";
|
|
import { Description } from "./Description";
|
|
type GPSInfoPanelProps = {
|
|
gpsData: Model.GPSResponse | undefined;
|
|
};
|
|
|
|
const GPSInfoPanel = ({ gpsData }: GPSInfoPanelProps) => {
|
|
const [isExpanded, setIsExpanded] = useState(true);
|
|
const [panelHeight, setPanelHeight] = useState(0);
|
|
const translateY = useRef(new Animated.Value(0)).current;
|
|
const blockBottom = useRef(new Animated.Value(0)).current;
|
|
const { t } = useI18n();
|
|
const { colors, styles } = useAppTheme();
|
|
|
|
useEffect(() => {
|
|
Animated.timing(translateY, {
|
|
toValue: isExpanded ? 0 : 200, // Dịch chuyển xuống 200px khi thu gọn
|
|
duration: 500,
|
|
useNativeDriver: true,
|
|
}).start();
|
|
}, [isExpanded]);
|
|
|
|
useEffect(() => {
|
|
const targetBottom = isExpanded ? panelHeight + 12 : 10;
|
|
Animated.timing(blockBottom, {
|
|
toValue: targetBottom,
|
|
duration: 500,
|
|
useNativeDriver: false,
|
|
}).start();
|
|
}, [isExpanded, panelHeight, blockBottom]);
|
|
|
|
const togglePanel = () => {
|
|
setIsExpanded(!isExpanded);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{/* Khối hình vuông */}
|
|
<Animated.View
|
|
style={{
|
|
position: "absolute",
|
|
bottom: blockBottom,
|
|
left: 5,
|
|
borderRadius: 4,
|
|
zIndex: 30,
|
|
}}
|
|
>
|
|
<ButtonCreateNewHaulOrTrip gpsData={gpsData} />
|
|
</Animated.View>
|
|
|
|
<Animated.View
|
|
style={[
|
|
styles.card,
|
|
{
|
|
transform: [{ translateY }],
|
|
backgroundColor: colors.card,
|
|
borderRadius: 0,
|
|
},
|
|
]}
|
|
className="absolute bottom-0 gap-5 right-0 px-4 pt-12 pb-2 left-0 h-auto w-full rounded-t-xl shadow-md"
|
|
onLayout={(event) => setPanelHeight(event.nativeEvent.layout.height)}
|
|
>
|
|
{/* Nút toggle ở top-right */}
|
|
<TouchableOpacity
|
|
onPress={togglePanel}
|
|
className="absolute top-2 right-2 z-10 rounded-full p-1"
|
|
style={{ backgroundColor: colors.card }}
|
|
>
|
|
<MaterialIcons
|
|
name={isExpanded ? "close" : "close"}
|
|
size={20}
|
|
color={colors.icon}
|
|
/>
|
|
</TouchableOpacity>
|
|
|
|
<View className="flex-row justify-between">
|
|
<View className="flex-1">
|
|
<Description
|
|
title={t("home.latitude")}
|
|
description={convertToDMS(gpsData?.lat ?? 0, true)}
|
|
/>
|
|
</View>
|
|
<View className="flex-1">
|
|
<Description
|
|
title={t("home.longitude")}
|
|
description={convertToDMS(gpsData?.lon ?? 0, false)}
|
|
/>
|
|
</View>
|
|
</View>
|
|
<View className="flex-row justify-between">
|
|
<View className="flex-1">
|
|
<Description
|
|
title={t("home.speed")}
|
|
description={`${kmhToKnot(gpsData?.s ?? 0).toString()} knot`}
|
|
/>
|
|
</View>
|
|
<View className="flex-1">
|
|
<Description
|
|
title={t("home.heading")}
|
|
description={`${gpsData?.h ?? 0}°`}
|
|
/>
|
|
</View>
|
|
</View>
|
|
</Animated.View>
|
|
|
|
{/* Nút floating để mở lại panel khi thu gọn */}
|
|
{!isExpanded && (
|
|
<TouchableOpacity
|
|
onPress={togglePanel}
|
|
className="absolute bottom-5 right-2 z-20 rounded-full p-2 shadow-lg"
|
|
style={{ backgroundColor: colors.card }}
|
|
>
|
|
<MaterialIcons name="info-outline" size={24} color={colors.icon} />
|
|
</TouchableOpacity>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default GPSInfoPanel;
|