Kantongku: animasi bar Uangmu Nyawamu (smooth width + shimmer + pulse kritis)
This commit is contained in:
@@ -48,6 +48,9 @@ export function DashboardScreen() {
|
|||||||
const [compare, setCompare] = useState({ current: 0, previous: 0 });
|
const [compare, setCompare] = useState({ current: 0, previous: 0 });
|
||||||
const [hidden, setHidden] = useState(true);
|
const [hidden, setHidden] = useState(true);
|
||||||
const heartScale = useRef(new Animated.Value(1)).current;
|
const heartScale = useRef(new Animated.Value(1)).current;
|
||||||
|
const hpAnim = useRef(new Animated.Value(0)).current;
|
||||||
|
const shimmerX = useRef(new Animated.Value(-140)).current;
|
||||||
|
const pulse = useRef(new Animated.Value(1)).current;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loop = Animated.loop(
|
const loop = Animated.loop(
|
||||||
@@ -67,6 +70,53 @@ export function DashboardScreen() {
|
|||||||
loop.start();
|
loop.start();
|
||||||
return () => loop.stop();
|
return () => loop.stop();
|
||||||
}, [heartScale]);
|
}, [heartScale]);
|
||||||
|
|
||||||
|
// Bar HP: width bergerak halus mengikuti data
|
||||||
|
useEffect(() => {
|
||||||
|
Animated.timing(hpAnim, {
|
||||||
|
toValue: hpPct,
|
||||||
|
duration: 800,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}).start();
|
||||||
|
}, [hpPct, hpAnim]);
|
||||||
|
|
||||||
|
// Shimmer: kilau menyapu di atas bar
|
||||||
|
useEffect(() => {
|
||||||
|
const loop = Animated.loop(
|
||||||
|
Animated.timing(shimmerX, {
|
||||||
|
toValue: 480,
|
||||||
|
duration: 2200,
|
||||||
|
useNativeDriver: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
loop.start();
|
||||||
|
return () => loop.stop();
|
||||||
|
}, [shimmerX]);
|
||||||
|
|
||||||
|
// Denyut saat kritis
|
||||||
|
useEffect(() => {
|
||||||
|
let loop: Animated.CompositeAnimation | null = null;
|
||||||
|
if (hpPct < 40) {
|
||||||
|
loop = Animated.loop(
|
||||||
|
Animated.sequence([
|
||||||
|
Animated.timing(pulse, {
|
||||||
|
toValue: 0.5,
|
||||||
|
duration: 480,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
Animated.timing(pulse, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 480,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
loop.start();
|
||||||
|
} else {
|
||||||
|
pulse.setValue(1);
|
||||||
|
}
|
||||||
|
return () => loop?.stop();
|
||||||
|
}, [hpPct, pulse]);
|
||||||
const [monthExpense, setMonthExpense] = useState(0);
|
const [monthExpense, setMonthExpense] = useState(0);
|
||||||
const [monthIncome, setMonthIncome] = useState(0);
|
const [monthIncome, setMonthIncome] = useState(0);
|
||||||
const [topCategory, setTopCategory] = useState<{
|
const [topCategory, setTopCategory] = useState<{
|
||||||
@@ -343,12 +393,32 @@ export function DashboardScreen() {
|
|||||||
<Text style={[styles.hpPct, { color: hpColor }]}>{hpPct}%</Text>
|
<Text style={[styles.hpPct, { color: hpColor }]}>{hpPct}%</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.hpTrack}>
|
<View style={styles.hpTrack}>
|
||||||
<View
|
<Animated.View
|
||||||
style={[
|
style={[
|
||||||
styles.hpFill,
|
styles.hpFill,
|
||||||
{ width: `${hpPct}%`, backgroundColor: hpBarColor },
|
{
|
||||||
|
backgroundColor: hpBarColor,
|
||||||
|
width: hpAnim.interpolate({
|
||||||
|
inputRange: [0, 100],
|
||||||
|
outputRange: ['0%', '100%'],
|
||||||
|
}),
|
||||||
|
opacity: pulse,
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
styles.shimmer,
|
||||||
|
{ transform: [{ translateX: shimmerX }] },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<LinearGradient
|
||||||
|
colors={['transparent', 'rgba(255,255,255,0.45)', 'transparent']}
|
||||||
|
start={{ x: 0, y: 0 }}
|
||||||
|
end={{ x: 1, y: 0 }}
|
||||||
|
style={styles.shimmerGradient}
|
||||||
|
/>
|
||||||
|
</Animated.View>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.hpFooter}>
|
<View style={styles.hpFooter}>
|
||||||
<Text style={[styles.hpStatus, { color: hpColor }]}>{hpStatus}</Text>
|
<Text style={[styles.hpStatus, { color: hpColor }]}>{hpStatus}</Text>
|
||||||
@@ -874,6 +944,14 @@ const styles = StyleSheet.create({
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
borderRadius: 7,
|
borderRadius: 7,
|
||||||
},
|
},
|
||||||
|
shimmer: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
width: '45%',
|
||||||
|
},
|
||||||
|
shimmerGradient: { flex: 1 },
|
||||||
hpFooter: {
|
hpFooter: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|||||||
Reference in New Issue
Block a user