import get from 'lodash.get';
import React from 'react';
import { Animated, Easing, StyleSheet } from 'react-native';
import { makeStyledComponent } from '../../../utils/styled';
import { useTheme, useThemeProps } from '../../../hooks';
import { canUseDom } from '../../../utils';
import { default as Box } from '../../primitives/Box';
import type { ICircularProgressProps } from './types';
import { themeTools } from '../../../theme';
const StyleAnimatedView = makeStyledComponent(Animated.View);
const CircularProgress = (
{ value, isIndeterminate, max, min, ...props }: ICircularProgressProps,
ref: any
) => {
const theme = useTheme();
const isDomUsable = canUseDom();
if (min) {
value = value - min;
}
let sizeProps;
let newProps = useThemeProps('CircularProgress', props);
let [, remainingProps] = themeTools.extractInObject(props, ['size']); // removing size from props so that Box don't accept size passed for CircularProgress
if (!newProps.size) {
sizeProps = {
height: newProps.height,
width: newProps.width,
};
} else {
sizeProps = { height: newProps.size, width: newProps.size };
}
// fetching size from theme for passing into style prop
const themeHeight = get(theme, 'space.' + sizeProps.height);
const themeWidth = get(theme, 'space.' + sizeProps.width);
const styleSize = {
height: themeHeight
? parseInt(themeHeight.slice(themeHeight.Length, -2), 10)
: sizeProps.height,
width: themeWidth
? parseInt(themeWidth.slice(themeWidth.Length, -2), 10)
: sizeProps.width,
};
const defaultThickness = newProps.thickness;
const degree: any = new Animated.Value(0);
if (isIndeterminate) {
if (isDomUsable) {
Animated.loop(
Animated.timing(degree, {
toValue: 1,
duration: 600,
easing: Easing.linear,
useNativeDriver: false,
})
).start();
}
}
const [viewHeight, setViewHeight] = React.useState(0);
const layout = (e: any) => {
let height = e.nativeEvent.layout.height;
setViewHeight(height);
};
const defaultStyling: any = {
borderBottomLeftRadius: viewHeight / 2,
borderBottomRightRadius: viewHeight / 2,
borderTopLeftRadius: viewHeight / 2,
borderTopRightRadius: viewHeight / 2,
borderLeftWidth: defaultThickness,
borderBottomWidth: defaultThickness,
position: 'absolute',
borderLeftColor: 'transparent',
borderBottomColor: 'transparent',
...styleSize,
};
const styles = StyleSheet.create({
firstProgressLayer: {
borderTopWidth: defaultThickness,
borderRightWidth: defaultThickness,
...defaultStyling,
transform: [{ rotateZ: '-135deg' }],
},
secondProgressLayer: {
borderTopWidth: defaultThickness,
borderRightWidth: defaultThickness,
...defaultStyling,
transform: [{ rotateZ: '45deg' }],
},
offsetLayer: {
borderTopWidth: defaultThickness,
borderRightWidth: defaultThickness,
...defaultStyling,
borderRadius: viewHeight / 2,
transform: [{ rotateZ: '-135deg' }],
},
animateStyle: {
borderTopWidth: defaultThickness,
borderRightWidth: defaultThickness,
...defaultStyling,
transform: [
{
rotateZ: degree.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
}),
},
],
},
});
let halfSide = (max ? (min ? max - min : max) : 100) / 2; // calculating the halfvalue of the progress according to min and max
const propStyle = (percent: number, base_degrees: number) => {
const rotateBy = base_degrees + (percent * 180) / halfSide;
return {
transform: [{ rotateZ: rotateBy + 'deg' }],
};
};
const renderThirdLayer = (percent: number) => {
if (percent > halfSide) {
return (
);
} else {
return (
);
}
};
let firstProgressLayerStyle;
if (value > halfSide) {
firstProgressLayerStyle = propStyle(halfSide, -135);
} else {
firstProgressLayerStyle = propStyle(value, -135);
}
return (
{!isIndeterminate ? (
<>
{renderThirdLayer(value)}
{remainingProps.children}
>
) : (
)}
);
};
export default React.memo(React.forwardRef(CircularProgress));