Skip to content

Commit

Permalink
refactor(rn-com): refactor rn switch component
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Jan 20, 2025
1 parent 203c253 commit aa5d5f5
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 80 deletions.
2 changes: 2 additions & 0 deletions apps/mobile/src/components/common/ThemedBlurView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { forwardRef } from "react"

export const ThemedBlurView = forwardRef<BlurView, BlurViewProps>(({ tint, ...rest }, ref) => {
const { colorScheme } = useColorScheme()

return (
<BlurView
ref={ref}
intensity={100}
tint={colorScheme === "light" ? "systemChromeMaterialLight" : "systemChromeMaterialDark"}
{...rest}
/>
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/components/ui/form/Switch.tsx
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
3 changes: 1 addition & 2 deletions apps/mobile/src/components/ui/grouped/GroupedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
129 changes: 53 additions & 76 deletions apps/mobile/src/components/ui/switch/Switch.tsx
Original file line number Diff line number Diff line change
@@ -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"

Expand All @@ -27,83 +34,62 @@ export type SwitchRef = {
}
export const Switch = forwardRef<SwitchRef, SwitchProps>(
({ 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 (
<View style={styles.container}>
<Pressable
Expand All @@ -115,21 +101,12 @@ export const Switch = forwardRef<SwitchRef, SwitchProps>(
}}
>
<Animated.View
style={[
size === "sm" ? styles.toggleContainerSm : styles.toggleContainer,
{
backgroundColor: bgColor,
},
]}
style={[size === "sm" ? styles.toggleContainerSm : styles.toggleContainer, toggleStyle]}
>
<Animated.View
style={[
size === "sm" ? styles.toggleWheelStyleSm : styles.toggleWheelStyle,
{
marginLeft: moveToggle,
width: circleWidth,
transform: [{ translateX }, { translateY: -0.4 }],
},
circleStyle,
]}
/>
</Animated.View>
Expand Down
1 change: 0 additions & 1 deletion apps/mobile/src/screens/(stack)/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -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"
Expand Down

0 comments on commit aa5d5f5

Please sign in to comment.