diff --git a/app/(Minitool_one)/chart_components/BatteryBar.jsx b/app/(Minitool_one)/chart_components/BatteryBar.jsx new file mode 100644 index 0000000..823936c --- /dev/null +++ b/app/(Minitool_one)/chart_components/BatteryBar.jsx @@ -0,0 +1,78 @@ +import React, { useState } from "react"; +import { Rect, Circle, G } from "react-native-svg"; +import Animated, { + useAnimatedReaction, + runOnJS, +} from "react-native-reanimated"; + +const AnimatedRect = Animated.createAnimatedComponent(Rect); +const BAR_HEIGHT = 8; +const DOT_COLOR = "#000"; +const RANGE_HIGHLIGHT_COLOR = "#ff0000"; +const TOUGH_CELL_COLOR = "#33cc33"; +const ALWAYS_READY_COLOR = "#cc00ff"; +const MAX_LIFESPAN = 140; +const BAR_SPACING = 7; + +const BatteryBar = ({ + item, + index, + chartWidth, + rangeStartX, + rangeEndX, + tool, + dotsOnly, + maxLifespan = 140, +}) => { + const yPos = index * (BAR_HEIGHT + BAR_SPACING); + const originalColor = + item.brand === "Tough Cell" ? TOUGH_CELL_COLOR : ALWAYS_READY_COLOR; + const [barColor, setBarColor] = useState(originalColor); + const barEndPosition = (item.lifespan / maxLifespan) * chartWidth; + + useAnimatedReaction( + () => ({ + isToolActive: tool, + start: rangeStartX.value, + end: rangeEndX.value, + }), + (currentRange) => { + "worklet"; + if (currentRange.isToolActive) { + if ( + barEndPosition >= currentRange.start && + barEndPosition <= currentRange.end + ) { + runOnJS(setBarColor)(RANGE_HIGHLIGHT_COLOR); + } else { + runOnJS(setBarColor)(originalColor); + } + } else { + runOnJS(setBarColor)(originalColor); + } + }, + [barEndPosition, originalColor, tool] + ); + + return ( + + {!dotsOnly && ( + + )} + + + ); +}; + +export default BatteryBar; diff --git a/app/(Minitool_one)/controls/ChartControls.jsx b/app/(Minitool_one)/controls/ChartControls.jsx new file mode 100644 index 0000000..8c3d1a8 --- /dev/null +++ b/app/(Minitool_one)/controls/ChartControls.jsx @@ -0,0 +1,152 @@ +import React, { useState, useCallback } from "react"; +import { View, Text, Switch, Button, StyleSheet } from "react-native"; + +/** + * ChartControls Hook + * Encapsulates all chart control logic including sorting, filtering, and tool toggles + * Returns state setters and a renderControls() function for rendering + */ +const useChartControls = () => { + // --- Control state --- + const [isSortedBySize, setIsSortedBySize] = useState(false); + const [isSortedByColor, setIsSortedByColor] = useState(false); + const [hideGreenBars, setHideGreenBars] = useState(false); + const [hidePurpleBars, setHidePurpleBars] = useState(false); + const [showDotsOnly, setShowDotsOnly] = useState(false); + const [valueToolActive, setValueToolActive] = useState(false); + const [rangeToolActive, setRangeToolActive] = useState(false); + + // --- Handler functions --- + const handleSortBySize = useCallback((isActive) => { + setIsSortedBySize(isActive); + // When sorting by size, turn off color sort + if (isActive) { + setIsSortedByColor(false); + } + }, []); + + const handleSortByColor = useCallback((isActive) => { + setIsSortedByColor(isActive); + // When sorting by color, turn off size sort + if (isActive) { + setIsSortedBySize(false); + } + }, []); + + const handleValueTool = useCallback((isActive) => { + setValueToolActive(isActive); + }, []); + + const handleRangeTool = useCallback((isActive) => { + setRangeToolActive(isActive); + }, []); + + const handleHideGreenBars = useCallback((isActive) => { + setHideGreenBars(isActive); + }, []); + + const handleHidePurpleBars = useCallback((isActive) => { + setHidePurpleBars(isActive); + }, []); + + const handleShowDotsOnly = useCallback((isActive) => { + setShowDotsOnly(isActive); + }, []); + + // --- Render component with all controls --- + const renderControls = useCallback( + () => ( + + {/* --- Tool toggles --- */} + + Value tool + + Range tool + + + + {/* --- Visibility filters --- */} + + Hide Green Bars + + Hide Purple Bars + + Show Dots Only + + + + {/* --- Sorting controllers --- */} + +