Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

invert the fab animation, play a haptic (#4309)

authored by

Hailey and committed by
GitHub
b77031a0 0f36ffdc

+44 -16
+14 -10
src/lib/haptics.ts
··· 4 4 import {isIOS, isWeb} from 'platform/detection' 5 5 import {useHapticsDisabled} from 'state/preferences/disable-haptics' 6 6 7 - const hapticImpact: ImpactFeedbackStyle = isIOS 8 - ? ImpactFeedbackStyle.Medium 9 - : ImpactFeedbackStyle.Light // Users said the medium impact was too strong on Android; see APP-537s 10 - 11 7 export function useHaptics() { 12 8 const isHapticsDisabled = useHapticsDisabled() 13 9 14 - return React.useCallback(() => { 15 - if (isHapticsDisabled || isWeb) { 16 - return 17 - } 18 - impactAsync(hapticImpact) 19 - }, [isHapticsDisabled]) 10 + return React.useCallback( 11 + (strength: 'Light' | 'Medium' | 'Heavy' = 'Medium') => { 12 + if (isHapticsDisabled || isWeb) { 13 + return 14 + } 15 + 16 + // Users said the medium impact was too strong on Android; see APP-537s 17 + const style = isIOS 18 + ? ImpactFeedbackStyle[strength] 19 + : ImpactFeedbackStyle.Light 20 + impactAsync(style) 21 + }, 22 + [isHapticsDisabled], 23 + ) 20 24 }
+30 -6
src/view/com/util/fab/FABInner.tsx
··· 1 1 import React, {ComponentProps} from 'react' 2 2 import {StyleSheet, TouchableWithoutFeedback} from 'react-native' 3 - import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated' 3 + import Animated, { 4 + Easing, 5 + useAnimatedStyle, 6 + withTiming, 7 + } from 'react-native-reanimated' 4 8 import {useSafeAreaInsets} from 'react-native-safe-area-context' 5 9 import {LinearGradient} from 'expo-linear-gradient' 6 10 ··· 9 13 import {clamp} from '#/lib/numbers' 10 14 import {gradients} from '#/lib/styles' 11 15 import {isWeb} from '#/platform/detection' 16 + import {useHaptics} from 'lib/haptics' 17 + import {useHapticsDisabled} from 'state/preferences' 12 18 import {useInteractionState} from '#/components/hooks/useInteractionState' 13 19 14 20 export interface FABProps ··· 17 23 icon: JSX.Element 18 24 } 19 25 20 - export function FABInner({testID, icon, ...props}: FABProps) { 26 + export function FABInner({testID, icon, onPress, ...props}: FABProps) { 21 27 const insets = useSafeAreaInsets() 22 28 const {isMobile, isTablet} = useWebMediaQueries() 23 29 const fabMinimalShellTransform = useMinimalShellFabTransform() 24 30 const { 25 - state: pressed, 31 + state: isPressed, 26 32 onIn: onPressIn, 27 33 onOut: onPressOut, 28 34 } = useInteractionState() 35 + const playHaptic = useHaptics() 36 + const isHapticsDisabled = useHapticsDisabled() 29 37 30 38 const size = isTablet ? styles.sizeLarge : styles.sizeRegular 31 39 ··· 33 41 ? {right: 50, bottom: 50} 34 42 : {right: 24, bottom: clamp(insets.bottom, 15, 60) + 15} 35 43 36 - const scale = useAnimatedStyle(() => ({ 37 - transform: [{scale: withTiming(pressed ? 0.95 : 1)}], 44 + const animatedStyle = useAnimatedStyle(() => ({ 45 + transform: [ 46 + { 47 + scale: withTiming(isPressed ? 1.1 : 1, { 48 + duration: 250, 49 + easing: Easing.out(Easing.quad), 50 + }), 51 + }, 52 + ], 38 53 })) 39 54 40 55 return ( 41 56 <TouchableWithoutFeedback 42 57 testID={testID} 58 + onPress={e => { 59 + playHaptic() 60 + setTimeout( 61 + () => { 62 + onPress?.(e) 63 + }, 64 + isHapticsDisabled ? 0 : 75, 65 + ) 66 + }} 43 67 onPressIn={onPressIn} 44 68 onPressOut={onPressOut} 45 69 {...props}> ··· 50 74 tabletSpacing, 51 75 isMobile && fabMinimalShellTransform, 52 76 ]}> 53 - <Animated.View style={scale}> 77 + <Animated.View style={animatedStyle}> 54 78 <LinearGradient 55 79 colors={[gradients.blueLight.start, gradients.blueLight.end]} 56 80 start={{x: 0, y: 0}}