[Sheets] [Pt. 10] (#5581)

Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
Hailey
2024-10-02 21:38:34 -07:00
committed by GitHub
parent c49182009a
commit 4466f68b81
29 changed files with 201 additions and 317 deletions
+3
View File
@@ -15,3 +15,6 @@ android
ios ios
src/locale/locales src/locale/locales
lib/react-compiler-runtime lib/react-compiler-runtime
bskyweb/static
coverage
web-build
+1
View File
@@ -255,6 +255,7 @@ func serve(cctx *cli.Context) error {
e.GET("/support/community-guidelines", server.WebGeneric) e.GET("/support/community-guidelines", server.WebGeneric)
e.GET("/support/copyright", server.WebGeneric) e.GET("/support/copyright", server.WebGeneric)
e.GET("/intent/compose", server.WebGeneric) e.GET("/intent/compose", server.WebGeneric)
e.GET("/intent/verify-email", server.WebGeneric)
e.GET("/messages", server.WebGeneric) e.GET("/messages", server.WebGeneric)
e.GET("/messages/:conversation", server.WebGeneric) e.GET("/messages/:conversation", server.WebGeneric)
+1 -1
View File
@@ -68,7 +68,7 @@
"@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-native-fontawesome": "^0.3.2", "@fortawesome/react-native-fontawesome": "^0.3.2",
"@haileyok/bluesky-bottom-sheet": "^0.1.1-alpha.9", "@haileyok/bluesky-bottom-sheet": "^0.1.1-alpha.11",
"@haileyok/bluesky-video": "0.1.10", "@haileyok/bluesky-video": "0.1.10",
"@lingui/react": "^4.5.0", "@lingui/react": "^4.5.0",
"@mattermost/react-native-paste-input": "^0.7.1", "@mattermost/react-native-paste-input": "^0.7.1",
+1 -1
View File
@@ -78,8 +78,8 @@ import {BottomBar} from '#/view/shell/bottom-bar/BottomBar'
import {createNativeStackNavigatorWithAuth} from '#/view/shell/createNativeStackNavigatorWithAuth' import {createNativeStackNavigatorWithAuth} from '#/view/shell/createNativeStackNavigatorWithAuth'
import {SharedPreferencesTesterScreen} from '#/screens/E2E/SharedPreferencesTesterScreen' import {SharedPreferencesTesterScreen} from '#/screens/E2E/SharedPreferencesTesterScreen'
import HashtagScreen from '#/screens/Hashtag' import HashtagScreen from '#/screens/Hashtag'
import {MessagesScreen} from '#/screens/Messages/ChatList'
import {MessagesConversationScreen} from '#/screens/Messages/Conversation' import {MessagesConversationScreen} from '#/screens/Messages/Conversation'
import {MessagesScreen} from '#/screens/Messages/List'
import {MessagesSettingsScreen} from '#/screens/Messages/Settings' import {MessagesSettingsScreen} from '#/screens/Messages/Settings'
import {ModerationScreen} from '#/screens/Moderation' import {ModerationScreen} from '#/screens/Moderation'
import {PostLikedByScreen} from '#/screens/Post/PostLikedBy' import {PostLikedByScreen} from '#/screens/Post/PostLikedBy'
+28
View File
@@ -901,4 +901,32 @@ export const atoms = {
hidden: { hidden: {
display: 'none', display: 'none',
}, },
/*
* Transition
*/
transition_none: web({
transitionProperty: 'none',
}),
transition_all: web({
transitionProperty: 'all',
transitionTimingFunction: 'cubic-bezier(0.17, 0.73, 0.14, 1)',
transitionDuration: '100ms',
}),
transition_color: web({
transitionProperty:
'color, background-color, border-color, text-decoration-color, fill, stroke',
transitionTimingFunction: 'cubic-bezier(0.17, 0.73, 0.14, 1)',
transitionDuration: '100ms',
}),
transition_opacity: web({
transitionProperty: 'opacity',
transitionTimingFunction: 'cubic-bezier(0.17, 0.73, 0.14, 1)',
transitionDuration: '100ms',
}),
transition_transform: web({
transitionProperty: 'transform',
transitionTimingFunction: 'cubic-bezier(0.17, 0.73, 0.14, 1)',
transitionDuration: '100ms',
}),
} as const } as const
+14
View File
@@ -1,3 +1,5 @@
import {useFonts} from 'expo-font'
import {isWeb} from '#/platform/detection' import {isWeb} from '#/platform/detection'
import {Device, device} from '#/storage' import {Device, device} from '#/storage'
@@ -63,3 +65,15 @@ export function applyFonts(
*/ */
style.fontVariant = ['no-contextual'] style.fontVariant = ['no-contextual']
} }
/*
* IMPORTANT: This is unused. Expo statically extracts these fonts.
*
* All used fonts MUST be configured here. Unused fonts can be commented out.
*/
export function DO_NOT_USE() {
return useFonts({
InterVariable: require('../../assets/fonts/inter/InterVariable.ttf'),
'InterVariable-Italic': require('../../assets/fonts/inter/InterVariable-Italic.ttf'),
})
}
-12
View File
@@ -1,12 +0,0 @@
import React from 'react'
import {Button, ButtonProps} from '#/components/Button'
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
export function BottomSheetButton({children, ...rest}: ButtonProps) {
return (
<Button {...rest} Component={NormalizedRNGHPressable}>
{children}
</Button>
)
}
+7 -7
View File
@@ -89,7 +89,7 @@ export type ButtonProps = Pick<
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
hoverStyle?: StyleProp<ViewStyle> hoverStyle?: StyleProp<ViewStyle>
children: NonTextElements | ((context: ButtonContext) => NonTextElements) children: NonTextElements | ((context: ButtonContext) => NonTextElements)
Component?: React.ComponentType<PressableProps> PressableComponent?: React.ComponentType<PressableProps>
} }
export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean} export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean}
@@ -117,7 +117,7 @@ export const Button = React.forwardRef<View, ButtonProps>(
disabled = false, disabled = false,
style, style,
hoverStyle: hoverStyleProp, hoverStyle: hoverStyleProp,
Component, PressableComponent,
...rest ...rest
}, },
ref, ref,
@@ -125,11 +125,11 @@ export const Button = React.forwardRef<View, ButtonProps>(
// This will pick the correct default pressable to use. If we are inside a dialog, we need to use the RNGH // This will pick the correct default pressable to use. If we are inside a dialog, we need to use the RNGH
// pressable so that it is usable inside the dialog. // pressable so that it is usable inside the dialog.
const {insideDialog} = useDialogContext() const {insideDialog} = useDialogContext()
if (!Component) { if (!PressableComponent) {
if (insideDialog) { if (insideDialog) {
Component = NormalizedRNGHPressable PressableComponent = NormalizedRNGHPressable
} else { } else {
Component = Pressable PressableComponent = Pressable
} }
} }
@@ -464,7 +464,7 @@ export const Button = React.forwardRef<View, ButtonProps>(
const flattenedBaseStyles = flatten([baseStyles, style]) const flattenedBaseStyles = flatten([baseStyles, style])
return ( return (
<Component <PressableComponent
role="button" role="button"
accessibilityHint={undefined} // optional accessibilityHint={undefined} // optional
{...rest} {...rest}
@@ -516,7 +516,7 @@ export const Button = React.forwardRef<View, ButtonProps>(
<Context.Provider value={context}> <Context.Provider value={context}>
{typeof children === 'function' ? children(context) : children} {typeof children === 'function' ? children(context) : children}
</Context.Provider> </Context.Provider>
</Component> </PressableComponent>
) )
}, },
) )
+7 -7
View File
@@ -105,11 +105,7 @@ export function Outer({
export function Item({children, label, style, onPress, ...rest}: ItemProps) { export function Item({children, label, style, onPress, ...rest}: ItemProps) {
const t = useTheme() const t = useTheme()
const {control} = React.useContext(Context) const {control} = React.useContext(Context)
const { const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
state: focused,
onIn: onHoverIn,
onOut: onHoverOut,
} = useInteractionState()
const { const {
state: pressed, state: pressed,
onIn: onPressIn, onIn: onPressIn,
@@ -121,9 +117,15 @@ export function Item({children, label, style, onPress, ...rest}: ItemProps) {
{...rest} {...rest}
accessibilityHint="" accessibilityHint=""
accessibilityLabel={label} accessibilityLabel={label}
onFocus={onFocus}
onBlur={onBlur}
onPress={e => { onPress={e => {
control?.close() control?.close()
onPress(e) onPress(e)
if (!e.defaultPrevented) {
control?.close()
}
}} }}
onPressIn={e => { onPressIn={e => {
onPressIn() onPressIn()
@@ -133,8 +135,6 @@ export function Item({children, label, style, onPress, ...rest}: ItemProps) {
onPressOut() onPressOut()
rest.onPressOut?.(e) rest.onPressOut?.(e)
}} }}
onHoverIn={onHoverIn}
onHoverOut={onHoverOut}
style={[ style={[
a.flex_row, a.flex_row,
a.align_center, a.align_center,
+3 -1
View File
@@ -16,6 +16,7 @@ import * as Toggle from '#/components/forms/Toggle'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron' import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {ReportDialogProps} from './types' import {ReportDialogProps} from './types'
@@ -153,7 +154,8 @@ export function SubmitView({
<Toggle.Item <Toggle.Item
key={labeler.creator.did} key={labeler.creator.did}
name={labeler.creator.did} name={labeler.creator.did}
label={title}> label={title}
PressableComponent={NormalizedRNGHPressable}>
<LabelerToggle title={title} /> <LabelerToggle title={title} />
</Toggle.Item> </Toggle.Item>
) )
+15 -7
View File
@@ -30,6 +30,7 @@ import {PageText_Stroke2_Corner0_Rounded as PageText} from '#/components/icons/P
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
@@ -168,7 +169,8 @@ function MutedWordsInner() {
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word until you unmute it`)} label={_(msg`Mute this word until you unmute it`)}
name="forever" name="forever"
style={[a.flex_1]}> style={[a.flex_1]}
PressableComponent={NormalizedRNGHPressable}>
<TargetToggle> <TargetToggle>
<View <View
style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}>
@@ -183,7 +185,8 @@ function MutedWordsInner() {
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word for 24 hours`)} label={_(msg`Mute this word for 24 hours`)}
name="24_hours" name="24_hours"
style={[a.flex_1]}> style={[a.flex_1]}
PressableComponent={NormalizedRNGHPressable}>
<TargetToggle> <TargetToggle>
<View <View
style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}>
@@ -207,7 +210,8 @@ function MutedWordsInner() {
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word for 7 days`)} label={_(msg`Mute this word for 7 days`)}
name="7_days" name="7_days"
style={[a.flex_1]}> style={[a.flex_1]}
PressableComponent={NormalizedRNGHPressable}>
<TargetToggle> <TargetToggle>
<View <View
style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}>
@@ -222,7 +226,8 @@ function MutedWordsInner() {
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word for 30 days`)} label={_(msg`Mute this word for 30 days`)}
name="30_days" name="30_days"
style={[a.flex_1]}> style={[a.flex_1]}
PressableComponent={NormalizedRNGHPressable}>
<TargetToggle> <TargetToggle>
<View <View
style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}>
@@ -256,7 +261,8 @@ function MutedWordsInner() {
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word in post text and tags`)} label={_(msg`Mute this word in post text and tags`)}
name="content" name="content"
style={[a.flex_1]}> style={[a.flex_1]}
PressableComponent={NormalizedRNGHPressable}>
<TargetToggle> <TargetToggle>
<View <View
style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}>
@@ -272,7 +278,8 @@ function MutedWordsInner() {
<Toggle.Item <Toggle.Item
label={_(msg`Mute this word in tags only`)} label={_(msg`Mute this word in tags only`)}
name="tag" name="tag"
style={[a.flex_1]}> style={[a.flex_1]}
PressableComponent={NormalizedRNGHPressable}>
<TargetToggle> <TargetToggle>
<View <View
style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}>
@@ -302,7 +309,8 @@ function MutedWordsInner() {
name="exclude_following" name="exclude_following"
style={[a.flex_row, a.justify_between]} style={[a.flex_row, a.justify_between]}
value={excludeFollowing} value={excludeFollowing}
onChange={setExcludeFollowing}> onChange={setExcludeFollowing}
PressableComponent={NormalizedRNGHPressable}>
<TargetToggle> <TargetToggle>
<View style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> <View style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}>
<Toggle.Checkbox /> <Toggle.Checkbox />
@@ -37,6 +37,7 @@ import * as Toggle from '#/components/forms/Toggle'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
export type PostInteractionSettingsFormProps = { export type PostInteractionSettingsFormProps = {
@@ -303,7 +304,8 @@ export function PostInteractionSettingsForm({
} }
value={quotesEnabled} value={quotesEnabled}
onChange={onChangeQuotesEnabled} onChange={onChangeQuotesEnabled}
style={[, a.justify_between, a.pt_xs]}> style={[, a.justify_between, a.pt_xs]}
PressableComponent={NormalizedRNGHPressable}>
<Text style={[t.atoms.text_contrast_medium]}> <Text style={[t.atoms.text_contrast_medium]}>
{quotesEnabled ? ( {quotesEnabled ? (
<Trans>Quote posts enabled</Trans> <Trans>Quote posts enabled</Trans>
-174
View File
@@ -1,174 +0,0 @@
import React, {useCallback, useEffect} from 'react'
import {View} from 'react-native'
import {ChatBskyActorDeclaration} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useUpdateActorDeclaration} from '#/state/queries/messages/actor-declaration'
import {useProfileQuery} from '#/state/queries/profile'
import {useSession} from '#/state/session'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useTheme, web} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import * as Toggle from '#/components/forms/Toggle'
import {Message_Stroke2_Corner0_Rounded} from '#/components/icons/Message'
import {Text} from '#/components/Typography'
export function MessagesNUX() {
const control = Dialog.useDialogControl()
const {currentAccount} = useSession()
const {data: profile} = useProfileQuery({
did: currentAccount!.did,
})
useEffect(() => {
if (profile && typeof profile.associated?.chat === 'undefined') {
const timeout = setTimeout(() => {
control.open()
}, 1000)
return () => {
clearTimeout(timeout)
}
}
}, [profile, control])
if (!profile) return null
return (
<Dialog.Outer control={control}>
<DialogInner chatDeclation={profile.associated?.chat} />
</Dialog.Outer>
)
}
function DialogInner({
chatDeclation,
}: {
chatDeclation?: ChatBskyActorDeclaration.Record
}) {
const control = Dialog.useDialogContext()
const {_} = useLingui()
const t = useTheme()
const [initialized, setInitialzed] = React.useState(false)
const {mutate: updateDeclaration} = useUpdateActorDeclaration({
onError: () => {
Toast.show(_(msg`Failed to update settings`), 'xmark')
},
})
const onSelectItem = useCallback(
(keys: string[]) => {
const key = keys[0]
if (!key) return
updateDeclaration(key as 'all' | 'none' | 'following')
},
[updateDeclaration],
)
useEffect(() => {
if (!chatDeclation && !initialized) {
updateDeclaration('following')
setInitialzed(true)
}
}, [chatDeclation, updateDeclaration, initialized])
return (
<Dialog.ScrollableInner
label={_(msg`Introducing Direct Messages`)}
style={web({maxWidth: 440})}>
<View style={a.gap_xl}>
<View style={[a.align_center, a.pt_sm, a.pb_xs]}>
<Message_Stroke2_Corner0_Rounded width={64} />
<Text style={[a.text_2xl, a.font_bold, a.text_center, a.mt_md]}>
<Trans>Direct messages are here!</Trans>
</Text>
<Text style={[a.text_md, a.text_center, a.mt_sm]}>
<Trans>Privately chat with other users.</Trans>
</Text>
</View>
<View
style={[
a.gap_xs,
a.border,
a.overflow_hidden,
a.rounded_sm,
t.atoms.border_contrast_low,
]}>
<View
style={[
a.p_md,
a.border_b,
t.atoms.bg_contrast_25,
t.atoms.border_contrast_low,
]}>
<Text style={[a.text_sm, a.font_bold]}>
<Trans>Who can message you?</Trans>
</Text>
<Text
style={[
a.mt_xs,
a.text_sm,
a.italic,
t.atoms.text_contrast_medium,
]}>
<Trans>You can change this at any time.</Trans>
</Text>
</View>
<View style={[a.px_md, a.py_xs]}>
<Toggle.Group
label={_(msg`Who can message you?`)}
type="radio"
values={[chatDeclation?.allowIncoming ?? 'following']}
onChange={onSelectItem}>
<View>
<Toggle.Item
name="all"
label={_(msg`Everyone`)}
style={[a.justify_between, a.py_sm, a.rounded_2xs]}>
<Toggle.LabelText>
<Trans>Everyone</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
<Toggle.Item
name="following"
label={_(msg`Users I follow`)}
style={[a.justify_between, a.py_sm, a.rounded_2xs]}>
<Toggle.LabelText>
<Trans>Users I follow</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
<Toggle.Item
name="none"
label={_(msg`No one`)}
style={[a.justify_between, a.py_sm, a.rounded_2xs]}>
<Toggle.LabelText>
<Trans>No one</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
</View>
</Toggle.Group>
</View>
</View>
<Button
label={_(msg`Start chatting`)}
accessibilityHint={_(msg`Close modal`)}
size="large"
color="primary"
variant="solid"
onPress={() => control.close()}>
<ButtonText>
<Trans>Get started</Trans>
</ButtonText>
</Button>
</View>
<Dialog.Close />
</Dialog.ScrollableInner>
)
}
+6 -4
View File
@@ -1,9 +1,9 @@
import React from 'react' import React from 'react'
import {Pressable, View, ViewStyle} from 'react-native' import {Pressable, PressableProps, View, ViewStyle} from 'react-native'
import Animated, {LinearTransition} from 'react-native-reanimated' import Animated, {LinearTransition} from 'react-native-reanimated'
import {HITSLOP_10} from '#/lib/constants'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
import {HITSLOP_10} from 'lib/constants'
import { import {
atoms as a, atoms as a,
flatten, flatten,
@@ -68,6 +68,7 @@ export type ItemProps = ViewStyleProp & {
onChange?: (selected: boolean) => void onChange?: (selected: boolean) => void
isInvalid?: boolean isInvalid?: boolean
children: ((props: ItemState) => React.ReactNode) | React.ReactNode children: ((props: ItemState) => React.ReactNode) | React.ReactNode
PressableComponent?: React.ComponentType<PressableProps>
} }
export function useItemContext() { export function useItemContext() {
@@ -159,6 +160,7 @@ export function Item({
style, style,
type = 'checkbox', type = 'checkbox',
label, label,
PressableComponent = Pressable,
...rest ...rest
}: ItemProps) { }: ItemProps) {
const { const {
@@ -206,7 +208,7 @@ export function Item({
return ( return (
<ItemContext.Provider value={state}> <ItemContext.Provider value={state}>
<Pressable <PressableComponent
accessibilityHint={undefined} // optional accessibilityHint={undefined} // optional
hitSlop={HITSLOP_10} hitSlop={HITSLOP_10}
{...rest} {...rest}
@@ -231,7 +233,7 @@ export function Item({
onBlur={onBlur} onBlur={onBlur}
style={[a.flex_row, a.align_center, a.gap_sm, flatten(style)]}> style={[a.flex_row, a.align_center, a.gap_sm, flatten(style)]}>
{typeof children === 'function' ? children(state) : children} {typeof children === 'function' ? children(state) : children}
</Pressable> </PressableComponent>
</ItemContext.Provider> </ItemContext.Provider>
) )
} }
@@ -3,11 +3,14 @@ import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {isNative} from '#/platform/detection'
import {useAgent, useSession} from '#/state/session' import {useAgent, useSession} from '#/state/session'
import {atoms as a} from '#/alf' import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog' import * as Dialog from '#/components/Dialog'
import {DialogControlProps} from '#/components/Dialog' import {DialogControlProps} from '#/components/Dialog'
import {Divider} from '#/components/Divider'
import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Resend} from '#/components/icons/ArrowRotateCounterClockwise'
import {useIntentDialogs} from '#/components/intents/IntentDialogs' import {useIntentDialogs} from '#/components/intents/IntentDialogs'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
@@ -22,7 +25,9 @@ export function VerifyEmailIntentDialog() {
) )
} }
function Inner({control}: {control: DialogControlProps}) { function Inner({}: {control: DialogControlProps}) {
const t = useTheme()
const {gtMobile} = useBreakpoints()
const {_} = useLingui() const {_} = useLingui()
const {verifyEmailState: state} = useIntentDialogs() const {verifyEmailState: state} = useIntentDialogs()
const [status, setStatus] = React.useState< const [status, setStatus] = React.useState<
@@ -57,43 +62,47 @@ function Inner({control}: {control: DialogControlProps}) {
} }
return ( return (
<Dialog.ScrollableInner label={_(msg`Verify email dialog`)}> <Dialog.ScrollableInner
<Dialog.Close /> label={_(msg`Verify email dialog`)}
style={[
gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full,
]}>
<View style={[a.gap_xl]}> <View style={[a.gap_xl]}>
{status === 'loading' ? ( {status === 'loading' ? (
<View style={[a.py_2xl, a.align_center, a.justify_center]}> <View style={[a.py_2xl, a.align_center, a.justify_center]}>
<Loader size="xl" /> <Loader size="xl" fill={t.atoms.text_contrast_low.color} />
</View> </View>
) : status === 'success' ? ( ) : status === 'success' ? (
<> <View style={[a.gap_sm, isNative && a.pb_xl]}>
<Text style={[a.font_bold, a.text_2xl]}> <Text style={[a.font_heavy, a.text_2xl]}>
<Trans>Email Verified</Trans> <Trans>Email Verified</Trans>
</Text> </Text>
<Text style={[a.text_md, a.leading_tight]}> <Text style={[a.text_md, a.leading_snug]}>
<Trans> <Trans>
Thanks, you have successfully verified your email address. Thanks, you have successfully verified your email address. You
can close this dialog.
</Trans> </Trans>
</Text> </Text>
</> </View>
) : status === 'failure' ? ( ) : status === 'failure' ? (
<> <View style={[a.gap_sm]}>
<Text style={[a.font_bold, a.text_2xl]}> <Text style={[a.font_heavy, a.text_2xl]}>
<Trans>Invalid Verification Code</Trans> <Trans>Invalid Verification Code</Trans>
</Text> </Text>
<Text style={[a.text_md, a.leading_tight]}> <Text style={[a.text_md, a.leading_snug]}>
<Trans> <Trans>
The verification code you have provided is invalid. Please make The verification code you have provided is invalid. Please make
sure that you have used the correct verification link or request sure that you have used the correct verification link or request
a new one. a new one.
</Trans> </Trans>
</Text> </Text>
</> </View>
) : ( ) : (
<> <View style={[a.gap_sm, isNative && a.pb_xl]}>
<Text style={[a.font_bold, a.text_2xl]}> <Text style={[a.font_heavy, a.text_2xl]}>
<Trans>Email Resent</Trans> <Trans>Email Resent</Trans>
</Text> </Text>
<Text style={[a.text_md, a.leading_tight]}> <Text style={[a.text_md, a.leading_snug]}>
<Trans> <Trans>
We have sent another verification email to{' '} We have sent another verification email to{' '}
<Text style={[a.text_md, a.font_bold]}> <Text style={[a.text_md, a.font_bold]}>
@@ -102,38 +111,29 @@ function Inner({control}: {control: DialogControlProps}) {
. .
</Trans> </Trans>
</Text> </Text>
</> </View>
)} )}
{status !== 'loading' ? (
<View style={[a.w_full, a.flex_row, a.gap_sm, {marginLeft: 'auto'}]}> {status === 'failure' && (
<>
<Divider />
<Button <Button
label={_(msg`Close`)} label={_(msg`Resend Verification Email`)}
onPress={() => control.close()} onPress={onPressResendEmail}
variant="solid" variant="solid"
color={status === 'failure' ? 'secondary' : 'primary'} color="secondary_inverted"
size="large" size="large"
style={{marginLeft: 'auto'}}> disabled={sending}>
<ButtonIcon icon={sending ? Loader : Resend} position="left" />
<ButtonText> <ButtonText>
<Trans>Close</Trans> <Trans>Resend Email</Trans>
</ButtonText> </ButtonText>
</Button> </Button>
{status === 'failure' ? ( </>
<Button )}
label={_(msg`Resend Verification Email`)}
onPress={onPressResendEmail}
variant="solid"
color="primary"
size="large"
disabled={sending}>
<ButtonText>
<Trans>Resend Email</Trans>
</ButtonText>
{sending ? <Loader size="sm" style={{color: 'white'}} /> : null}
</Button>
) : null}
</View>
) : null}
</View> </View>
<Dialog.Close />
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
) )
} }
@@ -22,7 +22,6 @@ import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {DialogControlProps, useDialogControl} from '#/components/Dialog' import {DialogControlProps, useDialogControl} from '#/components/Dialog'
import {NewChat} from '#/components/dms/dialogs/NewChatDialog' import {NewChat} from '#/components/dms/dialogs/NewChatDialog'
import {MessagesNUX} from '#/components/dms/MessagesNUX'
import {useRefreshOnFocus} from '#/components/hooks/useRefreshOnFocus' import {useRefreshOnFocus} from '#/components/hooks/useRefreshOnFocus'
import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Retry} from '#/components/icons/ArrowRotateCounterClockwise' import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Retry} from '#/components/icons/ArrowRotateCounterClockwise'
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
@@ -33,7 +32,7 @@ import {Link} from '#/components/Link'
import {ListFooter} from '#/components/Lists' import {ListFooter} from '#/components/Lists'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {ChatListItem} from './ChatListItem' import {ChatListItem} from './components/ChatListItem'
type Props = NativeStackScreenProps<MessagesTabNavigatorParams, 'Messages'> type Props = NativeStackScreenProps<MessagesTabNavigatorParams, 'Messages'>
@@ -151,8 +150,6 @@ export function MessagesScreen({navigation, route}: Props) {
if (conversations.length < 1) { if (conversations.length < 1) {
return ( return (
<View style={a.flex_1}> <View style={a.flex_1}>
<MessagesNUX />
<CenteredView sideBorders={gtMobile} style={[a.h_full_vh]}> <CenteredView sideBorders={gtMobile} style={[a.h_full_vh]}>
{gtMobile ? ( {gtMobile ? (
<DesktopHeader <DesktopHeader
@@ -240,7 +237,6 @@ export function MessagesScreen({navigation, route}: Props) {
return ( return (
<View style={a.flex_1}> <View style={a.flex_1}>
<MessagesNUX />
{!gtMobile && ( {!gtMobile && (
<ViewHeader <ViewHeader
title={_(msg`Messages`)} title={_(msg`Messages`)}
@@ -8,16 +8,16 @@ import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack' import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {CommonNavigatorParams} from '#/lib/routes/types' import {CommonNavigatorParams} from '#/lib/routes/types'
import {isWeb} from '#/platform/detection'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {ConvoProvider, isConvoActive, useConvo} from '#/state/messages/convo'
import {ConvoStatus} from '#/state/messages/convo/types'
import {useCurrentConvoId} from '#/state/messages/current-convo-id' import {useCurrentConvoId} from '#/state/messages/current-convo-id'
import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useProfileQuery} from '#/state/queries/profile' import {useProfileQuery} from '#/state/queries/profile'
import {isWeb} from 'platform/detection' import {useSetMinimalShellMode} from '#/state/shell'
import {useProfileShadow} from 'state/cache/profile-shadow' import {CenteredView} from '#/view/com/util/Views'
import {ConvoProvider, isConvoActive, useConvo} from 'state/messages/convo' import {MessagesList} from '#/screens/Messages/components/MessagesList'
import {ConvoStatus} from 'state/messages/convo/types'
import {useSetMinimalShellMode} from 'state/shell'
import {CenteredView} from 'view/com/util/Views'
import {MessagesList} from '#/screens/Messages/Conversation/MessagesList'
import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {MessagesListBlockedFooter} from '#/components/dms/MessagesListBlockedFooter' import {MessagesListBlockedFooter} from '#/components/dms/MessagesListBlockedFooter'
import {MessagesListHeader} from '#/components/dms/MessagesListHeader' import {MessagesListHeader} from '#/components/dms/MessagesListHeader'
@@ -18,11 +18,11 @@ import Graphemer from 'graphemer'
import {HITSLOP_10, MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants' import {HITSLOP_10, MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants'
import {useHaptics} from '#/lib/haptics' import {useHaptics} from '#/lib/haptics'
import {isIOS} from '#/platform/detection'
import { import {
useMessageDraft, useMessageDraft,
useSaveMessageDraft, useSaveMessageDraft,
} from '#/state/messages/message-drafts' } from '#/state/messages/message-drafts'
import {isIOS} from 'platform/detection'
import {EmojiPickerPosition} from '#/view/com/composer/text-input/web/EmojiPicker.web' import {EmojiPickerPosition} from '#/view/com/composer/text-input/web/EmojiPicker.web'
import * as Toast from '#/view/com/util/Toast' import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
@@ -5,13 +5,13 @@ import {useLingui} from '@lingui/react'
import Graphemer from 'graphemer' import Graphemer from 'graphemer'
import TextareaAutosize from 'react-textarea-autosize' import TextareaAutosize from 'react-textarea-autosize'
import {isSafari, isTouchDevice} from '#/lib/browser'
import {MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants' import {MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import { import {
useMessageDraft, useMessageDraft,
useSaveMessageDraft, useSaveMessageDraft,
} from '#/state/messages/message-drafts' } from '#/state/messages/message-drafts'
import {isSafari, isTouchDevice} from 'lib/browser'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {textInputWebEmitter} from '#/view/com/composer/text-input/textInputWebEmitter' import {textInputWebEmitter} from '#/view/com/composer/text-input/textInputWebEmitter'
import { import {
Emoji, Emoji,
@@ -15,6 +15,8 @@ import {ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/rean
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {AppBskyEmbedRecord, AppBskyRichtextFacet, RichText} from '@atproto/api' import {AppBskyEmbedRecord, AppBskyRichtextFacet, RichText} from '@atproto/api'
import {clamp} from '#/lib/numbers'
import {ScrollProvider} from '#/lib/ScrollContext'
import {shortenLinks, stripInvalidMentions} from '#/lib/strings/rich-text-manip' import {shortenLinks, stripInvalidMentions} from '#/lib/strings/rich-text-manip'
import { import {
convertBskyAppUrlIfNeeded, convertBskyAppUrlIfNeeded,
@@ -22,21 +24,19 @@ import {
} from '#/lib/strings/url-helpers' } from '#/lib/strings/url-helpers'
import {logger} from '#/logger' import {logger} from '#/logger'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
import {isWeb} from '#/platform/detection'
import {isConvoActive, useConvoActive} from '#/state/messages/convo' import {isConvoActive, useConvoActive} from '#/state/messages/convo'
import {ConvoItem, ConvoStatus} from '#/state/messages/convo/types' import {ConvoItem, ConvoStatus} from '#/state/messages/convo/types'
import {useGetPost} from '#/state/queries/post' import {useGetPost} from '#/state/queries/post'
import {useAgent} from '#/state/session' import {useAgent} from '#/state/session'
import {clamp} from 'lib/numbers'
import {ScrollProvider} from 'lib/ScrollContext'
import {isWeb} from 'platform/detection'
import { import {
EmojiPicker, EmojiPicker,
EmojiPickerState, EmojiPickerState,
} from '#/view/com/composer/text-input/web/EmojiPicker.web' } from '#/view/com/composer/text-input/web/EmojiPicker.web'
import {List} from 'view/com/util/List' import {List} from '#/view/com/util/List'
import {ChatDisabled} from '#/screens/Messages/Conversation/ChatDisabled' import {ChatDisabled} from '#/screens/Messages/components/ChatDisabled'
import {MessageInput} from '#/screens/Messages/Conversation/MessageInput' import {MessageInput} from '#/screens/Messages/components/MessageInput'
import {MessageListError} from '#/screens/Messages/Conversation/MessageListError' import {MessageListError} from '#/screens/Messages/components/MessageListError'
import {ChatEmptyPill} from '#/components/dms/ChatEmptyPill' import {ChatEmptyPill} from '#/components/dms/ChatEmptyPill'
import {MessageItem} from '#/components/dms/MessageItem' import {MessageItem} from '#/components/dms/MessageItem'
import {NewMessagesPill} from '#/components/dms/NewMessagesPill' import {NewMessagesPill} from '#/components/dms/NewMessagesPill'
@@ -46,29 +46,31 @@ export const PlaceholderCanvas = React.forwardRef<PlaceholderCanvasRef, {}>(
return ( return (
<View style={styles.container}> <View style={styles.container}>
<LazyViewShot <React.Suspense fallback={null}>
// @ts-ignore this library doesn't have types <LazyViewShot
ref={viewshotRef} // @ts-ignore this library doesn't have types
options={{ ref={viewshotRef}
fileName: 'placeholderAvatar', options={{
format: 'jpg', fileName: 'placeholderAvatar',
quality: 0.8, format: 'jpg',
height: 150 * SIZE_MULTIPLIER, quality: 0.8,
width: 150 * SIZE_MULTIPLIER, height: 150 * SIZE_MULTIPLIER,
}}> width: 150 * SIZE_MULTIPLIER,
<View }}>
style={[ <View
styles.imageContainer, style={[
{backgroundColor: avatar.backgroundColor}, styles.imageContainer,
]} {backgroundColor: avatar.backgroundColor},
collapsable={false}> ]}
<Icon collapsable={false}>
height={85 * SIZE_MULTIPLIER} <Icon
width={85 * SIZE_MULTIPLIER} height={85 * SIZE_MULTIPLIER}
style={{color: 'white'}} width={85 * SIZE_MULTIPLIER}
/> style={{color: 'white'}}
</View> />
</LazyViewShot> </View>
</LazyViewShot>
</React.Suspense>
</View> </View>
) )
}, },
+7 -2
View File
@@ -12,6 +12,7 @@ import * as TextField from '#/components/forms/TextField'
import * as ToggleButton from '#/components/forms/ToggleButton' import * as ToggleButton from '#/components/forms/ToggleButton'
import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe' import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
import {InlineLinkText} from '#/components/Link' import {InlineLinkText} from '#/components/Link'
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
import {P, Text} from '#/components/Typography' import {P, Text} from '#/components/Typography'
export function ServerInputDialog({ export function ServerInputDialog({
@@ -82,7 +83,10 @@ export function ServerInputDialog({
label="Preferences" label="Preferences"
values={fixedOption} values={fixedOption}
onChange={setFixedOption}> onChange={setFixedOption}>
<ToggleButton.Button name={BSKY_SERVICE} label={_(msg`Bluesky`)}> <ToggleButton.Button
name={BSKY_SERVICE}
label={_(msg`Bluesky`)}
PressableComponent={NormalizedRNGHPressable}>
<ToggleButton.ButtonText> <ToggleButton.ButtonText>
{_(msg`Bluesky`)} {_(msg`Bluesky`)}
</ToggleButton.ButtonText> </ToggleButton.ButtonText>
@@ -90,7 +94,8 @@ export function ServerInputDialog({
<ToggleButton.Button <ToggleButton.Button
testID="customSelectBtn" testID="customSelectBtn"
name="custom" name="custom"
label={_(msg`Custom`)}> label={_(msg`Custom`)}
PressableComponent={NormalizedRNGHPressable}>
<ToggleButton.ButtonText> <ToggleButton.ButtonText>
{_(msg`Custom`)} {_(msg`Custom`)}
</ToggleButton.ButtonText> </ToggleButton.ButtonText>
@@ -5,12 +5,12 @@ import {useLingui} from '@lingui/react'
import {PressableScale} from '#/lib/custom-animations/PressableScale' import {PressableScale} from '#/lib/custom-animations/PressableScale'
import {useHaptics} from '#/lib/haptics' import {useHaptics} from '#/lib/haptics'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {useHapticsDisabled} from '#/state/preferences' import {useHapticsDisabled} from '#/state/preferences'
import {useProfileQuery} from '#/state/queries/profile' import {useProfileQuery} from '#/state/queries/profile'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {UserAvatar} from '#/view/com/util/UserAvatar' import {UserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {useInteractionState} from '#/components/hooks/useInteractionState'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
export function PostThreadComposePrompt({ export function PostThreadComposePrompt({
@@ -21,10 +21,15 @@ export function PostThreadComposePrompt({
const {currentAccount} = useSession() const {currentAccount} = useSession()
const {data: profile} = useProfileQuery({did: currentAccount?.did}) const {data: profile} = useProfileQuery({did: currentAccount?.did})
const {_} = useLingui() const {_} = useLingui()
const {isTabletOrDesktop} = useWebMediaQueries() const {gtMobile} = useBreakpoints()
const t = useTheme() const t = useTheme()
const playHaptics = useHaptics() const playHaptics = useHaptics()
const isHapticsDisabled = useHapticsDisabled() const isHapticsDisabled = useHapticsDisabled()
const {
state: hovered,
onIn: onHoverIn,
onOut: onHoverOut,
} = useInteractionState()
const onPress = () => { const onPress = () => {
playHaptics('Light') playHaptics('Light')
@@ -42,13 +47,15 @@ export function PostThreadComposePrompt({
accessibilityLabel={_(msg`Compose reply`)} accessibilityLabel={_(msg`Compose reply`)}
accessibilityHint={_(msg`Opens composer`)} accessibilityHint={_(msg`Opens composer`)}
style={[ style={[
{paddingTop: 8, paddingBottom: isTabletOrDesktop ? 8 : 11}, gtMobile ? a.py_xs : {paddingTop: 8, paddingBottom: 11},
a.px_sm, gtMobile ? {paddingLeft: 6, paddingRight: 6} : a.px_sm,
a.border_t, a.border_t,
t.atoms.border_contrast_low, t.atoms.border_contrast_low,
t.atoms.bg, t.atoms.bg,
]} ]}
onPress={onPress}> onPress={onPress}
onHoverIn={onHoverIn}
onHoverOut={onHoverOut}>
<View <View
style={[ style={[
a.flex_row, a.flex_row,
@@ -56,10 +63,11 @@ export function PostThreadComposePrompt({
a.p_sm, a.p_sm,
a.gap_sm, a.gap_sm,
a.rounded_full, a.rounded_full,
t.atoms.bg_contrast_25, (!gtMobile || hovered) && t.atoms.bg_contrast_25,
a.transition_color,
]}> ]}>
<UserAvatar <UserAvatar
size={22} size={gtMobile ? 24 : 22}
avatar={profile?.avatar} avatar={profile?.avatar}
type={profile?.associated?.labeler ? 'labeler' : 'user'} type={profile?.associated?.labeler ? 'labeler' : 'user'}
/> />
@@ -156,7 +156,6 @@ let RepostButton = ({
</View> </View>
<Button <Button
label={_(msg`Cancel quote post`)} label={_(msg`Cancel quote post`)}
onAccessibilityEscape={close}
onPress={close} onPress={close}
size="large" size="large"
variant="solid" variant="solid"
+4 -4
View File
@@ -4120,10 +4120,10 @@
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
"@haileyok/bluesky-bottom-sheet@^0.1.1-alpha.9": "@haileyok/bluesky-bottom-sheet@^0.1.1-alpha.11":
version "0.1.1-alpha.9" version "0.1.1-alpha.11"
resolved "https://registry.yarnpkg.com/@haileyok/bluesky-bottom-sheet/-/bluesky-bottom-sheet-0.1.1-alpha.9.tgz#f23a9245d4fed5e1825222249f2ad64ec99896e6" resolved "https://registry.yarnpkg.com/@haileyok/bluesky-bottom-sheet/-/bluesky-bottom-sheet-0.1.1-alpha.11.tgz#a9c0e1c1903ba066c185481958f4ea9519cd5ba3"
integrity sha512-duGQ/l20Mr/lmjS7lUu0T0QgARA/V47PrmpL7LZJMoK4IhSBHT4HMSjjOaBcSJhQg2I5/uSX3pShFzCfdGttVQ== integrity sha512-RtiEpEIXtejBzCtspFO7oEw6n87LnVQuSz+FGGEQZ6ywnRUBy6HZ5bpE3IFI7mmyF2YjAPg2nLzsqR9NXRMlhQ==
"@haileyok/bluesky-video@0.1.10": "@haileyok/bluesky-video@0.1.10":
version "0.1.10" version "0.1.10"