|
|
|
import { Box } from '@/components/ui/box';
|
|
|
|
import { Button, ButtonText } from '@/components/ui/button';
|
|
|
|
import { Center } from '@/components/ui/center';
|
|
|
|
import { HStack } from '@/components/ui/hstack';
|
|
|
|
import { Text } from '@/components/ui/text';
|
|
|
|
import { Toast, ToastDescription, ToastTitle, useToast } from '@/components/ui/toast';
|
|
|
|
import { useCounterDispatch, useCounterState } from '@/states/CounterProvider';
|
|
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
|
|
import Animated, {
|
|
|
|
useSharedValue,
|
|
|
|
useAnimatedStyle,
|
|
|
|
withSequence,
|
|
|
|
withTiming,
|
|
|
|
} from 'react-native-reanimated';
|
|
|
|
|
|
|
|
export default function IndexPage() {
|
|
|
|
const state = useCounterState();
|
|
|
|
const dispatch = useCounterDispatch();
|
|
|
|
const toast = useToast();
|
|
|
|
const insets = useSafeAreaInsets();
|
|
|
|
|
|
|
|
const bounceY = useSharedValue(0);
|
|
|
|
|
|
|
|
const animatedStyle = useAnimatedStyle(() => ({
|
|
|
|
transform: [{ translateY: bounceY.value }],
|
|
|
|
}));
|
|
|
|
|
|
|
|
const onPress = () => {
|
|
|
|
const totalDuration = 500;
|
|
|
|
bounceY.value = 0; // 항상 리셋
|
|
|
|
bounceY.value = withSequence(
|
|
|
|
withTiming(-16, { duration: totalDuration * 0.3 }), // 위로 빠르게
|
|
|
|
withTiming(4, { duration: totalDuration * 0.3 }), // 아래로 반동
|
|
|
|
withTiming(-8, { duration: totalDuration * 0.2 }), // 위로 살짝
|
|
|
|
withTiming(0, { duration: totalDuration * 0.2 }) // 원위치
|
|
|
|
);
|
|
|
|
toast.show({
|
|
|
|
placement: 'top',
|
|
|
|
duration: 2000,
|
|
|
|
render: () => {
|
|
|
|
return (
|
|
|
|
<Box style={{ marginTop: insets.top + 12, alignItems: 'center', width: '100%' }}>
|
|
|
|
<Toast
|
|
|
|
nativeID="text"
|
|
|
|
variant="solid"
|
|
|
|
className="py2 mx-5 max-w-[90%] flex-row items-center justify-center gap-2 rounded-full px-5 opacity-80">
|
|
|
|
<ToastTitle>타이틀</ToastTitle>
|
|
|
|
<ToastDescription>설명</ToastDescription>
|
|
|
|
</Toast>
|
|
|
|
</Box>
|
|
|
|
);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Box className="flex-1 items-center justify-center">
|
|
|
|
<Box className="h-64 w-64 rounded-md border border-secondary-600 p-3">
|
|
|
|
<Center>
|
|
|
|
<Text className="text-lg font-semibold">Count: {state.count}</Text>
|
|
|
|
</Center>
|
|
|
|
<HStack className="w-full flex-row justify-between gap-0 p-0">
|
|
|
|
<Text className="text-red-600">Text1</Text>
|
|
|
|
<Box className="flex-1" />
|
|
|
|
<Text className="text-blue-600">Text2</Text>
|
|
|
|
</HStack>
|
|
|
|
|
|
|
|
<Box className="flex-1 items-center justify-center">
|
|
|
|
<Animated.View style={animatedStyle}>
|
|
|
|
<Button onPress={onPress}>
|
|
|
|
<ButtonText>🍞</ButtonText>
|
|
|
|
</Button>
|
|
|
|
</Animated.View>
|
|
|
|
</Box>
|
|
|
|
<HStack className="h-10 w-full flex-row justify-between gap-0 bg-red-500 p-0">
|
|
|
|
<Button onPress={() => dispatch({ type: 'INCREMENT' })}>
|
|
|
|
<ButtonText>+</ButtonText>
|
|
|
|
</Button>
|
|
|
|
<Box className="flex-1" />
|
|
|
|
<Button onPress={() => dispatch({ type: 'DECREMENT' })}>
|
|
|
|
<ButtonText>-</ButtonText>
|
|
|
|
</Button>
|
|
|
|
</HStack>
|
|
|
|
</Box>
|
|
|
|
</Box>
|
|
|
|
);
|
|
|
|
}
|