Files

110 lines
3.4 KiB
TypeScript

import React, { useEffect, useRef } from "react";
import { Animated, StyleSheet, View } from "react-native";
import { LinearGradient } from "expo-linear-gradient";
import type { RootTabParamList } from "../../types/navigation";
import lineColorList from "../../assets/originData/lineColorList";
import { stationIDPair } from "../../lib/getStationList";
import { fixedColors } from "../../lib/theme/colors";
export type TabBarBackgroundProps = {
routeName: keyof RootTabParamList;
selectedLine?: string | null;
isDark: boolean;
isExtraWindowOpen: boolean;
};
export type TabBarAppearance = {
lineColor: string | null;
lineColorDark: string | null;
showGradient: boolean;
defaultBg: string;
activeTintColor: string;
inactiveTintColor: string;
};
const getLineColor = (selectedLine?: string | null) => {
if (!selectedLine) return null;
const lineCode = stationIDPair[selectedLine as keyof typeof stationIDPair];
return lineCode ? lineColorList[lineCode] : null;
};
const darkenHex = (hex: string, factor: number) => {
const h = hex.replace("#", "");
const r = Math.round(parseInt(h.slice(0, 2), 16) * factor);
const g = Math.round(parseInt(h.slice(2, 4), 16) * factor);
const b = Math.round(parseInt(h.slice(4, 6), 16) * factor);
return `#${[r, g, b].map((v) => Math.min(255, v).toString(16).padStart(2, "0")).join("")}`;
};
export const getTabBarAppearance = ({
routeName,
selectedLine,
isDark,
isExtraWindowOpen,
}: TabBarBackgroundProps): TabBarAppearance => {
const lineColor = getLineColor(selectedLine);
const lineColorDark = lineColor ? darkenHex(lineColor, 0.78) : null;
const showGradient =
routeName === "positions" && !!lineColor && !!lineColorDark;
const defaultBg = isDark ? "#1c1c1e" : "white";
const defaultActive = isDark ? "#ffffff" : "#007AFF";
const defaultInactive = isDark ? "#8e8e93" : "#8e8e93";
const useLightTint = showGradient || isExtraWindowOpen;
return {
lineColor,
lineColorDark,
showGradient,
defaultBg,
activeTintColor: useLightTint ? "white" : defaultActive,
inactiveTintColor: useLightTint
? "rgba(255,255,255,0.75)"
: defaultInactive,
};
};
export function TabBarBackground(props: TabBarBackgroundProps) {
const { isExtraWindowOpen } = props;
const fadeAnim = useRef(new Animated.Value(0)).current;
const { lineColor, lineColorDark, showGradient, defaultBg } =
getTabBarAppearance(props);
useEffect(() => {
Animated.timing(fadeAnim, {
toValue: isExtraWindowOpen ? 1 : 0,
duration: 300,
useNativeDriver: false,
}).start();
}, [isExtraWindowOpen]);
return (
<View style={{ flex: 1 }}>
{/* 路線カラー or デフォルト背景 */}
{showGradient ? (
<LinearGradient
colors={[lineColor!, lineColorDark!]}
start={{ x: 0, y: 0 }}
end={{ x: 0, y: 1 }}
style={StyleSheet.absoluteFill}
/>
) : (
<View
style={{
...StyleSheet.absoluteFill,
backgroundColor: defaultBg,
}}
/>
)}
{/* 追加ウィンドウ時の青グラデーション(フェードイン/アウト) */}
<Animated.View style={{ ...StyleSheet.absoluteFill, opacity: fadeAnim }}>
<LinearGradient
colors={[fixedColors.primary, fixedColors.primaryDark]}
start={{ x: 0, y: 0 }}
end={{ x: 0, y: 1 }}
style={{ flex: 1 }}
/>
</Animated.View>
</View>
);
}