Kantongku: animasi bar Uangmu Nyawamu (smooth width + shimmer + pulse kritis)

This commit is contained in:
Bro
2026-08-16 16:15:13 +07:00
parent 99ee84a998
commit 28dccbfd07
+80 -2
View File
@@ -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',