about summary refs log tree commit diff
path: root/src/components/dms/NewMessagesPill.tsx
blob: 924f7c45581d626d6d0c308b3bf6aab60aeab91d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import React from 'react'
import {Pressable, View} from 'react-native'
import Animated, {
  runOnJS,
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {Trans} from '@lingui/macro'

import {
  ScaleAndFadeIn,
  ScaleAndFadeOut,
} from 'lib/custom-animations/ScaleAndFade'
import {useHaptics} from 'lib/haptics'
import {isAndroid, isIOS, isWeb} from 'platform/detection'
import {atoms as a, useTheme} from '#/alf'
import {Text} from '#/components/Typography'

const AnimatedPressable = Animated.createAnimatedComponent(Pressable)

export function NewMessagesPill({
  onPress: onPressInner,
}: {
  onPress: () => void
}) {
  const t = useTheme()
  const playHaptic = useHaptics()
  const {bottom: bottomInset} = useSafeAreaInsets()
  const bottomBarHeight = isIOS ? 42 : isAndroid ? 60 : 0
  const bottomOffset = isWeb ? 0 : bottomInset + bottomBarHeight

  const scale = useSharedValue(1)

  const onPressIn = React.useCallback(() => {
    if (isWeb) return
    scale.value = withTiming(1.075, {duration: 100})
  }, [scale])

  const onPressOut = React.useCallback(() => {
    if (isWeb) return
    scale.value = withTiming(1, {duration: 100})
  }, [scale])

  const onPress = React.useCallback(() => {
    runOnJS(playHaptic)()
    onPressInner?.()
  }, [onPressInner, playHaptic])

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{scale: scale.value}],
  }))

  return (
    <View
      style={[
        a.absolute,
        a.w_full,
        a.z_10,
        a.align_center,
        {
          bottom: bottomOffset + 70,
          // Don't prevent scrolling in this area _except_ for in the pill itself
          pointerEvents: 'box-none',
        },
      ]}>
      <AnimatedPressable
        style={[
          a.py_sm,
          a.rounded_full,
          a.shadow_sm,
          a.border,
          t.atoms.bg_contrast_50,
          t.atoms.border_contrast_medium,
          {
            width: 160,
            alignItems: 'center',
            shadowOpacity: 0.125,
            shadowRadius: 12,
            shadowOffset: {width: 0, height: 5},
            pointerEvents: 'box-only',
          },
          animatedStyle,
        ]}
        entering={ScaleAndFadeIn}
        exiting={ScaleAndFadeOut}
        onPress={onPress}
        onPressIn={onPressIn}
        onPressOut={onPressOut}>
        <Text style={[a.font_bold]}>
          <Trans>New messages</Trans>
        </Text>
      </AnimatedPressable>
    </View>
  )
}