fix(app): replace tab opacity=0 flash with proper slide+fade cross-fade

Use prevTab + Animated translateX/opacity driven by progress sharedValue.
Set opacity to 0 only inside a withTiming, never as initial value.
This commit is contained in:
fightrate-bot committed 2026-06-16 17:24:59 -03:00
1 parent e16d31318b
commit 2e527fbf5f
1 file changed
+31 -9
+31 -9
View File
@@ -18,6 +18,7 @@ import {
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import Animated, {
Easing,
runOnJS,
useAnimatedStyle,
useSharedValue,
withTiming,
@@ -49,17 +50,38 @@ export function FightRateApp() {
const insets = useSafeAreaInsets();
const monitor = useHeartRateMonitor();
const [activeTab, setActiveTab] = useState<TabKey>('capture');
const opacity = useSharedValue(1);
const [prevTab, setPrevTab] = useState<TabKey>('capture');
const progress = useSharedValue(1);
const direction = useSharedValue(1);
useEffect(() => {
opacity.value = 0;
opacity.value = withTiming(1, {
duration: motion.duration.fast,
easing: Easing.out(Easing.quad),
});
}, [activeTab, opacity]);
if (activeTab === prevTab) {
return;
}
const tabOrder: TabKey[] = ['capture', 'history', 'sensor', 'insights'];
direction.value =
tabOrder.indexOf(activeTab) > tabOrder.indexOf(prevTab) ? 1 : -1;
progress.value = 0;
progress.value = withTiming(
1,
{
duration: motion.duration.fast,
easing: Easing.out(Easing.quad),
},
(finished) => {
if (finished) {
runOnJS(setPrevTab)(activeTab);
}
},
);
}, [activeTab, prevTab, progress, direction]);
const fadeStyle = useAnimatedStyle(() => ({ opacity: opacity.value }));
const enterStyle = useAnimatedStyle(() => ({
opacity: progress.value,
transform: [
{ translateX: (1 - progress.value) * 24 * direction.value },
],
}));
const onCaptureAction = useCallback(async () => {
if (monitor.isCapturing) {
@@ -117,7 +139,7 @@ export function FightRateApp() {
</View>
</View>
<Animated.View style={fadeStyle} key={`tab-${activeTab}`}>
<Animated.View key={`tab-${prevTab}`} style={enterStyle}>
{activeTab === 'capture' ? (
<CaptureScreen
monitor={monitor}