Move /platform/detection vars into /env (#9707)

* Add platform vars to env

* Replace /platform/detection with /env
This commit is contained in:
Eric Bailey
2026-01-16 16:28:17 -06:00
committed by GitHub
parent bd510d8468
commit 0589bd7d9e
244 changed files with 789 additions and 789 deletions
+2 -2
View File
@@ -31,7 +31,7 @@ export const SplashScreen = ({
}) => {
const {_} = useLingui()
const t = useTheme()
const {isTabletOrMobile: isMobileWeb} = useWebMediaQueries()
const {isTabletOrMobile: IS_WEB_MOBILE} = useWebMediaQueries()
const [showClipOverlay, setShowClipOverlay] = React.useState(false)
React.useEffect(() => {
@@ -78,7 +78,7 @@ export const SplashScreen = ({
a.justify_center,
// @ts-expect-error web only
{paddingBottom: '20vh'},
isMobileWeb && a.pb_5xl,
IS_WEB_MOBILE && a.pb_5xl,
t.atoms.border_contrast_medium,
a.align_center,
a.gap_5xl,
+19 -19
View File
@@ -76,7 +76,6 @@ import {logEvent} from '#/lib/statsig/statsig'
import {cleanError} from '#/lib/strings/errors'
import {colors} from '#/lib/styles'
import {logger} from '#/logger'
import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection'
import {useDialogStateControlContext} from '#/state/dialogs'
import {emitPostCreated} from '#/state/events'
import {
@@ -130,6 +129,7 @@ import {LazyQuoteEmbed} from '#/components/Post/Embed/LazyQuoteEmbed'
import * as Prompt from '#/components/Prompt'
import * as Toast from '#/components/Toast'
import {Text as NewText} from '#/components/Typography'
import {IS_ANDROID, IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
import {BottomSheetPortalProvider} from '../../../../modules/bottom-sheet'
import {PostLanguageSelect} from './select-language/PostLanguageSelect'
import {
@@ -329,14 +329,14 @@ export const ComposePost = ({
const insets = useSafeAreaInsets()
const viewStyles = useMemo(
() => ({
paddingTop: isAndroid ? insets.top : 0,
paddingTop: IS_ANDROID ? insets.top : 0,
paddingBottom:
// iOS - when keyboard is closed, keep the bottom bar in the safe area
(isIOS && !isKeyboardVisible) ||
(IS_IOS && !isKeyboardVisible) ||
// Android - Android >=35 KeyboardAvoidingView adds double padding when
// keyboard is closed, so we subtract that in the offset and add it back
// here when the keyboard is open
(isAndroid && isKeyboardVisible)
(IS_ANDROID && isKeyboardVisible)
? insets.bottom
: 0,
}),
@@ -366,7 +366,7 @@ export const ComposePost = ({
// On Android, pressing Back should ask confirmation.
useEffect(() => {
if (!isAndroid) {
if (!IS_ANDROID) {
return
}
const backHandler = BackHandler.addEventListener(
@@ -671,7 +671,7 @@ export const ComposePost = ({
composerState.mutableNeedsFocusActive = false
// On Android, this risks getting the cursor stuck behind the keyboard.
// Not worth it.
if (!isAndroid) {
if (!IS_ANDROID) {
textInput.current?.focus()
}
}
@@ -727,12 +727,12 @@ export const ComposePost = ({
</>
)
const isWebFooterSticky = !isNative && thread.posts.length > 1
const IS_WEBFooterSticky = !IS_NATIVE && thread.posts.length > 1
return (
<BottomSheetPortalProvider>
<KeyboardAvoidingView
testID="composePostView"
behavior={isIOS ? 'padding' : 'height'}
behavior={IS_IOS ? 'padding' : 'height'}
keyboardVerticalOffset={keyboardVerticalOffset}
style={a.flex_1}>
<View
@@ -790,13 +790,13 @@ export const ComposePost = ({
onPublish={onComposerPostPublish}
onError={setError}
/>
{isWebFooterSticky && post.id === activePost.id && (
{IS_WEBFooterSticky && post.id === activePost.id && (
<View style={styles.stickyFooterWeb}>{footer}</View>
)}
</React.Fragment>
))}
</Animated.ScrollView>
{!isWebFooterSticky && footer}
{!IS_WEBFooterSticky && footer}
</View>
<Prompt.Basic
@@ -849,7 +849,7 @@ let ComposerPost = React.memo(function ComposerPost({
const {data: currentProfile} = useProfileQuery({did: currentDid})
const richtext = post.richtext
const isTextOnly = !post.embed.link && !post.embed.quote && !post.embed.media
const forceMinHeight = isWeb && isTextOnly && isActive
const forceMinHeight = IS_WEB && isTextOnly && isActive
const selectTextInputPlaceholder = isReply
? isFirstPost
? _(msg`Write your reply`)
@@ -889,9 +889,9 @@ let ComposerPost = React.memo(function ComposerPost({
async (uri: string) => {
if (
uri.startsWith('data:video/') ||
(isWeb && uri.startsWith('data:image/gif'))
(IS_WEB && uri.startsWith('data:image/gif'))
) {
if (isNative) return // web only
if (IS_NATIVE) return // web only
const [mimeType] = uri.slice('data:'.length).split(';')
if (!SUPPORTED_MIME_TYPES.includes(mimeType as SupportedMimeTypes)) {
Toast.show(_(msg`Unsupported video type: ${mimeType}`), {
@@ -921,9 +921,9 @@ let ComposerPost = React.memo(function ComposerPost({
a.mb_sm,
!isActive && isLastPost && a.mb_lg,
!isActive && styles.inactivePost,
isTextOnly && isNative && a.flex_grow,
isTextOnly && IS_NATIVE && a.flex_grow,
]}>
<View style={[a.flex_row, isNative && a.flex_1]}>
<View style={[a.flex_row, IS_NATIVE && a.flex_1]}>
<UserAvatar
avatar={currentProfile?.avatar}
size={42}
@@ -1241,7 +1241,7 @@ function ComposerEmbeds({
</LayoutAnimationConfig>
{embed.quote?.uri ? (
<View
style={[a.pb_sm, video ? [a.pt_md] : [a.pt_xl], isWeb && [a.pb_md]]}>
style={[a.pb_sm, video ? [a.pt_md] : [a.pt_xl], IS_WEB && [a.pb_md]]}>
<View style={[a.relative]}>
<View style={{pointerEvents: 'none'}}>
<LazyQuoteEmbed uri={embed.quote.uri} />
@@ -1652,7 +1652,7 @@ function useKeyboardVerticalOffset() {
const {top, bottom} = useSafeAreaInsets()
// Android etc
if (!isIOS) {
if (!IS_IOS) {
// need to account for the edge-to-edge nav bar
return bottom * -1
}
@@ -1696,7 +1696,7 @@ function useHideKeyboardOnBackground() {
const appState = useAppState()
useEffect(() => {
if (isIOS) {
if (IS_IOS) {
if (appState === 'inactive') {
Keyboard.dismiss()
}
@@ -1846,7 +1846,7 @@ function ToolbarWrapper({
style: StyleProp<ViewStyle>
children: React.ReactNode
}) {
if (isWeb) return children
if (IS_WEB) return children
return (
<Animated.View
style={style}
+2 -2
View File
@@ -9,7 +9,6 @@ import {
type EmbedPlayerParams,
parseEmbedPlayerFromUrl,
} from '#/lib/strings/embed-player'
import {isAndroid} from '#/platform/detection'
import {useResolveGifQuery} from '#/state/queries/resolve-link'
import {type Gif} from '#/state/queries/tenor'
import {AltTextCounterWrapper} from '#/view/com/composer/AltTextCounterWrapper'
@@ -23,6 +22,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/ico
import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {GifEmbed} from '#/components/Post/Embed/ExternalEmbed/Gif'
import {Text} from '#/components/Typography'
import {IS_ANDROID} from '#/env'
import {AltTextReminder} from './photos/Gallery'
export function GifAltTextDialog({
@@ -224,7 +224,7 @@ function AltTextInner({
</View>
<Dialog.Close />
{/* Maybe fix this later -h */}
{isAndroid ? <View style={{height: 300}} /> : null}
{IS_ANDROID ? <View style={{height: 300}} /> : null}
</Dialog.ScrollableInner>
)
}
+2 -2
View File
@@ -3,8 +3,8 @@ import {KeyboardStickyView} from 'react-native-keyboard-controller'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import type React from 'react'
import {isWeb} from '#/platform/detection'
import {atoms as a, useTheme} from '#/alf'
import {IS_WEB} from '#/env'
export function KeyboardAccessory({children}: {children: React.ReactNode}) {
const t = useTheme()
@@ -22,7 +22,7 @@ export function KeyboardAccessory({children}: {children: React.ReactNode}) {
]
// todo: when iPad support is added, it should also not use the KeyboardStickyView
if (isWeb) {
if (IS_WEB) {
return <View style={style}>{children}</View>
}
+9 -9
View File
@@ -11,13 +11,13 @@ import {
} from '#/lib/hooks/usePermissions'
import {openUnifiedPicker} from '#/lib/media/picker'
import {extractDataUriMime} from '#/lib/media/util'
import {isNative, isWeb} from '#/platform/detection'
import {MAX_IMAGES} from '#/view/com/composer/state/composer'
import {atoms as a, useTheme} from '#/alf'
import {Button} from '#/components/Button'
import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper'
import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image'
import * as toast from '#/components/Toast'
import {IS_NATIVE, IS_WEB} from '#/env'
export type SelectMediaButtonProps = {
disabled?: boolean
@@ -91,7 +91,7 @@ const SUPPORTED_IMAGE_MIME_TYPES = (
'image/svg+xml',
'image/webp',
'image/avif',
isNative && 'image/heic',
IS_NATIVE && 'image/heic',
] as const
).filter(Boolean)
type SupportedImageMimeType = Exclude<
@@ -261,7 +261,7 @@ async function processImagePickerAssets(
* We don't care too much about mimeType at this point on native,
* since the `processVideo` step later on will convert to `.mp4`.
*/
if (isWeb && !isSupportedVideoMimeType(mimeType)) {
if (IS_WEB && !isSupportedVideoMimeType(mimeType)) {
errors.add(SelectedAssetError.Unsupported)
continue
}
@@ -271,7 +271,7 @@ async function processImagePickerAssets(
* to filter out large files on web. On native, we compress these anyway,
* so we only check on web.
*/
if (isWeb && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) {
if (IS_WEB && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) {
errors.add(SelectedAssetError.FileTooBig)
continue
}
@@ -290,7 +290,7 @@ async function processImagePickerAssets(
* to filter out large files on web. On native, we compress GIFs as
* videos anyway, so we only check on web.
*/
if (isWeb && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) {
if (IS_WEB && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) {
errors.add(SelectedAssetError.FileTooBig)
continue
}
@@ -308,7 +308,7 @@ async function processImagePickerAssets(
* base64 data-uri, so we construct it here for web only.
*/
uri:
isWeb && asset.base64
IS_WEB && asset.base64
? `data:${mimeType};base64,${asset.base64}`
: asset.uri,
})
@@ -327,7 +327,7 @@ async function processImagePickerAssets(
}
if (supportedAssets[0].duration) {
if (isWeb) {
if (IS_WEB) {
/*
* Web reports duration as seconds
*/
@@ -432,7 +432,7 @@ export function SelectMediaButton({
)
const onPressSelectMedia = useCallback(async () => {
if (isNative) {
if (IS_NATIVE) {
const [photoAccess, videoAccess] = await Promise.all([
requestPhotoAccessIfNeeded(),
requestVideoAccessIfNeeded(),
@@ -446,7 +446,7 @@ export function SelectMediaButton({
}
}
if (isNative && Keyboard.isVisible()) {
if (IS_NATIVE && Keyboard.isVisible()) {
Keyboard.dismiss()
}
+2 -2
View File
@@ -9,7 +9,6 @@ import {
type OtherSelfLabel,
type SelfLabel,
} from '#/lib/moderation'
import {isWeb} from '#/platform/detection'
import {atoms as a, useTheme, web} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
@@ -18,6 +17,7 @@ import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {TinyChevronBottom_Stroke2_Corner0_Rounded as TinyChevronIcon} from '#/components/icons/Chevron'
import {Shield_Stroke2_Corner0_Rounded} from '#/components/icons/Shield'
import {Text} from '#/components/Typography'
import {IS_WEB} from '#/env'
export function LabelsBtn({
labels,
@@ -218,7 +218,7 @@ function DialogInner({
label={_(msg`Done`)}
onPress={() => control.close()}
color="primary"
size={isWeb ? 'small' : 'large'}
size={IS_WEB ? 'small' : 'large'}
variant="solid"
testID="confirmBtn">
<ButtonText>
+2 -2
View File
@@ -16,12 +16,12 @@ import {useLingui} from '@lingui/react'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {type Dimensions} from '#/lib/media/types'
import {colors, s} from '#/lib/styles'
import {isNative} from '#/platform/detection'
import {type ComposerImage, cropImage} from '#/state/gallery'
import {Text} from '#/view/com/util/text/Text'
import {tokens, useTheme} from '#/alf'
import * as Dialog from '#/components/Dialog'
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
import {IS_NATIVE} from '#/env'
import {type PostAction} from '../state/composer'
import {EditImageDialog} from './EditImageDialog'
import {ImageAltTextDialog} from './ImageAltTextDialog'
@@ -145,7 +145,7 @@ const GalleryItem = ({
const editControl = Dialog.useDialogControl()
const onImageEdit = () => {
if (isNative) {
if (IS_NATIVE) {
cropImage(image).then(next => {
onChange(next)
})
@@ -6,7 +6,6 @@ import {useLingui} from '@lingui/react'
import {MAX_ALT_TEXT} from '#/lib/constants'
import {enforceLen} from '#/lib/strings/helpers'
import {isAndroid, isWeb} from '#/platform/detection'
import {type ComposerImage} from '#/state/gallery'
import {AltTextCounterWrapper} from '#/view/com/composer/AltTextCounterWrapper'
import {atoms as a, useTheme} from '#/alf'
@@ -16,6 +15,7 @@ import {type DialogControlProps} from '#/components/Dialog'
import * as TextField from '#/components/forms/TextField'
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
import {Text} from '#/components/Typography'
import {IS_ANDROID, IS_WEB} from '#/env'
type Props = {
control: Dialog.DialogOuterProps['control']
@@ -66,7 +66,7 @@ const ImageAltTextInner = ({
const windim = useWindowDimensions()
const imageStyle = React.useMemo<ImageStyle>(() => {
const maxWidth = isWeb ? 450 : windim.width
const maxWidth = IS_WEB ? 450 : windim.width
const source = image.transformed ?? image.source
if (source.height > source.width) {
@@ -165,7 +165,7 @@ const ImageAltTextInner = ({
</AltTextCounterWrapper>
</View>
{/* Maybe fix this later -h */}
{isAndroid ? <View style={{height: 300}} /> : null}
{IS_ANDROID ? <View style={{height: 300}} /> : null}
</Dialog.ScrollableInner>
)
}
@@ -7,11 +7,11 @@ import {POST_IMG_MAX} from '#/lib/constants'
import {useCameraPermission} from '#/lib/hooks/usePermissions'
import {openCamera} from '#/lib/media/picker'
import {logger} from '#/logger'
import {isMobileWeb, isNative} from '#/platform/detection'
import {type ComposerImage, createComposerImage} from '#/state/gallery'
import {atoms as a, useTheme} from '#/alf'
import {Button} from '#/components/Button'
import {Camera_Stroke2_Corner0_Rounded as Camera} from '#/components/icons/Camera'
import {IS_NATIVE, IS_WEB_MOBILE} from '#/env'
type Props = {
disabled?: boolean
@@ -58,7 +58,7 @@ export function OpenCameraBtn({disabled, onAdd}: Props) {
requestMediaPermission,
])
const shouldShowCameraButton = isNative || isMobileWeb
const shouldShowCameraButton = IS_NATIVE || IS_WEB_MOBILE
if (!shouldShowCameraButton) {
return null
}
@@ -6,7 +6,6 @@ import {useLingui} from '@lingui/react'
import {languageName} from '#/locale/helpers'
import {type Language, LANGUAGES, LANGUAGES_MAP_CODE2} from '#/locale/languages'
import {isNative, isWeb} from '#/platform/detection'
import {
toPostLanguages,
useLanguagePrefs,
@@ -21,6 +20,7 @@ import {SearchInput} from '#/components/forms/SearchInput'
import * as Toggle from '#/components/forms/Toggle'
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
import {Text} from '#/components/Typography'
import {IS_NATIVE, IS_WEB} from '#/env'
export function PostLanguageSelectDialog({
control,
@@ -168,7 +168,7 @@ export function DialogInner({
const listHeader = (
<View
style={[a.pb_xs, t.atoms.bg, isNative && a.pt_2xl]}
style={[a.pb_xs, t.atoms.bg, IS_NATIVE && a.pt_2xl]}
onLayout={evt => setHeaderHeight(evt.nativeEvent.layout.height)}>
<View style={[a.flex_row, a.w_full, a.justify_between]}>
<View>
@@ -195,7 +195,7 @@ export function DialogInner({
</Text>
</View>
{isWeb && (
{IS_WEB && (
<Button
variant="ghost"
size="small"
@@ -252,7 +252,7 @@ export function DialogInner({
ListHeaderComponent={listHeader}
stickyHeaderIndices={[0]}
contentContainerStyle={[a.gap_0]}
style={[isNative && a.px_lg, web({paddingBottom: 120})]}
style={[IS_NATIVE && a.px_lg, web({paddingBottom: 120})]}
scrollIndicatorInsets={{top: headerHeight}}
renderItem={({item, index}) => {
if (item.type === 'header') {
@@ -25,13 +25,13 @@ import {isUriImage} from '#/lib/media/util'
import {cleanError} from '#/lib/strings/errors'
import {getMentionAt, insertMentionAt} from '#/lib/strings/mention-manip'
import {useTheme} from '#/lib/ThemeContext'
import {isAndroid, isNative} from '#/platform/detection'
import {
type LinkFacetMatch,
suggestLinkCardUri,
} from '#/view/com/composer/text-input/text-input-util'
import {atoms as a, useAlf} from '#/alf'
import {normalizeTextStyles} from '#/alf/typography'
import {IS_ANDROID, IS_NATIVE} from '#/env'
import {Autocomplete} from './mobile/Autocomplete'
import {type TextInputProps} from './TextInput.types'
@@ -179,14 +179,14 @@ export function TextInput({
/**
* PasteInput doesn't like `lineHeight`, results in jumpiness
*/
if (isNative) {
if (IS_NATIVE) {
style.lineHeight = undefined
}
/*
* Android impl of `PasteInput` doesn't support the array syntax for `fontVariant`
*/
if (isAndroid) {
if (IS_ANDROID) {
// @ts-ignore
style.fontVariant = style.fontVariant
? style.fontVariant.join(' ')
@@ -8,7 +8,6 @@ import deepEqual from 'fast-deep-equal'
import {isNetworkError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {isNative} from '#/platform/detection'
import {usePostInteractionSettingsMutation} from '#/state/queries/post-interaction-settings'
import {createPostgateRecord} from '#/state/queries/postgate/util'
import {usePreferencesQuery} from '#/state/queries/preferences'
@@ -25,6 +24,7 @@ import {Earth_Stroke2_Corner0_Rounded as EarthIcon} from '#/components/icons/Glo
import {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Group'
import * as Tooltip from '#/components/Tooltip'
import {Text} from '#/components/Typography'
import {IS_NATIVE} from '#/env'
import {useThreadgateNudged} from '#/storage/hooks/threadgate-nudged'
export function ThreadgateBtn({
@@ -70,7 +70,7 @@ export function ThreadgateBtn({
nudged: tooltipWasShown,
})
if (isNative && Keyboard.isVisible()) {
if (IS_NATIVE && Keyboard.isVisible()) {
Keyboard.dismiss()
}
@@ -6,7 +6,6 @@ import {useLingui} from '@lingui/react'
import {MAX_ALT_TEXT} from '#/lib/constants'
import {isOverMaxGraphemeCount} from '#/lib/strings/helpers'
import {LANGUAGES} from '#/locale/languages'
import {isWeb} from '#/platform/detection'
import {useLanguagePrefs} from '#/state/preferences'
import {atoms as a, useTheme, web} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
@@ -17,6 +16,7 @@ import {PageText_Stroke2_Corner0_Rounded as PageTextIcon} from '#/components/ico
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning'
import {Text} from '#/components/Typography'
import {IS_WEB} from '#/env'
import {SubtitleFilePicker} from './SubtitleFilePicker'
const MAX_NUM_CAPTIONS = 1
@@ -37,9 +37,9 @@ export function SubtitleDialogBtn(props: Props) {
return (
<View style={[a.flex_row, a.my_xs]}>
<Button
label={isWeb ? _(msg`Captions & alt text`) : _(msg`Alt text`)}
label={IS_WEB ? _(msg`Captions & alt text`) : _(msg`Alt text`)}
accessibilityHint={
isWeb
IS_WEB
? _(msg`Opens captions and alt text dialog`)
: _(msg`Opens alt text dialog`)
}
@@ -52,7 +52,11 @@ export function SubtitleDialogBtn(props: Props) {
}}>
<ButtonIcon icon={CCIcon} />
<ButtonText>
{isWeb ? <Trans>Captions & alt text</Trans> : <Trans>Alt text</Trans>}
{IS_WEB ? (
<Trans>Captions & alt text</Trans>
) : (
<Trans>Alt text</Trans>
)}
</ButtonText>
</Button>
<Dialog.Outer control={control}>
@@ -134,7 +138,7 @@ function SubtitleDialogInner({
</Text>
)}
{isWeb && (
{IS_WEB && (
<>
<View
style={[
@@ -182,7 +186,7 @@ function SubtitleDialogInner({
<View style={web([a.flex_row, a.justify_end])}>
<Button
label={_(msg`Done`)}
size={isWeb ? 'small' : 'large'}
size={IS_WEB ? 'small' : 'large'}
color="primary"
variant="solid"
onPress={() => {
@@ -4,8 +4,8 @@ import ProgressPie from 'react-native-progress/Pie'
import {type ImagePickerAsset} from 'expo-image-picker'
import {clamp} from '#/lib/numbers'
import {isWeb} from '#/platform/detection'
import {atoms as a, useTheme} from '#/alf'
import {IS_WEB} from '#/env'
import {ExternalEmbedRemoveBtn} from '../ExternalEmbedRemoveBtn'
import {VideoTranscodeBackdrop} from './VideoTranscodeBackdrop'
@@ -20,7 +20,7 @@ export function VideoTranscodeProgress({
}) {
const t = useTheme()
if (isWeb) return null
if (IS_WEB) return null
let aspectRatio = asset.width / asset.height
+5 -5
View File
@@ -11,7 +11,6 @@ import {
} from '#/lib/hooks/usePermissions'
import {openCamera, openUnifiedPicker} from '#/lib/media/picker'
import {logger} from '#/logger'
import {isNative} from '#/platform/detection'
import {useCurrentAccountProfile} from '#/state/queries/useCurrentAccountProfile'
import {MAX_IMAGES} from '#/view/com/composer/state/composer'
import {UserAvatar} from '#/view/com/util/UserAvatar'
@@ -22,6 +21,7 @@ import {Camera_Stroke2_Corner0_Rounded as CameraIcon} from '#/components/icons/C
import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image'
import {SubtleHover} from '#/components/SubtleHover'
import {Text} from '#/components/Typography'
import {IS_NATIVE} from '#/env'
export function ComposerPrompt() {
const {_} = useLingui()
@@ -43,7 +43,7 @@ export function ComposerPrompt() {
logger.metric('composerPrompt:gallery:press', {})
// On web, open the composer with the gallery picker auto-opening
if (!isNative) {
if (!IS_NATIVE) {
openComposer({openGallery: true})
return
}
@@ -105,7 +105,7 @@ export function ComposerPrompt() {
return
}
if (isNative && Keyboard.isVisible()) {
if (IS_NATIVE && Keyboard.isVisible()) {
Keyboard.dismiss()
}
@@ -122,7 +122,7 @@ export function ComposerPrompt() {
]
openComposer({
imageUris: isNative ? imageUris : undefined,
imageUris: IS_NATIVE ? imageUris : undefined,
})
} catch (err: any) {
if (!String(err).toLowerCase().includes('cancel')) {
@@ -189,7 +189,7 @@ export function ComposerPrompt() {
<Trans>What's up?</Trans>
</Text>
<View style={[a.flex_row, a.gap_md]}>
{isNative && (
{IS_NATIVE && (
<Button
onPress={e => {
e.stopPropagation()
+4 -4
View File
@@ -20,7 +20,6 @@ import {getRootNavigation, getTabState, TabState} from '#/lib/routes/helpers'
import {type AllNavigatorParams} from '#/lib/routes/types'
import {logEvent} from '#/lib/statsig/statsig'
import {s} from '#/lib/styles'
import {isNative} from '#/platform/detection'
import {listenSoftReset} from '#/state/events'
import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback'
import {useSetHomeBadge} from '#/state/home-badge'
@@ -34,6 +33,7 @@ import {truncateAndInvalidate} from '#/state/queries/util'
import {useSession} from '#/state/session'
import {useSetMinimalShellMode} from '#/state/shell'
import {useHeaderOffset} from '#/components/hooks/useHeaderOffset'
import {IS_NATIVE} from '#/env'
import {PostFeed} from '../posts/PostFeed'
import {FAB} from '../util/fab/FAB'
import {type ListMethods} from '../util/List'
@@ -80,7 +80,7 @@ export function FeedPage({
const feedIsVideoMode =
feedInfo.contentMode === AppBskyFeedDefs.CONTENTMODEVIDEO
const _isVideoFeed = isBskyVideoFeed || feedIsVideoMode
return isNative && _isVideoFeed
return IS_NATIVE && _isVideoFeed
}, [feedInfo])
useEffect(() => {
@@ -91,7 +91,7 @@ export function FeedPage({
const scrollToTop = useCallback(() => {
scrollElRef.current?.scrollToOffset({
animated: isNative,
animated: IS_NATIVE,
offset: -headerOffset,
})
setMinimalShellMode(false)
@@ -136,7 +136,7 @@ export function FeedPage({
})
}, [scrollToTop, feed, queryClient])
const shouldPrefetch = isNative && isPageAdjacent
const shouldPrefetch = IS_NATIVE && isPageAdjacent
const isDiscoverFeed = feedInfo.uri === DISCOVER_FEED_URI
return (
<View
+3 -3
View File
@@ -4,7 +4,6 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {cleanError} from '#/lib/strings/errors'
import {isNative, isWeb} from '#/platform/detection'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {getFeedTypeFromUri} from '#/state/queries/feed'
import {useProfileQuery} from '#/state/queries/profile'
@@ -15,6 +14,7 @@ import {Divider} from '#/components/Divider'
import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning'
import * as ProfileCard from '#/components/ProfileCard'
import {Text} from '#/components/Typography'
import {IS_NATIVE, IS_WEB} from '#/env'
export function MissingFeed({
style,
@@ -83,7 +83,7 @@ export function MissingFeed({
a.italic,
]}
numberOfLines={1}>
{isWeb ? (
{IS_WEB ? (
<Trans>Click for information</Trans>
) : (
<Trans>Tap for information</Trans>
@@ -205,7 +205,7 @@ function DialogInner({
</>
)}
</View>
{isNative && (
{IS_NATIVE && (
<Button
label={_(msg`Close`)}
onPress={() => control.close()}
+4 -4
View File
@@ -20,7 +20,6 @@ import {useQueryClient} from '@tanstack/react-query'
import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {isIOS, isNative, isWeb} from '#/platform/detection'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {RQKEY, useProfileFeedgensQuery} from '#/state/queries/profile-feedgens'
import {useSession} from '#/state/session'
@@ -33,6 +32,7 @@ import {atoms as a, ios, useTheme} from '#/alf'
import * as FeedCard from '#/components/FeedCard'
import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag'
import {ListFooter} from '#/components/Lists'
import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
const LOADING = {_reactKey: '__loading__'}
const EMPTY = {_reactKey: '__empty__'}
@@ -111,7 +111,7 @@ export function ProfileFeedgens({
const onScrollToTop = useCallback(() => {
scrollElRef.current?.scrollToOffset({
animated: isNative,
animated: IS_NATIVE,
offset: -headerOffset,
})
queryClient.invalidateQueries({queryKey: RQKEY(did)})
@@ -194,7 +194,7 @@ export function ProfileFeedgens({
return (
<View
style={[
(index !== 0 || isWeb) && a.border_t,
(index !== 0 || IS_WEB) && a.border_t,
t.atoms.border_contrast_low,
a.px_lg,
a.py_lg,
@@ -218,7 +218,7 @@ export function ProfileFeedgens({
)
useEffect(() => {
if (isIOS && enabled && scrollElRef.current) {
if (IS_IOS && enabled && scrollElRef.current) {
const nativeTag = findNodeHandle(scrollElRef.current)
setScrollViewTag(nativeTag)
}
+5 -5
View File
@@ -41,13 +41,13 @@ import {Trans} from '@lingui/macro'
import {type Dimensions} from '#/lib/media/types'
import {colors, s} from '#/lib/styles'
import {isIOS} from '#/platform/detection'
import {type Lightbox} from '#/state/lightbox'
import {Button} from '#/view/com/util/forms/Button'
import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views'
import {useTheme} from '#/alf'
import {setSystemUITheme} from '#/alf/util/systemUI'
import {IS_IOS} from '#/env'
import {PlatformInfo} from '../../../../../modules/expo-bluesky-swiss-army'
import {type ImageSource, type Transform} from './@types'
import ImageDefaultHeader from './components/ImageDefaultHeader'
@@ -59,13 +59,13 @@ const PORTRAIT_UP = ScreenOrientation.OrientationLock.PORTRAIT_UP
const PIXEL_RATIO = PixelRatio.get()
const SLOW_SPRING: WithSpringConfig = {
mass: isIOS ? 1.25 : 0.75,
mass: IS_IOS ? 1.25 : 0.75,
damping: 300,
stiffness: 800,
restDisplacementThreshold: 0.01,
}
const FAST_SPRING: WithSpringConfig = {
mass: isIOS ? 1.25 : 0.75,
mass: IS_IOS ? 1.25 : 0.75,
damping: 150,
stiffness: 900,
restDisplacementThreshold: 0.01,
@@ -248,7 +248,7 @@ function ImageView({
)
opacity -= dragProgress
}
const factor = isIOS ? 100 : 50
const factor = IS_IOS ? 100 : 50
return {
opacity: Math.round(opacity * factor) / factor,
}
@@ -686,7 +686,7 @@ const styles = StyleSheet.create({
maxHeight: '100%',
},
footerText: {
paddingBottom: isIOS ? 20 : 16,
paddingBottom: IS_IOS ? 20 : 16,
},
footerBtns: {
flexDirection: 'row',
+4 -4
View File
@@ -20,7 +20,6 @@ import {useQueryClient} from '@tanstack/react-query'
import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {isIOS, isNative, isWeb} from '#/platform/detection'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {RQKEY, useProfileListsQuery} from '#/state/queries/profile-lists'
import {useSession} from '#/state/session'
@@ -33,6 +32,7 @@ import {atoms as a, ios, useTheme} from '#/alf'
import {BulletList_Stroke1_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList'
import * as ListCard from '#/components/ListCard'
import {ListFooter} from '#/components/Lists'
import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
const LOADING = {_reactKey: '__loading__'}
const EMPTY = {_reactKey: '__empty__'}
@@ -111,7 +111,7 @@ export function ProfileLists({
const onScrollToTop = useCallback(() => {
scrollElRef.current?.scrollToOffset({
animated: isNative,
animated: IS_NATIVE,
offset: -headerOffset,
})
queryClient.invalidateQueries({queryKey: RQKEY(did)})
@@ -193,7 +193,7 @@ export function ProfileLists({
return (
<View
style={[
(index !== 0 || isWeb) && a.border_t,
(index !== 0 || IS_WEB) && a.border_t,
t.atoms.border_contrast_low,
a.px_lg,
a.py_lg,
@@ -217,7 +217,7 @@ export function ProfileLists({
)
useEffect(() => {
if (isIOS && enabled && scrollElRef.current) {
if (IS_IOS && enabled && scrollElRef.current) {
const nativeTag = findNodeHandle(scrollElRef.current)
setScrollViewTag(nativeTag)
}
+3 -3
View File
@@ -16,19 +16,19 @@ import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {cleanError} from '#/lib/strings/errors'
import {colors, gradients, s} from '#/lib/styles'
import {useTheme} from '#/lib/ThemeContext'
import {isAndroid, isWeb} from '#/platform/detection'
import {useModalControls} from '#/state/modals'
import {useAgent, useSession, useSessionApi} from '#/state/session'
import {atoms as a, useTheme as useNewTheme} from '#/alf'
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
import {Text as NewText} from '#/components/Typography'
import {IS_ANDROID, IS_WEB} from '#/env'
import {resetToTab} from '../../../Navigation'
import {ErrorMessage} from '../util/error/ErrorMessage'
import {Text} from '../util/text/Text'
import * as Toast from '../util/Toast'
import {ScrollView, TextInput} from './util'
export const snapPoints = isAndroid ? ['90%'] : ['55%']
export const snapPoints = IS_ANDROID ? ['90%'] : ['55%']
export function Component({}: {}) {
const pal = usePalette('default')
@@ -173,7 +173,7 @@ export function Component({}: {}) {
</>
)}
<View style={[!isWeb && a.px_xl]}>
<View style={[!IS_WEB && a.px_xl]}>
<View
style={[
a.w_full,
+5 -5
View File
@@ -14,7 +14,6 @@ import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {cleanError} from '#/lib/strings/errors'
import {sanitizeHandle} from '#/lib/strings/handles'
import {s} from '#/lib/styles'
import {isAndroid, isMobileWeb, isWeb} from '#/platform/detection'
import {useModalControls} from '#/state/modals'
import {
getMembership,
@@ -24,6 +23,7 @@ import {
useListMembershipRemoveMutation,
} from '#/state/queries/list-memberships'
import {useSession} from '#/state/session'
import {IS_ANDROID, IS_WEB, IS_WEB_MOBILE} from '#/env'
import {MyLists} from '../lists/MyLists'
import {Button} from '../util/forms/Button'
import {Text} from '../util/text/Text'
@@ -56,9 +56,9 @@ export function Component({
}, [closeModal])
const listStyle = React.useMemo(() => {
if (isMobileWeb) {
if (IS_WEB_MOBILE) {
return [pal.border, {height: screenHeight / 2}]
} else if (isWeb) {
} else if (IS_WEB) {
return [pal.border, {height: screenHeight / 1.5}]
}
@@ -243,7 +243,7 @@ function ListItem({
const styles = StyleSheet.create({
container: {
paddingHorizontal: isWeb ? 0 : 16,
paddingHorizontal: IS_WEB ? 0 : 16,
},
btns: {
position: 'relative',
@@ -252,7 +252,7 @@ const styles = StyleSheet.create({
justifyContent: 'center',
gap: 10,
paddingTop: 10,
paddingBottom: isAndroid ? 10 : 0,
paddingBottom: IS_ANDROID ? 10 : 0,
borderTopWidth: StyleSheet.hairlineWidth,
},
footerBtn: {
+2 -2
View File
@@ -1,7 +1,7 @@
import React, {useContext} from 'react'
import {type SharedValue} from 'react-native-reanimated'
import {isNative} from '#/platform/detection'
import {IS_NATIVE} from '#/env'
export const PagerHeaderContext = React.createContext<{
scrollY: SharedValue<number>
@@ -37,7 +37,7 @@ export function PagerHeaderProvider({
export function usePagerHeaderContext() {
const ctx = useContext(PagerHeaderContext)
if (isNative) {
if (IS_NATIVE) {
if (!ctx) {
throw new Error(
'usePagerHeaderContext must be used within a HeaderProvider',
+3 -3
View File
@@ -18,13 +18,13 @@ import Animated, {
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {ScrollProvider} from '#/lib/ScrollContext'
import {isIOS} from '#/platform/detection'
import {
Pager,
type PagerRef,
type RenderTabBarFnProps,
} from '#/view/com/pager/Pager'
import {useTheme} from '#/alf'
import {IS_IOS} from '#/env'
import {type ListMethods} from '../util/List'
import {PagerHeaderProvider} from './PagerHeaderContext'
import {TabBar} from './TabBar'
@@ -273,11 +273,11 @@ let PagerTabBar = ({
const headerRef = useRef(null)
return (
<Animated.View
pointerEvents={isIOS ? 'auto' : 'box-none'}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}
style={[styles.tabBarMobile, headerTransform, t.atoms.bg]}>
<View
ref={headerRef}
pointerEvents={isIOS ? 'auto' : 'box-none'}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}
collapsable={false}>
{renderHeader?.({setMinimumHeight: setMinimumHeaderHeight})}
{
+2 -2
View File
@@ -13,9 +13,9 @@ import {MagnifyingGlassIcon} from '#/lib/icons'
import {type NavigationProp} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {useFeedFeedbackContext} from '#/state/feed-feedback'
import {useSession} from '#/state/session'
import {IS_WEB} from '#/env'
import {Button} from '../util/forms/Button'
import {Text} from '../util/text/Text'
@@ -44,7 +44,7 @@ export function CustomFeedEmptyState() {
const navigation = useNavigation<NavigationProp>()
const onPressFindAccounts = React.useCallback(() => {
if (isWeb) {
if (IS_WEB) {
navigation.navigate('Search', {})
} else {
navigation.navigate('SearchTab')
+2 -2
View File
@@ -11,7 +11,7 @@ import {usePalette} from '#/lib/hooks/usePalette'
import {MagnifyingGlassIcon} from '#/lib/icons'
import {type NavigationProp} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {isWeb} from '#/platform/detection'
import {IS_WEB} from '#/env'
import {Button} from '../util/forms/Button'
import {Text} from '../util/text/Text'
@@ -21,7 +21,7 @@ export function FollowingEmptyState() {
const navigation = useNavigation<NavigationProp>()
const onPressFindAccounts = React.useCallback(() => {
if (isWeb) {
if (IS_WEB) {
navigation.navigate('Search', {})
} else {
navigation.navigate('SearchTab')
+2 -2
View File
@@ -10,7 +10,7 @@ import {useNavigation} from '@react-navigation/native'
import {usePalette} from '#/lib/hooks/usePalette'
import {type NavigationProp} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {isWeb} from '#/platform/detection'
import {IS_WEB} from '#/env'
import {Button} from '../util/forms/Button'
import {Text} from '../util/text/Text'
@@ -20,7 +20,7 @@ export function FollowingEndOfFeed() {
const navigation = useNavigation<NavigationProp>()
const onPressFindAccounts = React.useCallback(() => {
if (isWeb) {
if (IS_WEB) {
navigation.navigate('Search', {})
} else {
navigation.navigate('SearchTab')
+4 -4
View File
@@ -34,7 +34,6 @@ import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {logEvent, useGate} from '#/lib/statsig/statsig'
import {isNetworkError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {isIOS, isNative, isWeb} from '#/platform/detection'
import {usePostAuthorShadowFilter} from '#/state/cache/profile-shadow'
import {listenPostCreated} from '#/state/events'
import {useFeedFeedbackContext} from '#/state/feed-feedback'
@@ -70,6 +69,7 @@ import {
} from '#/components/feeds/PostFeedVideoGridRow'
import {TrendingInterstitial} from '#/components/interstitials/Trending'
import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interstitials/TrendingVideos'
import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
import {DiscoverFeedLiveEventFeedsAndTrendingBanner} from '#/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner'
import {ComposerPrompt} from '../feeds/ComposerPrompt'
import {DiscoverFallbackHeader} from './DiscoverFallbackHeader'
@@ -243,7 +243,7 @@ let PostFeed = ({
const [feedType, feedUriOrActorDid, feedTab] = feed.split('|')
const {gtMobile} = useBreakpoints()
const {rightNavVisible} = useLayoutBreakpoints()
const areVideoFeedsEnabled = isNative
const areVideoFeedsEnabled = IS_NATIVE
const [hasPressedShowLessUris, setHasPressedShowLessUris] = useState(
() => new Set<string>(),
@@ -873,7 +873,7 @@ let PostFeed = ({
* reach the end, so that content isn't cut off by the bottom of the
* screen.
*/
const offset = Math.max(headerOffset, 32) * (isWeb ? 1 : 2)
const offset = Math.max(headerOffset, 32) * (IS_WEB ? 1 : 2)
return isFetchingNextPage ? (
<View style={[styles.feedFooter]}>
@@ -1024,7 +1024,7 @@ let PostFeed = ({
}
initialNumToRender={initialNumToRenderOverride ?? initialNumToRender}
windowSize={9}
maxToRenderPerBatch={isIOS ? 5 : 1}
maxToRenderPerBatch={IS_IOS ? 5 : 1}
updateCellsBatchingPeriod={40}
onItemSeen={onItemSeen}
/>
+2 -2
View File
@@ -8,13 +8,13 @@ import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
import {type NavigationProp} from '#/lib/routes/types'
import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {useProfileFollowsQuery} from '#/state/queries/profile-follows'
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
import {useSession} from '#/state/session'
import {FindContactsBannerNUX} from '#/components/contacts/FindContactsBannerNUX'
import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2'
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
import {IS_WEB} from '#/env'
import {List} from '../util/List'
import {ProfileCardWithFollowBtn} from './ProfileCard'
@@ -49,7 +49,7 @@ export function ProfileFollows({name}: {name: string}) {
const navigation = useNavigation<NavigationProp>()
const onPressFindAccounts = React.useCallback(() => {
if (isWeb) {
if (IS_WEB) {
navigation.navigate('Search', {})
} else {
navigation.navigate('SearchTab')
+7 -5
View File
@@ -12,7 +12,6 @@ import {type NavigationProp} from '#/lib/routes/types'
import {shareText, shareUrl} from '#/lib/sharing'
import {toShareUrl} from '#/lib/strings/url-helpers'
import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {type Shadow} from '#/state/cache/types'
import {useModalControls} from '#/state/modals'
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
@@ -61,6 +60,7 @@ import * as Prompt from '#/components/Prompt'
import {useFullVerificationState} from '#/components/verification'
import {VerificationCreatePrompt} from '#/components/verification/VerificationCreatePrompt'
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
import {IS_WEB} from '#/env'
import {Dot} from '#/features/nuxs/components/Dot'
import {Gradient} from '#/features/nuxs/components/Gradient'
import {useDevMode} from '#/storage/hooks/dev-mode'
@@ -266,7 +266,7 @@ let ProfileMenu = ({
<Menu.Item
testID="profileHeaderDropdownShareBtn"
label={
isWeb ? _(msg`Copy link to profile`) : _(msg`Share via...`)
IS_WEB ? _(msg`Copy link to profile`) : _(msg`Share via...`)
}
onPress={() => {
if (showLoggedOutWarning) {
@@ -276,13 +276,15 @@ let ProfileMenu = ({
}
}}>
<Menu.ItemText>
{isWeb ? (
{IS_WEB ? (
<Trans>Copy link to profile</Trans>
) : (
<Trans>Share via...</Trans>
)}
</Menu.ItemText>
<Menu.ItemIcon icon={isWeb ? ChainLinkIcon : ArrowOutOfBoxIcon} />
<Menu.ItemIcon
icon={IS_WEB ? ChainLinkIcon : ArrowOutOfBoxIcon}
/>
</Menu.Item>
<Menu.Item
testID="profileHeaderDropdownSearchBtn"
@@ -382,7 +384,7 @@ let ProfileMenu = ({
a.flex_0,
{
color: t.palette.primary_500,
right: isWeb ? -8 : -4,
right: IS_WEB ? -8 : -4,
},
]}>
<Trans>New</Trans>
+4 -4
View File
@@ -25,12 +25,12 @@ import {
linkRequiresWarning,
} from '#/lib/strings/url-helpers'
import {type TypographyVariant} from '#/lib/ThemeContext'
import {isAndroid, isWeb} from '#/platform/detection'
import {emitSoftReset} from '#/state/events'
import {useModalControls} from '#/state/modals'
import {WebAuxClickWrapper} from '#/view/com/util/WebAuxClickWrapper'
import {useTheme} from '#/alf'
import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
import {IS_ANDROID, IS_WEB} from '#/env'
import {router} from '../../../routes'
import {PressableWithHover} from './PressableWithHover'
import {Text} from './text/Text'
@@ -130,7 +130,7 @@ export const Link = memo(function Link({
android_ripple={{
color: t.atoms.bg_contrast_25.backgroundColor,
}}
unstable_pressDelay={isAndroid ? 90 : undefined}>
unstable_pressDelay={IS_ANDROID ? 90 : undefined}>
{/* @ts-ignore web only -prf */}
<View style={style} href={anchorHref}>
{children ? children : <Text>{title || 'link'}</Text>}
@@ -219,7 +219,7 @@ export const TextLink = memo(function TextLink({
})
}
if (
isWeb &&
IS_WEB &&
href !== '#' &&
e != null &&
isModifiedEvent(e as React.MouseEvent)
@@ -323,7 +323,7 @@ export const TextLinkOnWebOnly = memo(function DesktopWebTextLink({
onBeforePress,
...props
}: TextLinkOnWebOnlyProps) {
if (isWeb) {
if (IS_WEB) {
return (
<TextLink
testID={testID}
+3 -3
View File
@@ -11,9 +11,9 @@ import {updateActiveVideoViewAsync} from '@haileyok/bluesky-video'
import {useDedupe} from '#/lib/hooks/useDedupe'
import {useScrollHandlers} from '#/lib/ScrollContext'
import {addStyle} from '#/lib/styles'
import {isIOS} from '#/platform/detection'
import {useLightbox} from '#/state/lightbox'
import {useTheme} from '#/alf'
import {IS_IOS} from '#/env'
import {FlatList_INTERNAL} from './Views'
export type ListMethods = FlatList_INTERNAL
@@ -94,7 +94,7 @@ let List = React.forwardRef<ListMethods, ListProps>(
}
}
if (isIOS) {
if (IS_IOS) {
runOnJS(dedupe)(updateActiveVideoViewAsync)
}
},
@@ -184,7 +184,7 @@ export {List}
// We only want to use this context value on iOS because the `scrollsToTop` prop is iOS-only
// removing it saves us a re-render on Android
const useAllowScrollToTop = isIOS ? useAllowScrollToTopIOS : () => undefined
const useAllowScrollToTop = IS_IOS ? useAllowScrollToTopIOS : () => undefined
function useAllowScrollToTopIOS() {
const {activeLightbox} = useLightbox()
return !activeLightbox
+8 -8
View File
@@ -9,9 +9,9 @@ import {
import EventEmitter from 'eventemitter3'
import {ScrollProvider} from '#/lib/ScrollContext'
import {isNative, isWeb} from '#/platform/detection'
import {useMinimalShellMode} from '#/state/shell'
import {useShellLayout} from '#/state/shell/shell-layout'
import {IS_NATIVE, IS_WEB} from '#/env'
const WEB_HIDE_SHELL_THRESHOLD = 200
@@ -35,7 +35,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
)
useEffect(() => {
if (isWeb) {
if (IS_WEB) {
return listenToForcedWindowScroll(() => {
startDragOffset.set(null)
startMode.set(null)
@@ -48,7 +48,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
(e: NativeScrollEvent) => {
'worklet'
const offsetY = Math.max(0, e.contentOffset.y)
if (isNative) {
if (IS_NATIVE) {
const startDragOffsetValue = startDragOffset.get()
if (startDragOffsetValue === null) {
return
@@ -75,7 +75,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
(e: NativeScrollEvent) => {
'worklet'
const offsetY = Math.max(0, e.contentOffset.y)
if (isNative) {
if (IS_NATIVE) {
startDragOffset.set(offsetY)
startMode.set(headerMode.get())
}
@@ -86,7 +86,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
const onEndDrag = useCallback(
(e: NativeScrollEvent) => {
'worklet'
if (isNative) {
if (IS_NATIVE) {
if (e.velocity && e.velocity.y !== 0) {
// If we detect a velocity, wait for onMomentumEnd to snap.
return
@@ -100,7 +100,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
const onMomentumEnd = useCallback(
(e: NativeScrollEvent) => {
'worklet'
if (isNative) {
if (IS_NATIVE) {
snapToClosestState(e)
}
},
@@ -111,7 +111,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
(e: NativeScrollEvent) => {
'worklet'
const offsetY = Math.max(0, e.contentOffset.y)
if (isNative) {
if (IS_NATIVE) {
const startDragOffsetValue = startDragOffset.get()
const startModeValue = startMode.get()
if (startDragOffsetValue === null || startModeValue === null) {
@@ -177,7 +177,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
const emitter = new EventEmitter()
if (isWeb) {
if (IS_WEB) {
const originalScroll = window.scroll
window.scroll = function () {
emitter.emit('forced-scroll')
+3 -3
View File
@@ -12,7 +12,6 @@ import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {niceDate} from '#/lib/strings/time'
import {isAndroid} from '#/platform/detection'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {precacheProfile} from '#/state/queries/profile'
import {atoms as a, platform, useTheme, web} from '#/alf'
@@ -21,6 +20,7 @@ import {ProfileHoverCard} from '#/components/ProfileHoverCard'
import {Text} from '#/components/Typography'
import {useSimpleVerificationState} from '#/components/verification'
import {VerificationCheck} from '#/components/verification/VerificationCheck'
import {IS_ANDROID} from '#/env'
import {TimeElapsed} from './TimeElapsed'
import {PreviewableUserAvatar} from './UserAvatar'
@@ -152,14 +152,14 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
a.pl_xs,
a.text_md,
a.leading_tight,
isAndroid && a.flex_grow,
IS_ANDROID && a.flex_grow,
a.text_right,
t.atoms.text_contrast_medium,
web({
whiteSpace: 'nowrap',
}),
]}>
{!isAndroid && (
{!IS_ANDROID && (
<Text
style={[
a.text_md,
+7 -7
View File
@@ -30,7 +30,6 @@ import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {isCancelledError} from '#/lib/strings/errors'
import {sanitizeHandle} from '#/lib/strings/handles'
import {logger} from '#/logger'
import {isAndroid, isNative, isWeb} from '#/platform/detection'
import {
type ComposerImage,
compressImage,
@@ -54,6 +53,7 @@ import {LiveStatusDialog} from '#/components/live/LiveStatusDialog'
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
import * as Menu from '#/components/Menu'
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
import {IS_ANDROID, IS_NATIVE, IS_WEB} from '#/env'
import type * as bsky from '#/types/bsky'
export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler'
@@ -88,7 +88,7 @@ interface PreviewableUserAvatarProps extends BaseUserAvatarProps {
onBeforePress?: () => void
}
const BLUR_AMOUNT = isWeb ? 5 : 100
const BLUR_AMOUNT = IS_WEB ? 5 : 100
let DefaultAvatar = ({
type,
@@ -286,7 +286,7 @@ let UserAvatar = ({
}, [size, style])
return avatar &&
!((moderation?.blur && isAndroid) /* android crashes with blur */) ? (
!((moderation?.blur && IS_ANDROID) /* android crashes with blur */) ? (
<View style={containerStyle}>
{usePlainRNImage ? (
<RNImage
@@ -394,7 +394,7 @@ let EditableUserAvatar = ({
}
try {
if (isNative) {
if (IS_NATIVE) {
onSelectNewAvatar(
await compressIfNeeded(
await openCropper({
@@ -464,7 +464,7 @@ let EditableUserAvatar = ({
</Menu.Trigger>
<Menu.Outer showCancel>
<Menu.Group>
{isNative && (
{IS_NATIVE && (
<Menu.Item
testID="changeAvatarCameraBtn"
label={_(msg`Upload from Camera`)}
@@ -481,7 +481,7 @@ let EditableUserAvatar = ({
label={_(msg`Upload from Library`)}
onPress={onOpenLibrary}>
<Menu.ItemText>
{isNative ? (
{IS_NATIVE ? (
<Trans>Upload from Library</Trans>
) : (
<Trans>Upload from Files</Trans>
@@ -571,7 +571,7 @@ let PreviewableUserAvatar = ({
<ProfileHoverCard did={profile.did} disable={disableHoverCard}>
{disableNavigation ? (
avatarEl
) : status.isActive && (isNative || isTouchDevice) ? (
) : status.isActive && (IS_NATIVE || isTouchDevice) ? (
<>
<Button
label={_(
+5 -5
View File
@@ -14,7 +14,6 @@ import {openCamera, openCropper, openPicker} from '#/lib/media/picker'
import {type PickerImage} from '#/lib/media/picker.shared'
import {isCancelledError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {isAndroid, isNative} from '#/platform/detection'
import {
type ComposerImage,
compressImage,
@@ -32,6 +31,7 @@ import {
import {StreamingLive_Stroke2_Corner0_Rounded as LibraryIcon} from '#/components/icons/StreamingLive'
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
import * as Menu from '#/components/Menu'
import {IS_ANDROID, IS_NATIVE} from '#/env'
export function UserBanner({
type,
@@ -75,7 +75,7 @@ export function UserBanner({
}
try {
if (isNative) {
if (IS_NATIVE) {
onSelectNewBanner?.(
await compressIfNeeded(
await openCropper({
@@ -153,7 +153,7 @@ export function UserBanner({
</Menu.Trigger>
<Menu.Outer showCancel>
<Menu.Group>
{isNative && (
{IS_NATIVE && (
<Menu.Item
testID="changeBannerCameraBtn"
label={_(msg`Upload from Camera`)}
@@ -170,7 +170,7 @@ export function UserBanner({
label={_(msg`Upload from Library`)}
onPress={onOpenLibrary}>
<Menu.ItemText>
{isNative ? (
{IS_NATIVE ? (
<Trans>Upload from Library</Trans>
) : (
<Trans>Upload from Files</Trans>
@@ -207,7 +207,7 @@ export function UserBanner({
/>
</>
) : banner &&
!((moderation?.blur && isAndroid) /* android crashes with blur */) ? (
!((moderation?.blur && IS_ANDROID) /* android crashes with blur */) ? (
<Image
testID="userBannerImage"
style={[styles.bannerImage, t.atoms.bg_contrast_25]}
+2 -2
View File
@@ -13,7 +13,7 @@ import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
import {usePalette} from '#/lib/hooks/usePalette'
import {clamp} from '#/lib/numbers'
import {colors, s} from '#/lib/styles'
import {isAndroid} from '#/platform/detection'
import {IS_ANDROID} from '#/env'
import {Text} from './text/Text'
import {FlatList_INTERNAL} from './Views'
@@ -120,7 +120,7 @@ export const ViewSelector = React.forwardRef<
renderItem={renderItemInternal}
ListFooterComponent={ListFooterComponent}
// NOTE sticky header disabled on android due to major performance issues -prf
stickyHeaderIndices={isAndroid ? undefined : STICKY_HEADER_INDICES}
stickyHeaderIndices={IS_ANDROID ? undefined : STICKY_HEADER_INDICES}
onScroll={onScroll}
onEndReached={onEndReached}
refreshControl={
+2 -2
View File
@@ -12,9 +12,9 @@ import {PressableScale} from '#/lib/custom-animations/PressableScale'
import {useHaptics} from '#/lib/haptics'
import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
import {clamp} from '#/lib/numbers'
import {isWeb} from '#/platform/detection'
import {ios, useBreakpoints, useTheme} from '#/alf'
import {atoms as a} from '#/alf'
import {IS_WEB} from '#/env'
export interface FABProps extends ComponentProps<typeof Pressable> {
testID?: string
@@ -84,7 +84,7 @@ const styles = StyleSheet.create({
},
outer: {
// @ts-ignore web-only
position: isWeb ? 'fixed' : 'absolute',
position: IS_WEB ? 'fixed' : 'absolute',
zIndex: 1,
cursor: 'pointer',
},
@@ -5,8 +5,8 @@ import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
import {useIsKeyboardVisible} from '#/lib/hooks/useIsKeyboardVisible'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {isWeb} from '#/platform/detection'
import {atoms as a} from '#/alf'
import {IS_WEB} from '#/env'
import {Text} from '../text/Text'
export const LoggedOutLayout = ({
@@ -79,7 +79,7 @@ export const LoggedOutLayout = ({
contentContainerStyle={styles.scrollViewContentContainer}
keyboardShouldPersistTaps="handled"
keyboardDismissMode="on-drag">
<View style={[styles.contentWrapper, isWeb && a.my_auto]}>
<View style={[styles.contentWrapper, IS_WEB && a.my_auto]}>
{children}
</View>
</ScrollView>
+3 -3
View File
@@ -5,13 +5,13 @@ import {UITextView} from 'react-native-uitextview'
import {lh, s} from '#/lib/styles'
import {type TypographyVariant, useTheme} from '#/lib/ThemeContext'
import {logger} from '#/logger'
import {isIOS, isWeb} from '#/platform/detection'
import {applyFonts, useAlf} from '#/alf'
import {
childHasEmoji,
renderChildrenWithEmoji,
type StringChild,
} from '#/alf/typography'
import {IS_IOS, IS_WEB} from '#/env'
export type CustomTextProps = Omit<TextProps, 'children'> & {
type?: TypographyVariant
@@ -81,10 +81,10 @@ function Text_DEPRECATED({
}
return {
uiTextView: selectable && isIOS,
uiTextView: selectable && IS_IOS,
selectable,
style: flattened,
dataSet: isWeb
dataSet: IS_WEB
? Object.assign({tooltip: title}, dataSet || {})
: undefined,
...props,