···11import {StyleSheet} from 'react-native'
22import type React from 'react'
3344-import {isHighDPI} from '#/lib/browser'
54import {atoms as a, platform, useTheme, type ViewStyleProp} from '#/alf'
65import {Fill} from '#/components/Fill'
66+import {IS_HIGH_DPI} from '#/env'
7788/**
99 * Applies and thin border within a bounding box. Used to contrast media from
···3333 // while we generally use hairlineWidth (aka 1px),
3434 // we make an exception here for high DPI screens
3535 // as the 1px border is very noticeable -sfn
3636- web: isHighDPI ? 0.5 : StyleSheet.hairlineWidth,
3636+ web: IS_HIGH_DPI ? 0.5 : StyleSheet.hairlineWidth,
3737 }),
3838 },
3939 opaque
···33import {msg} from '@lingui/macro'
44import {useLingui} from '@lingui/react'
5566-import {isFirefox, isTouchDevice} from '#/lib/browser'
76import {clamp} from '#/lib/numbers'
87import {atoms as a, useTheme, web} from '#/alf'
98import {useInteractionState} from '#/components/hooks/useInteractionState'
99+import {IS_WEB_FIREFOX, IS_WEB_TOUCH_DEVICE} from '#/env'
1010import {formatTime} from './utils'
11111212export function Scrubber({
···100100 // a pointerUp event is fired outside the element that captured the
101101 // pointer. Firefox clicks on the element the mouse is over, so we have
102102 // to make everything unclickable while seeking -sfn
103103- if (isFirefox && scrubberActive) {
103103+ if (IS_WEB_FIREFOX && scrubberActive) {
104104 document.body.classList.add('force-no-clicks')
105105106106 return () => {
···151151 <View
152152 testID="scrubber"
153153 style={[
154154- {height: isTouchDevice ? 32 : 18, width: '100%'},
154154+ {height: IS_WEB_TOUCH_DEVICE ? 32 : 18, width: '100%'},
155155 a.flex_shrink_0,
156156 a.px_xs,
157157 ]}
···11import {type RefObject, useCallback, useEffect, useRef, useState} from 'react'
2233-import {isSafari} from '#/lib/browser'
43import {logger} from '#/logger'
54import {useVideoVolumeState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
55+import {IS_WEB_SAFARI} from '#/env'
6677export function useVideoElement(ref: RefObject<HTMLVideoElement | null>) {
88 const [playing, setPlaying] = useState(false)
···4141 setCurrentTime(round(ref.current.currentTime) || 0)
4242 // HACK: Safari randomly fires `stalled` events when changing between segments
4343 // let's just clear the buffering state if the video is still progressing -sfn
4444- if (isSafari) {
4444+ if (IS_WEB_SAFARI) {
4545 if (bufferingTimeout) clearTimeout(bufferingTimeout)
4646 setBuffering(false)
4747 }
···1111import {msg} from '@lingui/macro'
1212import {useLingui} from '@lingui/react'
13131414-import {isFirefox} from '#/lib/browser'
1514import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
1615import {atoms as a, useTheme} from '#/alf'
1716import {useIsWithinMessage} from '#/components/dms/MessageContext'
···2322 VideoEmbedInnerWeb,
2423 VideoNotFoundError,
2524} from '#/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerWeb'
2525+import {IS_WEB_FIREFOX} from '#/env'
2626import {useActiveVideoWeb} from './ActiveVideoWebContext'
2727import * as VideoFallback from './VideoEmbedInner/VideoFallback'
2828···37373838 useEffect(() => {
3939 if (!ref.current) return
4040- if (isFullscreen && !isFirefox) return
4040+ if (isFullscreen && !IS_WEB_FIREFOX) return
4141 const observer = new IntersectionObserver(
4242 entries => {
4343 const entry = entries[0]
···150150 // observing a div of 100vh height
151151 useEffect(() => {
152152 if (!ref.current) return
153153- if (isFullscreen && !isFirefox) return
153153+ if (isFullscreen && !IS_WEB_FIREFOX) return
154154 const observer = new IntersectionObserver(
155155 entries => {
156156 const entry = entries[0]
+2-2
src/components/ProfileHoverCard/index.web.tsx
···1111import {useNavigation} from '@react-navigation/native'
12121313import {useActorStatus} from '#/lib/actor-status'
1414-import {isTouchDevice} from '#/lib/browser'
1514import {getModerationCauseKey} from '#/lib/moderation'
1615import {makeProfileLink} from '#/lib/routes/links'
1716import {type NavigationProp} from '#/lib/routes/types'
···4342import {Text} from '#/components/Typography'
4443import {useSimpleVerificationState} from '#/components/verification'
4544import {VerificationCheck} from '#/components/verification/VerificationCheck'
4545+import {IS_WEB_TOUCH_DEVICE} from '#/env'
4646import {type ProfileHoverCardProps} from './types'
47474848const floatingMiddlewares = [
···7070 }
7171 }
72727373- if (props.disable || isTouchDevice) {
7373+ if (props.disable || IS_WEB_TOUCH_DEVICE) {
7474 return props.children
7575 } else {
7676 return (
+2-3
src/components/SubtleHover.tsx
···11import {View} from 'react-native'
2233-import {isTouchDevice} from '#/lib/browser'
43import {atoms as a, useTheme, type ViewStyleProp} from '#/alf'
55-import {IS_NATIVE, IS_WEB} from '#/env'
44+import {IS_NATIVE, IS_WEB, IS_WEB_TOUCH_DEVICE} from '#/env'
6576export function SubtleHover({
87 style,
···4039 )
41404241 if (IS_WEB && web) {
4343- return isTouchDevice ? null : el
4242+ return IS_WEB_TOUCH_DEVICE ? null : el
4443 } else if (IS_NATIVE && native) {
4544 return el
4645 }
+2-3
src/components/hooks/useFullscreen.ts
···66 useSyncExternalStore,
77} from 'react'
8899-import {isFirefox, isSafari} from '#/lib/browser'
1010-import {IS_WEB} from '#/env'
99+import {IS_WEB, IS_WEB_FIREFOX, IS_WEB_SAFARI} from '#/env'
11101211function fullscreenSubscribe(onChange: () => void) {
1312 document.addEventListener('fullscreenchange', onChange)
···39384039 // Chrome has an issue where it doesn't scroll back to the top after exiting fullscreen
4140 // Let's play it safe and do it if not FF or Safari, since anything else will probably be chromium
4242- if (prevIsFullscreen && !isFirefox && !isSafari) {
4141+ if (prevIsFullscreen && !IS_WEB_FIREFOX && !IS_WEB_SAFARI) {
4342 setTimeout(() => {
4443 if (scrollYRef.current !== null) {
4544 window.scrollTo(0, scrollYRef.current)
···66import TextareaAutosize from 'react-textarea-autosize'
77import {countGraphemes} from 'unicode-segmenter/grapheme'
8899-import {isSafari, isTouchDevice} from '#/lib/browser'
109import {MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants'
1110import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
1211import {
···2423import {useSharedInputStyles} from '#/components/forms/TextField'
2524import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji'
2625import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane'
2626+import {IS_WEB_SAFARI, IS_WEB_TOUCH_DEVICE} from '#/env'
2727import {useExtractEmbedFromFacets} from './MessageInputEmbed'
28282929export function MessageInput({
···8585 // far too long of a delay, and a subsequent enter press would often just end up doing nothing. A shorter time
8686 // frame was also not great, since it was too short to be reliable (i.e. an older system might have a larger
8787 // time gap between the two events firing.
8888- if (isSafari && e.key === 'Enter' && e.keyCode === 229) {
8888+ if (IS_WEB_SAFARI && e.key === 'Enter' && e.keyCode === 229) {
8989 return
9090 }
9191···228228 onChange={onChange}
229229 // On mobile web phones, we want to keep the same behavior as the native app. Do not submit the message
230230 // in these cases.
231231- onKeyDown={isTouchDevice && isMobile ? undefined : onKeyDown}
231231+ onKeyDown={IS_WEB_TOUCH_DEVICE && isMobile ? undefined : onKeyDown}
232232 />
233233 <Pressable
234234 accessibilityRole="button"