Skip to content

Commit c4785ef

Browse files
New ContextMenu menu type for DM messages (#8014)
* get context menu somewhat working ish * take screenshot rather than double rendering * get animations somewhat working * get transform animation working * rm log * upwards safe area * get working on android * get android working once and for all * fix positioning on both platforms * use dark blur on ios always, fix dark mode * allow closing with hardware back press * try and fix type error * add note about ts-ignore * round post * add image capture error handling * extract magic numbers * set explicit embed width, rm top margin * Message embed width tweaks * Format * fix position of embeds * same as above for web --------- Co-authored-by: Eric Bailey <[email protected]>
1 parent f6f253b commit c4785ef

15 files changed

+1091
-296
lines changed

src/App.native.tsx

Lines changed: 52 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ import * as Toast from '#/view/com/util/Toast'
6666
import {Shell} from '#/view/shell'
6767
import {ThemeProvider as Alf} from '#/alf'
6868
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
69+
import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
6970
import {NuxDialogs} from '#/components/dialogs/nuxs'
7071
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
7172
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
@@ -128,55 +129,57 @@ function InnerApp() {
128129
return (
129130
<Alf theme={theme}>
130131
<ThemeProvider theme={theme}>
131-
<Splash isReady={isReady && hasCheckedReferrer}>
132-
<RootSiblingParent>
133-
<VideoVolumeProvider>
134-
<React.Fragment
135-
// Resets the entire tree below when it changes:
136-
key={currentAccount?.did}>
137-
<QueryProvider currentDid={currentAccount?.did}>
138-
<ComposerProvider>
139-
<StatsigProvider>
140-
<MessagesProvider>
141-
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
142-
<LabelDefsProvider>
143-
<ModerationOptsProvider>
144-
<LoggedOutViewProvider>
145-
<SelectedFeedProvider>
146-
<HiddenRepliesProvider>
147-
<HomeBadgeProvider>
148-
<UnreadNotifsProvider>
149-
<BackgroundNotificationPreferencesProvider>
150-
<MutedThreadsProvider>
151-
<ProgressGuideProvider>
152-
<TrendingConfigProvider>
153-
<GestureHandlerRootView
154-
style={s.h100pct}>
155-
<IntentDialogProvider>
156-
<TestCtrls />
157-
<Shell />
158-
<NuxDialogs />
159-
</IntentDialogProvider>
160-
</GestureHandlerRootView>
161-
</TrendingConfigProvider>
162-
</ProgressGuideProvider>
163-
</MutedThreadsProvider>
164-
</BackgroundNotificationPreferencesProvider>
165-
</UnreadNotifsProvider>
166-
</HomeBadgeProvider>
167-
</HiddenRepliesProvider>
168-
</SelectedFeedProvider>
169-
</LoggedOutViewProvider>
170-
</ModerationOptsProvider>
171-
</LabelDefsProvider>
172-
</MessagesProvider>
173-
</StatsigProvider>
174-
</ComposerProvider>
175-
</QueryProvider>
176-
</React.Fragment>
177-
</VideoVolumeProvider>
178-
</RootSiblingParent>
179-
</Splash>
132+
<ContextMenuProvider>
133+
<Splash isReady={isReady && hasCheckedReferrer}>
134+
<RootSiblingParent>
135+
<VideoVolumeProvider>
136+
<React.Fragment
137+
// Resets the entire tree below when it changes:
138+
key={currentAccount?.did}>
139+
<QueryProvider currentDid={currentAccount?.did}>
140+
<ComposerProvider>
141+
<StatsigProvider>
142+
<MessagesProvider>
143+
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
144+
<LabelDefsProvider>
145+
<ModerationOptsProvider>
146+
<LoggedOutViewProvider>
147+
<SelectedFeedProvider>
148+
<HiddenRepliesProvider>
149+
<HomeBadgeProvider>
150+
<UnreadNotifsProvider>
151+
<BackgroundNotificationPreferencesProvider>
152+
<MutedThreadsProvider>
153+
<ProgressGuideProvider>
154+
<TrendingConfigProvider>
155+
<GestureHandlerRootView
156+
style={s.h100pct}>
157+
<IntentDialogProvider>
158+
<TestCtrls />
159+
<Shell />
160+
<NuxDialogs />
161+
</IntentDialogProvider>
162+
</GestureHandlerRootView>
163+
</TrendingConfigProvider>
164+
</ProgressGuideProvider>
165+
</MutedThreadsProvider>
166+
</BackgroundNotificationPreferencesProvider>
167+
</UnreadNotifsProvider>
168+
</HomeBadgeProvider>
169+
</HiddenRepliesProvider>
170+
</SelectedFeedProvider>
171+
</LoggedOutViewProvider>
172+
</ModerationOptsProvider>
173+
</LabelDefsProvider>
174+
</MessagesProvider>
175+
</StatsigProvider>
176+
</ComposerProvider>
177+
</QueryProvider>
178+
</React.Fragment>
179+
</VideoVolumeProvider>
180+
</RootSiblingParent>
181+
</Splash>
182+
</ContextMenuProvider>
180183
</ThemeProvider>
181184
</Alf>
182185
)

src/App.web.tsx

Lines changed: 51 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import {ToastContainer} from '#/view/com/util/Toast.web'
5656
import {Shell} from '#/view/shell/index'
5757
import {ThemeProvider as Alf} from '#/alf'
5858
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
59+
import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
5960
import {NuxDialogs} from '#/components/dialogs/nuxs'
6061
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
6162
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
@@ -107,54 +108,56 @@ function InnerApp() {
107108
return (
108109
<Alf theme={theme}>
109110
<ThemeProvider theme={theme}>
110-
<RootSiblingParent>
111-
<VideoVolumeProvider>
112-
<ActiveVideoProvider>
113-
<React.Fragment
114-
// Resets the entire tree below when it changes:
115-
key={currentAccount?.did}>
116-
<QueryProvider currentDid={currentAccount?.did}>
117-
<ComposerProvider>
118-
<StatsigProvider>
119-
<MessagesProvider>
120-
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
121-
<LabelDefsProvider>
122-
<ModerationOptsProvider>
123-
<LoggedOutViewProvider>
124-
<SelectedFeedProvider>
125-
<HiddenRepliesProvider>
126-
<HomeBadgeProvider>
127-
<UnreadNotifsProvider>
128-
<BackgroundNotificationPreferencesProvider>
129-
<MutedThreadsProvider>
130-
<SafeAreaProvider>
131-
<ProgressGuideProvider>
132-
<TrendingConfigProvider>
133-
<IntentDialogProvider>
134-
<Shell />
135-
<NuxDialogs />
136-
</IntentDialogProvider>
137-
</TrendingConfigProvider>
138-
</ProgressGuideProvider>
139-
</SafeAreaProvider>
140-
</MutedThreadsProvider>
141-
</BackgroundNotificationPreferencesProvider>
142-
</UnreadNotifsProvider>
143-
</HomeBadgeProvider>
144-
</HiddenRepliesProvider>
145-
</SelectedFeedProvider>
146-
</LoggedOutViewProvider>
147-
</ModerationOptsProvider>
148-
</LabelDefsProvider>
149-
</MessagesProvider>
150-
</StatsigProvider>
151-
</ComposerProvider>
152-
</QueryProvider>
153-
<ToastContainer />
154-
</React.Fragment>
155-
</ActiveVideoProvider>
156-
</VideoVolumeProvider>
157-
</RootSiblingParent>
111+
<ContextMenuProvider>
112+
<RootSiblingParent>
113+
<VideoVolumeProvider>
114+
<ActiveVideoProvider>
115+
<React.Fragment
116+
// Resets the entire tree below when it changes:
117+
key={currentAccount?.did}>
118+
<QueryProvider currentDid={currentAccount?.did}>
119+
<ComposerProvider>
120+
<StatsigProvider>
121+
<MessagesProvider>
122+
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
123+
<LabelDefsProvider>
124+
<ModerationOptsProvider>
125+
<LoggedOutViewProvider>
126+
<SelectedFeedProvider>
127+
<HiddenRepliesProvider>
128+
<HomeBadgeProvider>
129+
<UnreadNotifsProvider>
130+
<BackgroundNotificationPreferencesProvider>
131+
<MutedThreadsProvider>
132+
<SafeAreaProvider>
133+
<ProgressGuideProvider>
134+
<TrendingConfigProvider>
135+
<IntentDialogProvider>
136+
<Shell />
137+
<NuxDialogs />
138+
</IntentDialogProvider>
139+
</TrendingConfigProvider>
140+
</ProgressGuideProvider>
141+
</SafeAreaProvider>
142+
</MutedThreadsProvider>
143+
</BackgroundNotificationPreferencesProvider>
144+
</UnreadNotifsProvider>
145+
</HomeBadgeProvider>
146+
</HiddenRepliesProvider>
147+
</SelectedFeedProvider>
148+
</LoggedOutViewProvider>
149+
</ModerationOptsProvider>
150+
</LabelDefsProvider>
151+
</MessagesProvider>
152+
</StatsigProvider>
153+
</ComposerProvider>
154+
</QueryProvider>
155+
<ToastContainer />
156+
</React.Fragment>
157+
</ActiveVideoProvider>
158+
</VideoVolumeProvider>
159+
</RootSiblingParent>
160+
</ContextMenuProvider>
158161
</ThemeProvider>
159162
</Alf>
160163
)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {Pressable} from 'react-native'
2+
import Animated, {
3+
Extrapolation,
4+
interpolate,
5+
SharedValue,
6+
useAnimatedProps,
7+
} from 'react-native-reanimated'
8+
import {BlurView} from 'expo-blur'
9+
import {msg} from '@lingui/macro'
10+
import {useLingui} from '@lingui/react'
11+
12+
import {atoms as a} from '#/alf'
13+
14+
const AnimatedBlurView = Animated.createAnimatedComponent(BlurView)
15+
16+
export function Backdrop({
17+
animation,
18+
intensity = 50,
19+
onPress,
20+
}: {
21+
animation: SharedValue<number>
22+
intensity?: number
23+
onPress?: () => void
24+
}) {
25+
const {_} = useLingui()
26+
27+
const animatedProps = useAnimatedProps(() => ({
28+
intensity: interpolate(
29+
animation.get(),
30+
[0, 1],
31+
[0, intensity],
32+
Extrapolation.CLAMP,
33+
),
34+
}))
35+
36+
return (
37+
<AnimatedBlurView
38+
animatedProps={animatedProps}
39+
style={[a.absolute, a.inset_0]}
40+
tint="systemThinMaterialDark">
41+
<Pressable
42+
style={a.flex_1}
43+
accessibilityLabel={_(msg`Close menu`)}
44+
accessibilityHint={_(msg`Tap to close context menu`)}
45+
onPress={onPress}
46+
/>
47+
</AnimatedBlurView>
48+
)
49+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import {Pressable} from 'react-native'
2+
import Animated, {
3+
Extrapolation,
4+
interpolate,
5+
SharedValue,
6+
useAnimatedStyle,
7+
} from 'react-native-reanimated'
8+
import {msg} from '@lingui/macro'
9+
import {useLingui} from '@lingui/react'
10+
11+
import {atoms as a, useTheme} from '#/alf'
12+
13+
export function Backdrop({
14+
animation,
15+
intensity = 50,
16+
onPress,
17+
}: {
18+
animation: SharedValue<number>
19+
intensity?: number
20+
onPress?: () => void
21+
}) {
22+
const t = useTheme()
23+
const {_} = useLingui()
24+
25+
const animatedStyle = useAnimatedStyle(() => ({
26+
opacity: interpolate(
27+
animation.get(),
28+
[0, 1],
29+
[0, intensity / 100],
30+
Extrapolation.CLAMP,
31+
),
32+
}))
33+
34+
return (
35+
<Animated.View
36+
style={[a.absolute, a.inset_0, t.atoms.bg_contrast_975, animatedStyle]}>
37+
<Pressable
38+
style={a.flex_1}
39+
accessibilityLabel={_(msg`Close menu`)}
40+
accessibilityHint={_(msg`Tap to close context menu`)}
41+
onPress={onPress}
42+
/>
43+
</Animated.View>
44+
)
45+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react'
2+
3+
import type {ContextType, ItemContextType} from '#/components/ContextMenu/types'
4+
5+
export const Context = React.createContext<ContextType | null>(null)
6+
7+
export const ItemContext = React.createContext<ItemContextType | null>(null)
8+
9+
export function useContextMenuContext() {
10+
const context = React.useContext(Context)
11+
12+
if (!context) {
13+
throw new Error(
14+
'useContextMenuContext must be used within a Context.Provider',
15+
)
16+
}
17+
18+
return context
19+
}
20+
21+
export function useContextMenuItemContext() {
22+
const context = React.useContext(ItemContext)
23+
24+
if (!context) {
25+
throw new Error(
26+
'useContextMenuItemContext must be used within a Context.Provider',
27+
)
28+
}
29+
30+
return context
31+
}

0 commit comments

Comments
 (0)