diff --git a/apps/mobile/src/components/common/ThemedBlurView.tsx b/apps/mobile/src/components/common/ThemedBlurView.tsx index 7da5c91b0..f917ab97b 100644 --- a/apps/mobile/src/components/common/ThemedBlurView.tsx +++ b/apps/mobile/src/components/common/ThemedBlurView.tsx @@ -5,9 +5,11 @@ import { forwardRef } from "react" export const ThemedBlurView = forwardRef(({ tint, ...rest }, ref) => { const { colorScheme } = useColorScheme() + return ( diff --git a/apps/mobile/src/components/ui/form/Switch.tsx b/apps/mobile/src/components/ui/form/Switch.tsx index b724ed52c..20fa0a280 100644 --- a/apps/mobile/src/components/ui/form/Switch.tsx +++ b/apps/mobile/src/components/ui/form/Switch.tsx @@ -1,5 +1,5 @@ import { forwardRef } from "react" -import type { StyleProp, Switch as NativeSwitch, ViewStyle } from "react-native" +import type { StyleProp, ViewStyle } from "react-native" import { Text, View } from "react-native" import type { SwitchProps, SwitchRef } from "../switch/Switch" diff --git a/apps/mobile/src/components/ui/grouped/GroupedList.tsx b/apps/mobile/src/components/ui/grouped/GroupedList.tsx index 631417b10..69c8a4bad 100644 --- a/apps/mobile/src/components/ui/grouped/GroupedList.tsx +++ b/apps/mobile/src/components/ui/grouped/GroupedList.tsx @@ -3,9 +3,8 @@ import type { FC, PropsWithChildren } from "react" import * as React from "react" import { Fragment } from "react" import type { ViewProps } from "react-native" -import { Pressable, StyleSheet, Switch, Text, View } from "react-native" +import { Pressable, StyleSheet, Text, View } from "react-native" -import { setGeneralSetting } from "@/src/atoms/settings/general" import { RightCuteReIcon } from "@/src/icons/right_cute_re" import { useColor } from "@/src/theme/colors" diff --git a/apps/mobile/src/components/ui/switch/Switch.tsx b/apps/mobile/src/components/ui/switch/Switch.tsx index 0348dc0d2..fe22f8373 100644 --- a/apps/mobile/src/components/ui/switch/Switch.tsx +++ b/apps/mobile/src/components/ui/switch/Switch.tsx @@ -1,7 +1,14 @@ -import type { useState } from "react" -import { forwardRef, useEffect, useImperativeHandle, useMemo } from "react" +import { forwardRef, useEffect, useImperativeHandle } from "react" import type { SwitchChangeEvent } from "react-native" -import { Animated, Easing, Pressable, StyleSheet, useAnimatedValue, View } from "react-native" +import { Pressable, StyleSheet, View } from "react-native" +import Animated, { + interpolate, + interpolateColor, + useAnimatedStyle, + useSharedValue, + withSpring, + withTiming, +} from "react-native-reanimated" import { accentColor, useColor } from "@/src/theme/colors" @@ -27,83 +34,62 @@ export type SwitchRef = { } export const Switch = forwardRef( ({ value, onValueChange, onChange, size = "default" }, ref) => { - const animatedValue = useAnimatedValue(0) - const circleWidthAnimatedValue = useAnimatedValue(0) - const translateX = useAnimatedValue(0) - const colorAnimatedValue = useAnimatedValue(0) - - useEffect(() => { - Animated.timing(animatedValue, { - toValue: value ? 1 : 0, - duration: 110, - easing: Easing.linear, - useNativeDriver: false, - }).start() - - Animated.timing(colorAnimatedValue, { - toValue: value ? 1 : 0, - duration: 300, - easing: Easing.linear, - useNativeDriver: false, - }).start() - }, [value]) + const progress = useSharedValue(value ? 1 : 0) + const scale = useSharedValue(1) + const translateX = useSharedValue(0) const onTouchStart = () => { - Animated.timing(circleWidthAnimatedValue, { - toValue: 1, - duration: 200, - useNativeDriver: false, - }).start() - if (value) - Animated.timing(translateX, { - toValue: size === "sm" ? -4 : -7, - duration: 200, - useNativeDriver: false, - }).start() + scale.value = withSpring(1.1) + if (value) { + translateX.value = withSpring(size === "sm" ? -4 : -7) + } } const onTouchEnd = () => { - Animated.timing(circleWidthAnimatedValue, { - toValue: 0, - duration: 100, - useNativeDriver: false, - }).start() - Animated.timing(translateX, { - toValue: 0, - duration: 100, - useNativeDriver: false, - }).start() + scale.value = withSpring(1) + translateX.value = withSpring(0) } - const moveToggle = useMemo( - () => - animatedValue.interpolate({ - inputRange: [0, 1], - outputRange: size === "sm" ? [2, 20] : [2.3, 22], - }), - [animatedValue, size], - ) - - const circleWidth = useMemo( - () => - circleWidthAnimatedValue.interpolate({ - inputRange: [0, 1], - outputRange: size === "sm" ? [18, 21] : [27.8, 35], - }), - [circleWidthAnimatedValue, size], - ) - useImperativeHandle(ref, () => ({ value: !!value, })) const activeBgColor = accentColor const inactiveBgColor = useColor("secondarySystemFill") - const bgColor = colorAnimatedValue.interpolate({ - inputRange: [0, 1], - outputRange: [inactiveBgColor, activeBgColor], + + const toggleStyle = useAnimatedStyle(() => { + const backgroundColor = interpolateColor( + progress.value, + [0, 1], + [inactiveBgColor, activeBgColor], + ) + + return { + backgroundColor, + } }) + const circleStyle = useAnimatedStyle(() => { + const marginLeft = interpolate(progress.value, [0, 1], size === "sm" ? [2, 20] : [2.3, 22]) + + const width = interpolate(scale.value, [1, 1.1], size === "sm" ? [18, 21] : [27.8, 35]) + + return { + marginLeft, + width, + transform: [{ translateX: translateX.value }, { translateY: -0.4 }, { scale: scale.value }], + } + }) + + useEffect(() => { + // Update progress when value changes + if (value && progress.value === 0) { + progress.value = withTiming(1) + } else if (!value && progress.value === 1) { + progress.value = withTiming(0) + } + }, [progress, value]) + return ( ( }} > diff --git a/apps/mobile/src/screens/(stack)/(tabs)/_layout.tsx b/apps/mobile/src/screens/(stack)/(tabs)/_layout.tsx index 34ddf9c3a..c1eb69681 100644 --- a/apps/mobile/src/screens/(stack)/(tabs)/_layout.tsx +++ b/apps/mobile/src/screens/(stack)/(tabs)/_layout.tsx @@ -1,5 +1,4 @@ import { FeedViewType } from "@follow/constants" -import { transformUriPath } from "@follow/utils" import { PlatformPressable } from "@react-navigation/elements/src/PlatformPressable" import { router, Tabs } from "expo-router" import { useContext, useEffect, useMemo, useState } from "react"