73 lines
2.4 KiB
TypeScript
73 lines
2.4 KiB
TypeScript
import React, { useEffect, useRef } from 'react';
|
|
import { View, Animated, StyleSheet, Text } from 'react-native';
|
|
import Svg, { Circle } from 'react-native-svg';
|
|
import { theme } from '../styles/theme';
|
|
|
|
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
|
|
|
|
interface CircularProgressProps {
|
|
size?: number;
|
|
strokeWidth?: number;
|
|
progress: number; // 0 to 100
|
|
color?: string;
|
|
backgroundColor?: string;
|
|
}
|
|
|
|
export function CircularProgress({
|
|
size = 60,
|
|
strokeWidth = 6,
|
|
progress,
|
|
color = theme.colors.primary,
|
|
backgroundColor = theme.colors.gray200,
|
|
}: CircularProgressProps) {
|
|
const animatedValue = useRef(new Animated.Value(0)).current;
|
|
const radius = (size - strokeWidth) / 2;
|
|
const circumference = radius * 2 * Math.PI;
|
|
|
|
useEffect(() => {
|
|
Animated.timing(animatedValue, {
|
|
toValue: progress,
|
|
duration: 1000,
|
|
useNativeDriver: true,
|
|
}).start();
|
|
}, [progress]);
|
|
|
|
const strokeDashoffset = animatedValue.interpolate({
|
|
inputRange: [0, 100],
|
|
outputRange: [circumference, 0],
|
|
});
|
|
|
|
return (
|
|
<View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
|
|
<Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
|
|
<Circle
|
|
cx={size / 2}
|
|
cy={size / 2}
|
|
r={radius}
|
|
stroke={backgroundColor}
|
|
strokeWidth={strokeWidth}
|
|
fill="transparent"
|
|
/>
|
|
<AnimatedCircle
|
|
cx={size / 2}
|
|
cy={size / 2}
|
|
r={radius}
|
|
stroke={color}
|
|
strokeWidth={strokeWidth}
|
|
fill="transparent"
|
|
strokeDasharray={circumference}
|
|
strokeDashoffset={strokeDashoffset}
|
|
strokeLinecap="round"
|
|
rotation="-90"
|
|
origin={`${size / 2}, ${size / 2}`}
|
|
/>
|
|
</Svg>
|
|
<View style={[StyleSheet.absoluteFillObject, { justifyContent: 'center', alignItems: 'center' }]}>
|
|
<Text style={{ fontSize: size * 0.25, fontWeight: 'bold', color: theme.colors.gray900 }}>
|
|
{Math.round(progress)}%
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|