deer social fork for personal usage. but you might see a use idk. github mirror
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge remote-tracking branch 'upstream/main'

ayla bd6f11fc c8d773b9

+3429 -2019
+3 -5
package.json
··· 123 123 "array.prototype.findlast": "^1.2.3", 124 124 "await-lock": "^2.2.2", 125 125 "babel-plugin-transform-remove-console": "^6.9.4", 126 - "base64-js": "^1.5.1", 127 126 "bcp-47": "^2.1.0", 128 127 "bcp-47-match": "^2.0.3", 129 128 "date-fns": "^2.30.0", ··· 213 212 "react-native-web-webview": "^1.0.2", 214 213 "react-native-webview": "^13.13.5", 215 214 "react-remove-scroll-bar": "^2.3.8", 216 - "react-responsive": "^9.0.2", 215 + "react-responsive": "^10.0.1", 217 216 "react-textarea-autosize": "^8.5.3", 218 217 "sonner": "^2.0.7", 219 218 "sonner-native": "^0.21.0", ··· 245 244 "@types/lodash.isequal": "^4.5.6", 246 245 "@types/lodash.shuffle": "^4.2.7", 247 246 "@types/psl": "^1.1.1", 248 - "@types/react-dom": "^19.1.2", 249 - "@types/react-responsive": "^8.0.5", 247 + "@types/react": "^19.1.12", 248 + "@types/react-dom": "^19.1.8", 250 249 "@typescript-eslint/eslint-plugin": "^7.18.0", 251 250 "@typescript-eslint/parser": "^7.18.0", 252 251 "babel-jest": "^29.7.0", ··· 284 283 "@expo/image-utils": "0.6.3", 285 284 "@react-native/babel-preset": "0.79.3", 286 285 "@react-native/normalize-colors": "0.79.3", 287 - "@types/react": "^18", 288 286 "**/expo-constants": "17.0.3", 289 287 "**/expo-device": "7.1.4", 290 288 "**/zod": "3.23.8",
+13
patches/@discord+bottom-sheet+4.6.1.patch
··· 1 + diff --git a/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts b/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts 2 + index 1c788ab..d30f330 100644 3 + --- a/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts 4 + +++ b/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts 5 + @@ -6,7 +6,7 @@ type Callback = (...args: any[]) => any; 6 + * https://gist.github.com/JakeCoxon/c7ebf6e6496f8468226fd36b596e1985 7 + */ 8 + export const useStableCallback = (callback: Callback) => { 9 + - const callbackRef = useRef<Callback>(); 10 + + const callbackRef = useRef<Callback>(undefined); 11 + const memoCallback = useCallback( 12 + (...args: any) => callbackRef.current && callbackRef.current(...args), 13 + []
+3 -3
src/Navigation.tsx
··· 1 - import {useCallback, useRef} from 'react' 1 + import {type JSX, useCallback, useRef} from 'react' 2 2 import {i18n, type MessageDescriptor} from '@lingui/core' 3 3 import {msg} from '@lingui/macro' 4 4 import { ··· 55 55 import {PrivacyPolicyScreen} from '#/view/screens/PrivacyPolicy' 56 56 import {ProfileScreen} from '#/view/screens/Profile' 57 57 import {ProfileFeedLikedByScreen} from '#/view/screens/ProfileFeedLikedBy' 58 - import {ProfileListScreen} from '#/view/screens/ProfileList' 59 - import {SavedFeeds} from '#/view/screens/SavedFeeds' 60 58 import {Storybook} from '#/view/screens/Storybook' 61 59 import {SupportScreen} from '#/view/screens/Support' 62 60 import {TermsOfServiceScreen} from '#/view/screens/TermsOfService' ··· 83 81 import {ProfileFollowsScreen} from '#/screens/Profile/ProfileFollows' 84 82 import {ProfileLabelerLikedByScreen} from '#/screens/Profile/ProfileLabelerLikedBy' 85 83 import {ProfileSearchScreen} from '#/screens/Profile/ProfileSearch' 84 + import {ProfileListScreen} from '#/screens/ProfileList' 85 + import {SavedFeeds} from '#/screens/SavedFeeds' 86 86 import {SearchScreen} from '#/screens/Search' 87 87 import {AboutSettingsScreen} from '#/screens/Settings/AboutSettings' 88 88 import {AccessibilitySettingsScreen} from '#/screens/Settings/AccessibilitySettings'
+1 -1
src/Splash.tsx
··· 15 15 withTiming, 16 16 } from 'react-native-reanimated' 17 17 import {useSafeAreaInsets} from 'react-native-safe-area-context' 18 - import Svg, {Path, SvgProps} from 'react-native-svg' 18 + import Svg, {Path, type SvgProps} from 'react-native-svg' 19 19 import {Image} from 'expo-image' 20 20 import * as SplashScreen from 'expo-splash-screen' 21 21
+1 -1
src/alf/types.ts
··· 1 - import {StyleProp, TextStyle, ViewStyle} from 'react-native' 1 + import {type StyleProp, type TextStyle, type ViewStyle} from 'react-native' 2 2 3 3 export type TextStyleProp = { 4 4 style?: StyleProp<TextStyle>
-1
src/alf/typography.tsx
··· 3 3 import {type StyleProp, type TextStyle} from 'react-native' 4 4 import {UITextView} from 'react-native-uitextview' 5 5 import createEmojiRegex from 'emoji-regex' 6 - import type React from 'react' 7 6 8 7 import {isNative} from '#/platform/detection' 9 8 import {isIOS} from '#/platform/detection'
+1 -1
src/alf/util/themeSelector.ts
··· 1 - import {ThemeName} from '#/alf/types' 1 + import {type ThemeName} from '#/alf/types' 2 2 3 3 export function select<T>(name: ThemeName, options: Record<ThemeName, T>) { 4 4 switch (name) {
+2 -2
src/alf/util/useColorModeTheme.ts
··· 1 1 import React from 'react' 2 - import {ColorSchemeName, useColorScheme} from 'react-native' 2 + import {type ColorSchemeName, useColorScheme} from 'react-native' 3 3 4 4 import {isWeb} from '#/platform/detection' 5 5 import {useThemePrefs} from '#/state/shell' 6 6 import {dark, dim, light} from '#/alf/themes' 7 - import {ThemeName} from '#/alf/types' 7 + import {type ThemeName} from '#/alf/types' 8 8 9 9 export function useColorModeTheme(): ThemeName { 10 10 const theme = useThemeName()
+1 -1
src/alf/util/useGutters.ts
··· 1 1 import React from 'react' 2 2 3 - import {Breakpoint, useBreakpoints} from '#/alf/breakpoints' 3 + import {type Breakpoint, useBreakpoints} from '#/alf/breakpoints' 4 4 import * as tokens from '#/alf/tokens' 5 5 6 6 type Gutter = 'compact' | 'base' | 'wide' | 0
+2 -2
src/components/Button.tsx
··· 71 71 export type ButtonContext = VariantProps & ButtonState 72 72 73 73 type NonTextElements = 74 - | React.ReactElement 75 - | Iterable<React.ReactElement | null | undefined | boolean> 74 + | React.ReactElement<any> 75 + | Iterable<React.ReactElement<any> | null | undefined | boolean> 76 76 77 77 export type ButtonProps = Pick< 78 78 PressableProps,
+2 -1
src/components/ContextMenu/index.tsx
··· 119 119 const hoverablesSV = useSharedValue< 120 120 Record<string, {id: string; rect: Measurement}> 121 121 >({}) 122 - const syncHoverablesThrottleRef = useRef<ReturnType<typeof setTimeout>>() 122 + const syncHoverablesThrottleRef = 123 + useRef<ReturnType<typeof setTimeout>>(undefined) 123 124 const [hoveredMenuItem, setHoveredMenuItem] = useState<string | null>(null) 124 125 125 126 const onHoverableTouchUp = useCallback((id: string) => {
-1
src/components/ContextMenu/types.ts
··· 5 5 type ViewStyle, 6 6 } from 'react-native' 7 7 import {type SharedValue} from 'react-native-reanimated' 8 - import type React from 'react' 9 8 10 9 import type * as Dialog from '#/components/Dialog' 11 10 import {
+1 -2
src/components/Dialog/types.ts
··· 5 5 type StyleProp, 6 6 type ViewStyle, 7 7 } from 'react-native' 8 - import type React from 'react' 9 8 10 9 import {type ViewStyleProp} from '#/alf' 11 10 import {type BottomSheetViewProps} from '../../../modules/bottom-sheet' ··· 34 33 */ 35 34 export type DialogControlProps = DialogControlRefProps & { 36 35 id: string 37 - ref: React.RefObject<DialogControlRefProps> 36 + ref: React.RefObject<DialogControlRefProps | null> 38 37 isOpen?: boolean 39 38 } 40 39
+1 -1
src/components/Dialog/utils.ts
··· 1 1 import React from 'react' 2 2 3 - import {DialogControlProps} from '#/components/Dialog/types' 3 + import {type DialogControlProps} from '#/components/Dialog/types' 4 4 5 5 export function useAutoOpen(control: DialogControlProps, showTimeout?: number) { 6 6 React.useEffect(() => {
+2 -2
src/components/Fill.tsx
··· 1 - import React from 'react' 2 1 import {View} from 'react-native' 2 + import type React from 'react' 3 3 4 - import {atoms as a, ViewStyleProp} from '#/alf' 4 + import {atoms as a, type ViewStyleProp} from '#/alf' 5 5 6 6 export function Fill({ 7 7 children,
+1 -1
src/components/GradientFill.tsx
··· 1 1 import {LinearGradient} from 'expo-linear-gradient' 2 2 3 - import {atoms as a, tokens, ViewStyleProp} from '#/alf' 3 + import {atoms as a, type tokens, type ViewStyleProp} from '#/alf' 4 4 5 5 export function GradientFill({ 6 6 gradient,
+4 -4
src/components/IconCircle.tsx
··· 3 3 import { 4 4 atoms as a, 5 5 flatten, 6 - TextStyleProp, 6 + type TextStyleProp, 7 7 useTheme, 8 - ViewStyleProp, 8 + type ViewStyleProp, 9 9 } from '#/alf' 10 - import {Props} from '#/components/icons/common' 11 - import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth' 10 + import {type Props} from '#/components/icons/common' 11 + import {type Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth' 12 12 13 13 export function IconCircle({ 14 14 icon: Icon,
+4 -4
src/components/LabelingServiceCard/index.tsx
··· 1 - import React from 'react' 2 1 import {View} from 'react-native' 3 - import {AppBskyLabelerDefs} from '@atproto/api' 2 + import {type AppBskyLabelerDefs} from '@atproto/api' 4 3 import {msg, Plural, Trans} from '@lingui/macro' 5 4 import {useLingui} from '@lingui/react' 5 + import type React from 'react' 6 6 7 7 import {getLabelingServiceTitle} from '#/lib/moderation' 8 8 import {sanitizeHandle} from '#/lib/strings/handles' 9 9 import {useLabelerInfoQuery} from '#/state/queries/labeler' 10 10 import {UserAvatar} from '#/view/com/util/UserAvatar' 11 - import {atoms as a, useTheme, ViewStyleProp} from '#/alf' 11 + import {atoms as a, useTheme, type ViewStyleProp} from '#/alf' 12 12 import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag' 13 - import {Link as InternalLink, LinkProps} from '#/components/Link' 13 + import {Link as InternalLink, type LinkProps} from '#/components/Link' 14 14 import {RichText} from '#/components/RichText' 15 15 import {Text} from '#/components/Typography' 16 16 import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '../icons/Chevron'
+1 -1
src/components/LikedByList.tsx
··· 1 1 import React from 'react' 2 - import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api' 2 + import {type AppBskyFeedGetLikes as GetLikes} from '@atproto/api' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5
+2 -2
src/components/LinearGradientBackground.tsx
··· 1 - import React from 'react' 2 - import {StyleProp, ViewStyle} from 'react-native' 1 + import {type StyleProp, type ViewStyle} from 'react-native' 3 2 import {LinearGradient} from 'expo-linear-gradient' 3 + import type React from 'react' 4 4 5 5 import {gradients} from '#/alf/tokens' 6 6
-1
src/components/Lists.tsx
··· 2 2 import {type StyleProp, View, type ViewStyle} from 'react-native' 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 - import type React from 'react' 6 5 7 6 import {cleanError} from '#/lib/strings/errors' 8 7 import {CenteredView} from '#/view/com/util/Views'
+1 -1
src/components/Loader.tsx
··· 8 8 } from 'react-native-reanimated' 9 9 10 10 import {atoms as a, flatten, useTheme} from '#/alf' 11 - import {Props, useCommonSVGProps} from '#/components/icons/common' 11 + import {type Props, useCommonSVGProps} from '#/components/icons/common' 12 12 import {Loader_Stroke2_Corner0_Rounded as Icon} from '#/components/icons/Loader' 13 13 14 14 export function Loader(props: Props) {
+1 -1
src/components/Loader.web.tsx
··· 1 1 import {View} from 'react-native' 2 2 3 3 import {atoms as a, flatten, useTheme} from '#/alf' 4 - import {Props, useCommonSVGProps} from '#/components/icons/common' 4 + import {type Props, useCommonSVGProps} from '#/components/icons/common' 5 5 import {Loader_Stroke2_Corner0_Rounded as Icon} from '#/components/icons/Loader' 6 6 7 7 export function Loader(props: Props) {
+2 -2
src/components/MediaInsetBorder.tsx
··· 1 - import React from 'react' 1 + import type React from 'react' 2 2 3 - import {atoms as a, useTheme, ViewStyleProp} from '#/alf' 3 + import {atoms as a, useTheme, type ViewStyleProp} from '#/alf' 4 4 import {Fill} from '#/components/Fill' 5 5 6 6 /**
+8 -8
src/components/Menu/types.ts
··· 1 - import React from 'react' 2 1 import { 3 - AccessibilityProps, 4 - AccessibilityRole, 5 - GestureResponderEvent, 6 - PressableProps, 2 + type AccessibilityProps, 3 + type AccessibilityRole, 4 + type GestureResponderEvent, 5 + type PressableProps, 7 6 } from 'react-native' 7 + import type React from 'react' 8 8 9 - import {TextStyleProp, ViewStyleProp} from '#/alf' 10 - import * as Dialog from '#/components/Dialog' 11 - import {Props as SVGIconProps} from '#/components/icons/common' 9 + import {type TextStyleProp, type ViewStyleProp} from '#/alf' 10 + import type * as Dialog from '#/components/Dialog' 11 + import {type Props as SVGIconProps} from '#/components/icons/common' 12 12 13 13 export type ContextType = { 14 14 control: Dialog.DialogOuterProps['control']
+111 -101
src/components/NewskieDialog.tsx
··· 1 - import React from 'react' 1 + import {useMemo, useState} from 'react' 2 2 import {View} from 'react-native' 3 - import {AppBskyActorDefs, moderateProfile} from '@atproto/api' 3 + import {type AppBskyActorDefs, moderateProfile} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 import {differenceInSeconds} from 'date-fns' ··· 27 27 disabled?: boolean 28 28 }) { 29 29 const {_} = useLingui() 30 - const t = useTheme() 31 - const moderationOpts = useModerationOpts() 32 - const {currentAccount} = useSession() 33 - const timeAgo = useGetTimeAgo() 34 30 const control = useDialogControl() 35 31 36 - const isMe = profile.did === currentAccount?.did 37 32 const createdAt = profile.createdAt as string | undefined 38 33 39 - const profileName = React.useMemo(() => { 40 - const name = profile.displayName || profile.handle 41 - 42 - if (isMe) { 43 - return _(msg`You`) 44 - } 45 - 46 - if (!moderationOpts) return name 47 - const moderation = moderateProfile(profile, moderationOpts) 48 - 49 - return sanitizeDisplayName(name, moderation.ui('displayName')) 50 - }, [_, isMe, moderationOpts, profile]) 51 - 52 - const [now] = React.useState(() => Date.now()) 53 - const daysOld = React.useMemo(() => { 34 + const [now] = useState(() => Date.now()) 35 + const daysOld = useMemo(() => { 54 36 if (!createdAt) return Infinity 55 37 return differenceInSeconds(now, new Date(createdAt)) / 86400 56 38 }, [createdAt, now]) ··· 77 59 )} 78 60 </Button> 79 61 80 - <Dialog.Outer control={control}> 62 + <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> 81 63 <Dialog.Handle /> 82 - <Dialog.ScrollableInner 83 - label={_(msg`New user info dialog`)} 84 - style={web({width: 'auto', maxWidth: 400, minWidth: 200})}> 85 - <View style={[a.gap_md]}> 86 - <View style={[a.align_center]}> 87 - <View 88 - style={[ 89 - { 90 - height: 60, 91 - width: 64, 92 - }, 93 - ]}> 94 - <Newskie 95 - width={64} 96 - height={64} 97 - fill="#FFC404" 98 - style={[a.absolute, a.inset_0]} 99 - /> 100 - </View> 101 - <Text style={[a.font_bold, a.text_xl]}> 102 - {isMe ? ( 103 - <Trans>Welcome, friend!</Trans> 104 - ) : ( 105 - <Trans>Say hello!</Trans> 106 - )} 107 - </Text> 108 - </View> 109 - <Text style={[a.text_md, a.text_center, a.leading_snug]}> 110 - {profile.joinedViaStarterPack ? ( 111 - <Trans> 112 - {profileName} joined Bluesky using a starter pack{' '} 113 - {timeAgo(createdAt, now, {format: 'long'})} ago 114 - </Trans> 115 - ) : ( 116 - <Trans> 117 - {profileName} joined Bluesky{' '} 118 - {timeAgo(createdAt, now, {format: 'long'})} ago 119 - </Trans> 120 - )} 121 - </Text> 122 - {profile.joinedViaStarterPack ? ( 123 - <StarterPackCard.Link 124 - starterPack={profile.joinedViaStarterPack} 125 - onPress={() => { 126 - control.close() 127 - }}> 128 - <View 129 - style={[ 130 - a.w_full, 131 - a.mt_sm, 132 - a.p_lg, 133 - a.border, 134 - a.rounded_sm, 135 - t.atoms.border_contrast_low, 136 - ]}> 137 - <StarterPackCard.Card 138 - starterPack={profile.joinedViaStarterPack} 139 - /> 140 - </View> 141 - </StarterPackCard.Link> 142 - ) : null} 64 + <DialogInner profile={profile} createdAt={createdAt} now={now} /> 65 + </Dialog.Outer> 66 + </View> 67 + ) 68 + } 143 69 144 - {isNative && ( 145 - <Button 146 - label={_(msg`Close`)} 147 - variant="solid" 148 - color="secondary" 149 - size="small" 150 - style={[a.mt_sm]} 151 - onPress={() => control.close()}> 152 - <ButtonText> 153 - <Trans>Close</Trans> 154 - </ButtonText> 155 - </Button> 156 - )} 70 + function DialogInner({ 71 + profile, 72 + createdAt, 73 + now, 74 + }: { 75 + profile: AppBskyActorDefs.ProfileViewDetailed 76 + createdAt: string 77 + now: number 78 + }) { 79 + const control = Dialog.useDialogContext() 80 + const {_} = useLingui() 81 + const t = useTheme() 82 + const moderationOpts = useModerationOpts() 83 + const {currentAccount} = useSession() 84 + const timeAgo = useGetTimeAgo() 85 + const isMe = profile.did === currentAccount?.did 86 + 87 + const profileName = useMemo(() => { 88 + const name = profile.displayName || profile.handle 89 + 90 + if (isMe) { 91 + return _(msg`You`) 92 + } 93 + 94 + if (!moderationOpts) return name 95 + const moderation = moderateProfile(profile, moderationOpts) 96 + 97 + return sanitizeDisplayName(name, moderation.ui('displayName')) 98 + }, [_, isMe, moderationOpts, profile]) 99 + 100 + return ( 101 + <Dialog.ScrollableInner 102 + label={_(msg`New user info dialog`)} 103 + style={web({maxWidth: 400})}> 104 + <View style={[a.gap_md]}> 105 + <View style={[a.align_center]}> 106 + <View 107 + style={[ 108 + { 109 + height: 60, 110 + width: 64, 111 + }, 112 + ]}> 113 + <Newskie 114 + width={64} 115 + height={64} 116 + fill="#FFC404" 117 + style={[a.absolute, a.inset_0]} 118 + /> 157 119 </View> 120 + <Text style={[a.font_bold, a.text_xl]}> 121 + {isMe ? <Trans>Welcome, friend!</Trans> : <Trans>Say hello!</Trans>} 122 + </Text> 123 + </View> 124 + <Text style={[a.text_md, a.text_center, a.leading_snug]}> 125 + {profile.joinedViaStarterPack ? ( 126 + <Trans> 127 + {profileName} joined Bluesky using a starter pack{' '} 128 + {timeAgo(createdAt, now, {format: 'long'})} ago 129 + </Trans> 130 + ) : ( 131 + <Trans> 132 + {profileName} joined Bluesky{' '} 133 + {timeAgo(createdAt, now, {format: 'long'})} ago 134 + </Trans> 135 + )} 136 + </Text> 137 + {profile.joinedViaStarterPack ? ( 138 + <StarterPackCard.Link 139 + starterPack={profile.joinedViaStarterPack} 140 + onPress={() => control.close()}> 141 + <View 142 + style={[ 143 + a.w_full, 144 + a.mt_sm, 145 + a.p_lg, 146 + a.border, 147 + a.rounded_sm, 148 + t.atoms.border_contrast_low, 149 + ]}> 150 + <StarterPackCard.Card 151 + starterPack={profile.joinedViaStarterPack} 152 + /> 153 + </View> 154 + </StarterPackCard.Link> 155 + ) : null} 158 156 159 - <Dialog.Close /> 160 - </Dialog.ScrollableInner> 161 - </Dialog.Outer> 162 - </View> 157 + {isNative && ( 158 + <Button 159 + label={_(msg`Close`)} 160 + color="secondary" 161 + size="small" 162 + style={[a.mt_sm]} 163 + onPress={() => control.close()}> 164 + <ButtonText> 165 + <Trans>Close</Trans> 166 + </ButtonText> 167 + </Button> 168 + )} 169 + </View> 170 + 171 + <Dialog.Close /> 172 + </Dialog.ScrollableInner> 163 173 ) 164 174 }
+2 -2
src/components/Pills.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 - import {BSKY_LABELER_DID, ModerationCause} from '@atproto/api' 3 + import {BSKY_LABELER_DID, type ModerationCause} from '@atproto/api' 4 4 import {Trans} from '@lingui/macro' 5 5 6 6 import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' 7 7 import {UserAvatar} from '#/view/com/util/UserAvatar' 8 - import {atoms as a, useTheme, ViewStyleProp} from '#/alf' 8 + import {atoms as a, useTheme, type ViewStyleProp} from '#/alf' 9 9 import {Button} from '#/components/Button' 10 10 import { 11 11 ModerationDetailsDialog,
+1 -1
src/components/Portal.tsx
··· 10 10 useState, 11 11 } from 'react' 12 12 13 - type Component = React.ReactElement 13 + type Component = React.ReactElement<any> 14 14 15 15 type ContextType = { 16 16 outlet: Component | null
+1 -1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerWeb.tsx
··· 139 139 playlist: string 140 140 setHasSubtitleTrack: (v: boolean) => void 141 141 setError: (v: Error | null) => void 142 - videoRef: React.RefObject<HTMLVideoElement> 142 + videoRef: React.RefObject<HTMLVideoElement | null> 143 143 setHlsLoading: (v: boolean) => void 144 144 }) { 145 145 const [Hls, setHls] = useState<typeof HlsTypes.default | undefined>(
+7 -6
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx
··· 1 1 import {View} from 'react-native' 2 2 import {msg, Trans} from '@lingui/macro' 3 3 import {useLingui} from '@lingui/react' 4 - import type React from 'react' 5 4 6 5 import {atoms as a, useTheme} from '#/alf' 7 - import {Button, ButtonText} from '#/components/Button' 6 + import {Button, ButtonIcon, ButtonText} from '#/components/Button' 7 + import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as ArrowRotateIcon} from '#/components/icons/ArrowRotateCounterClockwise' 8 + import {MediaInsetBorder} from '#/components/MediaInsetBorder' 8 9 import {Text as TypoText} from '#/components/Typography' 9 10 10 11 export function Container({children}: {children: React.ReactNode}) { ··· 17 18 a.justify_center, 18 19 a.align_center, 19 20 a.px_lg, 20 - a.border, 21 - t.atoms.border_contrast_low, 22 - a.rounded_sm, 21 + a.rounded_md, 22 + a.overflow_hidden, 23 23 a.gap_lg, 24 24 ]}> 25 25 {children} 26 + <MediaInsetBorder /> 26 27 </View> 27 28 ) 28 29 } ··· 51 52 onPress={onPress} 52 53 size="small" 53 54 color="secondary_inverted" 54 - variant="solid" 55 55 label={_(msg`Retry`)}> 56 + <ButtonIcon icon={ArrowRotateIcon} /> 56 57 <ButtonText> 57 58 <Trans>Retry</Trans> 58 59 </ButtonText>
-1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/ControlButton.tsx
··· 1 1 import {type SvgProps} from 'react-native-svg' 2 - import type React from 'react' 3 2 4 3 import {PressableWithHover} from '#/view/com/util/PressableWithHover' 5 4 import {atoms as a, useTheme, web} from '#/alf'
-1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/Scrubber.tsx
··· 2 2 import {View} from 'react-native' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 - import type React from 'react' 6 5 7 6 import {isFirefox, isTouchDevice} from '#/lib/browser' 8 7 import {clamp} from '#/lib/numbers'
+5 -5
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx
··· 46 46 hlsLoading, 47 47 hasSubtitleTrack, 48 48 }: { 49 - videoRef: React.RefObject<HTMLVideoElement> 50 - hlsRef: React.RefObject<Hls | undefined> 49 + videoRef: React.RefObject<HTMLVideoElement | null> 50 + hlsRef: React.RefObject<Hls | undefined | null> 51 51 active: boolean 52 52 setActive: () => void 53 53 focused: boolean 54 54 setFocused: (focused: boolean) => void 55 55 onScreen: boolean 56 - fullscreenRef: React.RefObject<HTMLDivElement> 56 + fullscreenRef: React.RefObject<HTMLDivElement | null> 57 57 hlsLoading: boolean 58 58 hasSubtitleTrack: boolean 59 59 }) { ··· 232 232 }, [onSeek, videoRef]) 233 233 234 234 const [showCursor, setShowCursor] = useState(true) 235 - const cursorTimeoutRef = useRef<ReturnType<typeof setTimeout>>() 235 + const cursorTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined) 236 236 const onPointerMoveEmptySpace = useCallback(() => { 237 237 setShowCursor(true) 238 238 if (cursorTimeoutRef.current) { ··· 264 264 [hovered], 265 265 ) 266 266 267 - const timeoutRef = useRef<ReturnType<typeof setTimeout>>() 267 + const timeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined) 268 268 269 269 const onHoverWithTimeout = useCallback(() => { 270 270 onHover()
-1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx
··· 3 3 import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 - import type React from 'react' 7 6 8 7 import {isSafari, isTouchDevice} from '#/lib/browser' 9 8 import {atoms as a} from '#/alf'
+1 -1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/utils.tsx
··· 4 4 import {logger} from '#/logger' 5 5 import {useVideoVolumeState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext' 6 6 7 - export function useVideoElement(ref: RefObject<HTMLVideoElement>) { 7 + export function useVideoElement(ref: RefObject<HTMLVideoElement | null>) { 8 8 const [playing, setPlaying] = useState(false) 9 9 const [muted, setMuted] = useState(true) 10 10 const [currentTime, setCurrentTime] = useState(0)
+8 -3
src/components/Post/Embed/VideoEmbed/index.web.tsx
··· 10 10 import {type AppBskyEmbedVideo} from '@atproto/api' 11 11 import {msg} from '@lingui/macro' 12 12 import {useLingui} from '@lingui/react' 13 - import type React from 'react' 14 13 15 14 import {isFirefox} from '#/lib/browser' 16 15 import {ErrorBoundary} from '#/view/com/util/ErrorBoundary' ··· 38 37 useActiveVideoWeb() 39 38 const [onScreen, setOnScreen] = useState(false) 40 39 const [isFullscreen] = useFullscreen() 41 - const lastKnownTime = useRef<number | undefined>() 40 + const lastKnownTime = useRef<number | undefined>(undefined) 42 41 43 42 useEffect(() => { 44 43 if (!ref.current) return ··· 87 86 const contents = ( 88 87 <div 89 88 ref={ref} 90 - style={{display: 'flex', flex: 1, cursor: 'default'}} 89 + style={{ 90 + display: 'flex', 91 + flex: 1, 92 + cursor: 'default', 93 + backgroundImage: `url(${embed.thumbnail})`, 94 + backgroundSize: 'cover', 95 + }} 91 96 onClick={evt => evt.stopPropagation()}> 92 97 <ErrorBoundary renderError={renderError} key={key}> 93 98 <OnlyNearScreen>
-1
src/components/PostControls/PostMenu/index.tsx
··· 8 8 } from '@atproto/api' 9 9 import {msg} from '@lingui/macro' 10 10 import {useLingui} from '@lingui/react' 11 - import type React from 'react' 12 11 13 12 import {type Shadow} from '#/state/cache/post-shadow' 14 13 import {EventStopper} from '#/view/com/util/EventStopper'
-1
src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx
··· 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 import {useNavigation} from '@react-navigation/native' 6 - import type React from 'react' 7 6 8 7 import {makeProfileLink} from '#/lib/routes/links' 9 8 import {type NavigationProp} from '#/lib/routes/types'
-1
src/components/PostControls/ShareMenu/index.tsx
··· 9 9 } from '@atproto/api' 10 10 import {msg} from '@lingui/macro' 11 11 import {useLingui} from '@lingui/react' 12 - import type React from 'react' 13 12 14 13 import {makeProfileLink} from '#/lib/routes/links' 15 14 import {shareUrl} from '#/lib/sharing'
-2
src/components/ProfileHoverCard/types.ts
··· 1 - import type React from 'react' 2 - 3 1 import {type ViewStyleProp} from '#/alf' 4 2 5 3 export type ProfileHoverCardProps = ViewStyleProp & {
+3 -3
src/components/ProgressGuide/FollowDialog.tsx
··· 293 293 interestsDisplayNames, 294 294 }: { 295 295 guide: Follow10ProgressGuide 296 - inputRef: React.RefObject<TextInput> 297 - listRef: React.RefObject<ListMethods> 296 + inputRef: React.RefObject<TextInput | null> 297 + listRef: React.RefObject<ListMethods | null> 298 298 onSelectTab: (v: string) => void 299 299 searchText: string 300 300 setHeaderHeight: (v: number) => void ··· 565 565 }: { 566 566 onChangeText: (text: string) => void 567 567 onEscape: () => void 568 - inputRef: React.RefObject<TextInput> 568 + inputRef: React.RefObject<TextInput | null> 569 569 defaultValue: string 570 570 }) { 571 571 const t = useTheme()
+1 -1
src/components/ProgressGuide/List.tsx
··· 1 - import {StyleProp, View, ViewStyle} from 'react-native' 1 + import {type StyleProp, View, type ViewStyle} from 'react-native' 2 2 import {msg, Trans} from '@lingui/macro' 3 3 import {useLingui} from '@lingui/react' 4 4
+2 -2
src/components/ProgressGuide/Toast.tsx
··· 14 14 import {isWeb} from '#/platform/detection' 15 15 import {atoms as a, useTheme} from '#/alf' 16 16 import {Portal} from '#/components/Portal' 17 - import {AnimatedCheck, AnimatedCheckRef} from '../anim/AnimatedCheck' 17 + import {AnimatedCheck, type AnimatedCheckRef} from '../anim/AnimatedCheck' 18 18 import {Text} from '../Typography' 19 19 20 20 export interface ProgressGuideToastRef { ··· 39 39 const translateY = useSharedValue(0) 40 40 const opacity = useSharedValue(0) 41 41 const animatedCheckRef = React.useRef<AnimatedCheckRef | null>(null) 42 - const timeoutRef = React.useRef<NodeJS.Timeout | undefined>() 42 + const timeoutRef = React.useRef<NodeJS.Timeout | undefined>(undefined) 43 43 const winDim = useWindowDimensions() 44 44 45 45 /**
+2 -2
src/components/ReportDialog/SelectLabelerView.tsx
··· 1 1 import {View} from 'react-native' 2 - import {AppBskyLabelerDefs} from '@atproto/api' 2 + import {type AppBskyLabelerDefs} from '@atproto/api' 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 ··· 9 9 import {Divider} from '#/components/Divider' 10 10 import * as LabelingServiceCard from '#/components/LabelingServiceCard' 11 11 import {Text} from '#/components/Typography' 12 - import {ReportDialogProps} from './types' 12 + import {type ReportDialogProps} from './types' 13 13 14 14 export function SelectLabelerView({ 15 15 ...props
+6 -3
src/components/ReportDialog/SelectReportOptionView.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 - import {AppBskyLabelerDefs} from '@atproto/api' 3 + import {type AppBskyLabelerDefs} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 - import {ReportOption, useReportOptions} from '#/lib/moderation/useReportOptions' 7 + import { 8 + type ReportOption, 9 + useReportOptions, 10 + } from '#/lib/moderation/useReportOptions' 8 11 import {Link} from '#/components/Link' 9 12 import {DMCA_LINK} from '#/components/ReportDialog/const' 10 13 export {useDialogControl as useReportDialogControl} from '#/components/Dialog' ··· 23 26 } from '#/components/icons/Chevron' 24 27 import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRight} from '#/components/icons/SquareArrowTopRight' 25 28 import {Text} from '#/components/Typography' 26 - import {ReportDialogProps} from './types' 29 + import {type ReportDialogProps} from './types' 27 30 28 31 export function SelectReportOptionView(props: { 29 32 params: ReportDialogProps['params']
+3 -3
src/components/ReportDialog/SubmitView.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 - import {AppBskyLabelerDefs} from '@atproto/api' 3 + import {type AppBskyLabelerDefs} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 7 import {getLabelingServiceTitle} from '#/lib/moderation' 8 - import {ReportOption} from '#/lib/moderation/useReportOptions' 8 + import {type ReportOption} from '#/lib/moderation/useReportOptions' 9 9 import {isAndroid} from '#/platform/detection' 10 10 import {useAgent} from '#/state/session' 11 11 import {CharProgress} from '#/view/com/composer/char-progress/CharProgress' ··· 19 19 import {PaperPlane_Stroke2_Corner0_Rounded as SendIcon} from '#/components/icons/PaperPlane' 20 20 import {Loader} from '#/components/Loader' 21 21 import {Text} from '#/components/Typography' 22 - import {ReportDialogProps} from './types' 22 + import {type ReportDialogProps} from './types' 23 23 24 24 export function SubmitView({ 25 25 params,
+1 -1
src/components/ReportDialog/types.ts
··· 1 - import * as Dialog from '#/components/Dialog' 1 + import type * as Dialog from '#/components/Dialog' 2 2 3 3 export type ReportDialogProps = { 4 4 control: Dialog.DialogOuterProps['control']
+2 -2
src/components/RichTextTag.tsx
··· 1 1 import React from 'react' 2 - import {StyleProp, Text as RNText, TextStyle} from 'react-native' 2 + import {type StyleProp, Text as RNText, type TextStyle} from 'react-native' 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 import {useNavigation} from '@react-navigation/native' 6 6 7 - import {NavigationProp} from '#/lib/routes/types' 7 + import {type NavigationProp} from '#/lib/routes/types' 8 8 import {isInvalidHandle} from '#/lib/strings/handles' 9 9 import {isNative, isWeb} from '#/platform/detection' 10 10 import {
+1 -1
src/components/Select/types.ts
··· 160 160 item: T, 161 161 index: number, 162 162 selectedValue?: string | null, 163 - ) => React.ReactElement 163 + ) => React.ReactElement<any> 164 164 /* 165 165 * Extracts the value from an item. Defaults to `item => item.value` 166 166 */
+3 -3
src/components/StarterPack/Main/PostsList.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 6 6 import {isNative} from '#/platform/detection' 7 - import {FeedDescriptor} from '#/state/queries/post-feed' 7 + import {type FeedDescriptor} from '#/state/queries/post-feed' 8 8 import {PostFeed} from '#/view/com/posts/PostFeed' 9 9 import {EmptyState} from '#/view/com/util/EmptyState' 10 - import {ListRef} from '#/view/com/util/List' 11 - import {SectionRef} from '#/screens/Profile/Sections/types' 10 + import {type ListRef} from '#/view/com/util/List' 11 + import {type SectionRef} from '#/screens/Profile/Sections/types' 12 12 13 13 interface ProfilesListProps { 14 14 listUri: string
+10 -7
src/components/StarterPack/Main/ProfilesList.tsx
··· 1 1 import React, {useCallback} from 'react' 2 - import {ListRenderItemInfo, View} from 'react-native' 2 + import {type ListRenderItemInfo, View} from 'react-native' 3 3 import { 4 - AppBskyActorDefs, 5 - AppBskyGraphGetList, 4 + type AppBskyActorDefs, 5 + type AppBskyGraphGetList, 6 6 AtUri, 7 - ModerationOpts, 7 + type ModerationOpts, 8 8 } from '@atproto/api' 9 - import {InfiniteData, UseInfiniteQueryResult} from '@tanstack/react-query' 9 + import { 10 + type InfiniteData, 11 + type UseInfiniteQueryResult, 12 + } from '@tanstack/react-query' 10 13 11 14 import {useBottomBarOffset} from '#/lib/hooks/useBottomBarOffset' 12 15 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' ··· 14 17 import {isNative, isWeb} from '#/platform/detection' 15 18 import {useAllListMembersQuery} from '#/state/queries/list-members' 16 19 import {useSession} from '#/state/session' 17 - import {List, ListRef} from '#/view/com/util/List' 18 - import {SectionRef} from '#/screens/Profile/Sections/types' 20 + import {List, type ListRef} from '#/view/com/util/List' 21 + import {type SectionRef} from '#/screens/Profile/Sections/types' 19 22 import {atoms as a, useTheme} from '#/alf' 20 23 import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' 21 24 import {Default as ProfileCard} from '#/components/ProfileCard'
+20 -24
src/components/StarterPack/ProfileStarterPacks.tsx
··· 1 - import React, { 2 - useCallback, 3 - useEffect, 4 - useImperativeHandle, 5 - useState, 6 - } from 'react' 1 + import {useCallback, useEffect, useImperativeHandle, useState} from 'react' 7 2 import { 8 3 findNodeHandle, 9 4 type ListRenderItemInfo, 10 5 type StyleProp, 6 + useWindowDimensions, 11 7 View, 12 8 type ViewStyle, 13 9 } from 'react-native' ··· 42 38 } 43 39 44 40 interface ProfileFeedgensProps { 41 + ref?: React.Ref<SectionRef> 45 42 scrollElRef: ListRef 46 43 did: string 47 44 headerOffset: number ··· 56 53 return item.uri 57 54 } 58 55 59 - export const ProfileStarterPacks = React.forwardRef< 60 - SectionRef, 61 - ProfileFeedgensProps 62 - >(function ProfileFeedgensImpl( 63 - { 64 - scrollElRef, 65 - did, 66 - headerOffset, 67 - enabled, 68 - style, 69 - testID, 70 - setScrollViewTag, 71 - isMe, 72 - }, 56 + export function ProfileStarterPacks({ 73 57 ref, 74 - ) { 58 + scrollElRef, 59 + did, 60 + headerOffset, 61 + enabled, 62 + style, 63 + testID, 64 + setScrollViewTag, 65 + isMe, 66 + }: ProfileFeedgensProps) { 75 67 const t = useTheme() 76 68 const bottomBarOffset = useBottomBarOffset(100) 69 + const {height} = useWindowDimensions() 77 70 const [isPTRing, setIsPTRing] = useState(false) 78 71 const { 79 72 data, ··· 101 94 setIsPTRing(false) 102 95 }, [refetch, setIsPTRing]) 103 96 104 - const onEndReached = React.useCallback(async () => { 97 + const onEndReached = useCallback(async () => { 105 98 if (isFetchingNextPage || !hasNextPage || isError) return 106 99 try { 107 100 await fetchNextPage() ··· 144 137 refreshing={isPTRing} 145 138 headerOffset={headerOffset} 146 139 progressViewOffset={ios(0)} 147 - contentContainerStyle={{paddingBottom: headerOffset + bottomBarOffset}} 140 + contentContainerStyle={{ 141 + minHeight: height + headerOffset, 142 + paddingBottom: bottomBarOffset, 143 + }} 148 144 removeClippedSubviews={true} 149 145 desktopFixedHeight 150 146 onEndReached={onEndReached} ··· 158 154 /> 159 155 </View> 160 156 ) 161 - }) 157 + } 162 158 163 159 function CreateAnother() { 164 160 const {_} = useLingui()
+11 -11
src/components/StarterPack/QrCode.tsx
··· 1 - import React from 'react' 1 + import {lazy} from 'react' 2 2 import {View} from 'react-native' 3 3 // @ts-expect-error missing types 4 4 import QRCode from 'react-native-qrcode-styled' 5 5 import type ViewShot from 'react-native-view-shot' 6 - import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' 6 + import {type AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' 7 7 import {Trans} from '@lingui/macro' 8 8 9 9 import {isWeb} from '#/platform/detection' ··· 15 15 import {Text} from '#/components/Typography' 16 16 import * as bsky from '#/types/bsky' 17 17 18 - const LazyViewShot = React.lazy( 18 + const LazyViewShot = lazy( 19 19 // @ts-expect-error dynamic import 20 20 () => import('react-native-view-shot/src/index'), 21 21 ) 22 22 23 - interface Props { 23 + export function QrCode({ 24 + starterPack, 25 + link, 26 + ref, 27 + }: { 24 28 starterPack: AppBskyGraphDefs.StarterPackView 25 29 link: string 26 - } 27 - 28 - export const QrCode = React.forwardRef<ViewShot, Props>(function QrCode( 29 - {starterPack, link}, 30 - ref, 31 - ) { 30 + ref: React.Ref<ViewShot> 31 + }) { 32 32 const {record} = starterPack 33 33 34 34 if ( ··· 93 93 </LinearGradientBackground> 94 94 </LazyViewShot> 95 95 ) 96 - }) 96 + } 97 97 98 98 export function QrCodeInner({link}: {link: string}) { 99 99 const t = useTheme()
+62 -51
src/components/StarterPack/QrCodeDialog.tsx
··· 1 - import React from 'react' 1 + import {Suspense, useRef, useState} from 'react' 2 2 import {View} from 'react-native' 3 3 import type ViewShot from 'react-native-view-shot' 4 4 import {requestMediaLibraryPermissionsAsync} from 'expo-image-picker' ··· 8 8 import {msg, Trans} from '@lingui/macro' 9 9 import {useLingui} from '@lingui/react' 10 10 11 - import {logEvent} from '#/lib/statsig/statsig' 12 11 import {logger} from '#/logger' 13 12 import {isNative, isWeb} from '#/platform/detection' 14 - import * as Toast from '#/view/com/util/Toast' 15 - import {atoms as a} from '#/alf' 16 - import {Button, ButtonText} from '#/components/Button' 13 + import {atoms as a, useBreakpoints} from '#/alf' 14 + import {Button, ButtonIcon, ButtonText} from '#/components/Button' 17 15 import * as Dialog from '#/components/Dialog' 18 16 import {type DialogControlProps} from '#/components/Dialog' 17 + import {ArrowOutOfBoxModified_Stroke2_Corner2_Rounded as ShareIcon} from '#/components/icons/ArrowOutOfBox' 18 + import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' 19 + import {FloppyDisk_Stroke2_Corner0_Rounded as FloppyDiskIcon} from '#/components/icons/FloppyDisk' 19 20 import {Loader} from '#/components/Loader' 20 21 import {QrCode} from '#/components/StarterPack/QrCode' 22 + import * as Toast from '#/components/Toast' 21 23 import * as bsky from '#/types/bsky' 22 24 23 25 export function QrCodeDialog({ ··· 30 32 control: DialogControlProps 31 33 }) { 32 34 const {_} = useLingui() 33 - const [isProcessing, setIsProcessing] = React.useState(false) 35 + const {gtMobile} = useBreakpoints() 36 + const [isSaveProcessing, setIsSaveProcessing] = useState(false) 37 + const [isCopyProcessing, setIsCopyProcessing] = useState(false) 34 38 35 - const ref = React.useRef<ViewShot>(null) 39 + const ref = useRef<ViewShot>(null) 36 40 37 41 const getCanvas = (base64: string): Promise<HTMLCanvasElement> => { 38 42 return new Promise(resolve => { ··· 68 72 try { 69 73 await createAssetAsync(`file://${uri}`) 70 74 } catch (e: unknown) { 71 - Toast.show( 72 - _(msg`An error occurred while saving the QR code!`), 73 - 'xmark', 74 - ) 75 + Toast.show(_(msg`An error occurred while saving the QR code!`), { 76 + type: 'error', 77 + }) 75 78 logger.error('Failed to save QR code', {error: e}) 76 79 return 77 80 } 78 81 } else { 79 - setIsProcessing(true) 82 + setIsSaveProcessing(true) 80 83 81 84 if ( 82 85 !bsky.validate( ··· 101 104 link.click() 102 105 } 103 106 104 - logEvent('starterPack:share', { 107 + logger.metric('starterPack:share', { 105 108 starterPack: starterPack.uri, 106 109 shareType: 'qrcode', 107 110 qrShareType: 'save', 108 111 }) 109 - setIsProcessing(false) 112 + setIsSaveProcessing(false) 110 113 Toast.show( 111 114 isWeb 112 115 ? _(msg`QR code has been downloaded!`) ··· 117 120 } 118 121 119 122 const onCopyPress = async () => { 120 - setIsProcessing(true) 123 + setIsCopyProcessing(true) 121 124 ref.current?.capture?.().then(async (uri: string) => { 122 125 const canvas = await getCanvas(uri) 123 126 // @ts-expect-error web only ··· 126 129 navigator.clipboard.write([item]) 127 130 }) 128 131 129 - logEvent('starterPack:share', { 132 + logger.metric('starterPack:share', { 130 133 starterPack: starterPack.uri, 131 134 shareType: 'qrcode', 132 135 qrShareType: 'copy', 133 136 }) 134 137 Toast.show(_(msg`QR code copied to your clipboard!`)) 135 - setIsProcessing(false) 138 + setIsCopyProcessing(false) 136 139 control.close() 137 140 }) 138 141 } ··· 142 145 control.close(() => { 143 146 Sharing.shareAsync(uri, {mimeType: 'image/png', UTI: 'image/png'}).then( 144 147 () => { 145 - logEvent('starterPack:share', { 148 + logger.metric('starterPack:share', { 146 149 starterPack: starterPack.uri, 147 150 shareType: 'qrcode', 148 151 qrShareType: 'share', ··· 154 157 } 155 158 156 159 return ( 157 - <Dialog.Outer control={control}> 160 + <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> 158 161 <Dialog.Handle /> 159 162 <Dialog.ScrollableInner 160 163 label={_(msg`Create a QR code for a starter pack`)}> 161 164 <View style={[a.flex_1, a.align_center, a.gap_5xl]}> 162 - <React.Suspense fallback={<Loading />}> 165 + <Suspense fallback={<Loading />}> 163 166 {!link ? ( 164 167 <Loading /> 165 168 ) : ( 166 169 <> 167 170 <QrCode starterPack={starterPack} link={link} ref={ref} /> 168 - {isProcessing ? ( 169 - <View> 170 - <Loader size="xl" /> 171 - </View> 172 - ) : ( 173 - <View 174 - style={[a.w_full, a.gap_md, isWeb && [a.flex_row_reverse]]}> 175 - <Button 176 - label={_(msg`Copy QR code`)} 177 - variant="solid" 178 - color="secondary" 179 - size="small" 180 - onPress={isWeb ? onCopyPress : onSharePress}> 181 - <ButtonText> 182 - {isWeb ? <Trans>Copy</Trans> : <Trans>Share</Trans>} 183 - </ButtonText> 184 - </Button> 185 - <Button 186 - label={_(msg`Save QR code`)} 187 - variant="solid" 188 - color="secondary" 189 - size="small" 190 - onPress={onSavePress}> 191 - <ButtonText> 192 - <Trans>Save</Trans> 193 - </ButtonText> 194 - </Button> 195 - </View> 196 - )} 171 + <View 172 + style={[ 173 + a.w_full, 174 + a.gap_md, 175 + gtMobile && [a.flex_row, a.justify_center, a.flex_wrap], 176 + ]}> 177 + <Button 178 + label={_(msg`Copy QR code`)} 179 + color="primary_subtle" 180 + size="large" 181 + onPress={isWeb ? onCopyPress : onSharePress}> 182 + <ButtonIcon 183 + icon={ 184 + isCopyProcessing 185 + ? Loader 186 + : isWeb 187 + ? ChainLinkIcon 188 + : ShareIcon 189 + } 190 + /> 191 + <ButtonText> 192 + {isWeb ? <Trans>Copy</Trans> : <Trans>Share</Trans>} 193 + </ButtonText> 194 + </Button> 195 + <Button 196 + label={_(msg`Save QR code`)} 197 + color="secondary" 198 + size="large" 199 + onPress={onSavePress}> 200 + <ButtonIcon 201 + icon={isSaveProcessing ? Loader : FloppyDiskIcon} 202 + /> 203 + <ButtonText> 204 + <Trans>Save</Trans> 205 + </ButtonText> 206 + </Button> 207 + </View> 197 208 </> 198 209 )} 199 - </React.Suspense> 210 + </Suspense> 200 211 </View> 201 212 <Dialog.Close /> 202 213 </Dialog.ScrollableInner> ··· 206 217 207 218 function Loading() { 208 219 return ( 209 - <View style={[a.align_center, a.p_xl]}> 220 + <View style={[a.align_center, a.justify_center, {minHeight: 400}]}> 210 221 <Loader size="xl" /> 211 222 </View> 212 223 )
+30 -24
src/components/StarterPack/ShareDialog.tsx
··· 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 - import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 8 7 import {useSaveImageToMediaLibrary} from '#/lib/media/save-image' 9 8 import {shareUrl} from '#/lib/sharing' 10 - import {logEvent} from '#/lib/statsig/statsig' 11 9 import {getStarterPackOgCard} from '#/lib/strings/starter-pack' 10 + import {logger} from '#/logger' 12 11 import {isNative, isWeb} from '#/platform/detection' 13 - import {atoms as a, useTheme} from '#/alf' 14 - import {Button, ButtonText} from '#/components/Button' 12 + import {atoms as a, useBreakpoints, useTheme} from '#/alf' 13 + import {Button, ButtonIcon, ButtonText} from '#/components/Button' 15 14 import {type DialogControlProps} from '#/components/Dialog' 16 15 import * as Dialog from '#/components/Dialog' 16 + import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' 17 + import {Download_Stroke2_Corner0_Rounded as DownloadIcon} from '#/components/icons/Download' 18 + import {QrCode_Stroke2_Corner0_Rounded as QrCodeIcon} from '#/components/icons/QrCode' 17 19 import {Loader} from '#/components/Loader' 18 20 import {Text} from '#/components/Typography' 19 21 ··· 27 29 28 30 export function ShareDialog(props: Props) { 29 31 return ( 30 - <Dialog.Outer control={props.control}> 32 + <Dialog.Outer 33 + control={props.control} 34 + nativeOptions={{preventExpansion: true}}> 31 35 <Dialog.Handle /> 32 36 <ShareDialogInner {...props} /> 33 37 </Dialog.Outer> ··· 43 47 }: Props) { 44 48 const {_} = useLingui() 45 49 const t = useTheme() 46 - const {isTabletOrDesktop} = useWebMediaQueries() 50 + const {gtMobile} = useBreakpoints() 47 51 48 52 const imageUrl = getStarterPackOgCard(starterPack) 49 53 50 54 const onShareLink = async () => { 51 55 if (!link) return 52 56 shareUrl(link) 53 - logEvent('starterPack:share', { 57 + logger.metric('starterPack:share', { 54 58 starterPack: starterPack.uri, 55 59 shareType: 'link', 56 60 }) ··· 67 71 <> 68 72 <Dialog.ScrollableInner label={_(msg`Share link dialog`)}> 69 73 {!imageLoaded || !link ? ( 70 - <View style={[a.p_xl, a.align_center]}> 74 + <View style={[a.align_center, a.justify_center, {minHeight: 350}]}> 71 75 <Loader size="xl" /> 72 76 </View> 73 77 ) : ( 74 - <View style={[!isTabletOrDesktop && a.gap_lg]}> 75 - <View style={[a.gap_sm, isTabletOrDesktop && a.pb_lg]}> 78 + <View style={[!gtMobile && a.gap_lg]}> 79 + <View style={[a.gap_sm, gtMobile && a.pb_lg]}> 76 80 <Text style={[a.font_bold, a.text_2xl]}> 77 81 <Trans>Invite people to this starter pack!</Trans> 78 82 </Text> ··· 89 93 a.rounded_sm, 90 94 { 91 95 aspectRatio: 1200 / 630, 92 - transform: [{scale: isTabletOrDesktop ? 0.85 : 1}], 93 - marginTop: isTabletOrDesktop ? -20 : 0, 96 + transform: [{scale: gtMobile ? 0.85 : 1}], 97 + marginTop: gtMobile ? -20 : 0, 94 98 }, 95 99 ]} 96 100 accessibilityIgnoresInvertColors={true} ··· 98 102 <View 99 103 style={[ 100 104 a.gap_md, 101 - isWeb && [a.gap_sm, a.flex_row_reverse, {marginLeft: 'auto'}], 105 + gtMobile && [ 106 + a.gap_sm, 107 + a.justify_center, 108 + a.flex_row, 109 + a.flex_wrap, 110 + ], 102 111 ]}> 103 112 <Button 104 113 label={isWeb ? _(msg`Copy link`) : _(msg`Share link`)} 105 - variant="solid" 106 - color="secondary" 107 - size="small" 108 - style={[isWeb && a.self_center]} 114 + color="primary_subtle" 115 + size="large" 109 116 onPress={onShareLink}> 117 + <ButtonIcon icon={ChainLinkIcon} /> 110 118 <ButtonText> 111 119 {isWeb ? <Trans>Copy Link</Trans> : <Trans>Share link</Trans>} 112 120 </ButtonText> 113 121 </Button> 114 122 <Button 115 123 label={_(msg`Share QR code`)} 116 - variant="solid" 117 - color="secondary" 118 - size="small" 119 - style={[isWeb && a.self_center]} 124 + color="primary_subtle" 125 + size="large" 120 126 onPress={() => { 121 127 control.close(() => { 122 128 qrDialogControl.open() 123 129 }) 124 130 }}> 131 + <ButtonIcon icon={QrCodeIcon} /> 125 132 <ButtonText> 126 133 <Trans>Share QR code</Trans> 127 134 </ButtonText> ··· 129 136 {isNative && ( 130 137 <Button 131 138 label={_(msg`Save image`)} 132 - variant="ghost" 133 139 color="secondary" 134 - size="small" 135 - style={[isWeb && a.self_center]} 140 + size="large" 136 141 onPress={onSave}> 142 + <ButtonIcon icon={DownloadIcon} /> 137 143 <ButtonText> 138 144 <Trans>Save image</Trans> 139 145 </ButtonText>
+2 -2
src/components/StarterPack/Wizard/ScreenTransition.tsx
··· 1 - import React from 'react' 2 - import {StyleProp, ViewStyle} from 'react-native' 1 + import {type StyleProp, type ViewStyle} from 'react-native' 3 2 import Animated, { 4 3 FadeIn, 5 4 FadeOut, 6 5 SlideInLeft, 7 6 SlideInRight, 8 7 } from 'react-native-reanimated' 8 + import type React from 'react' 9 9 10 10 import {isWeb} from '#/platform/detection' 11 11
+1 -1
src/components/SubtleWebHover.tsx
··· 1 - import {ViewStyleProp} from '#/alf' 1 + import {type ViewStyleProp} from '#/alf' 2 2 3 3 export function SubtleWebHover({}: ViewStyleProp & {hover: boolean}) { 4 4 return null
+4 -4
src/components/TrendingTopics.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 - import {AtUri} from '@atproto/api' 3 + import {type AtUri} from '@atproto/api' 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 ··· 10 10 // import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag' 11 11 // import {CloseQuote_Filled_Stroke2_Corner0_Rounded as Quote} from '#/components/icons/Quote' 12 12 // import {UserAvatar} from '#/view/com/util/UserAvatar' 13 - import type {TrendingTopic} from '#/state/queries/trending/useTrendingTopics' 14 - import {atoms as a, native, useTheme, ViewStyleProp} from '#/alf' 13 + import {type TrendingTopic} from '#/state/queries/trending/useTrendingTopics' 14 + import {atoms as a, native, useTheme, type ViewStyleProp} from '#/alf' 15 15 import {StarterPack as StarterPackIcon} from '#/components/icons/StarterPack' 16 - import {Link as InternalLink, LinkProps} from '#/components/Link' 16 + import {Link as InternalLink, type LinkProps} from '#/components/Link' 17 17 import {Text} from '#/components/Typography' 18 18 19 19 export function TrendingTopic({
+1 -1
src/components/anim/AnimatedCheck.tsx
··· 8 8 } from 'react-native-reanimated' 9 9 import Svg, {Circle, Path} from 'react-native-svg' 10 10 11 - import {Props, useCommonSVGProps} from '#/components/icons/common' 11 + import {type Props, useCommonSVGProps} from '#/components/icons/common' 12 12 13 13 const AnimatedPath = Animated.createAnimatedComponent(Path) 14 14 const AnimatedCircle = Animated.createAnimatedComponent(Circle)
+1 -1
src/components/dialogs/Embed.tsx
··· 1 1 import {memo, useEffect, useMemo, useState} from 'react' 2 2 import {View} from 'react-native' 3 - import {AppBskyActorDefs, AppBskyFeedPost, AtUri} from '@atproto/api' 3 + import {type AppBskyActorDefs, type AppBskyFeedPost, AtUri} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6
+3 -3
src/components/dialogs/EmbedConsent.tsx
··· 10 10 } from '#/lib/strings/embed-player' 11 11 import {useSetExternalEmbedPref} from '#/state/preferences' 12 12 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 13 + import {Button, ButtonText} from '#/components/Button' 13 14 import * as Dialog from '#/components/Dialog' 14 - import {Button, ButtonText} from '../Button' 15 - import {Text} from '../Typography' 15 + import {Text} from '#/components/Typography' 16 16 17 17 export function EmbedConsentDialog({ 18 18 control, ··· 48 48 }, [control, setExternalEmbedPref, source]) 49 49 50 50 return ( 51 - <Dialog.Outer control={control}> 51 + <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> 52 52 <Dialog.Handle /> 53 53 <Dialog.ScrollableInner 54 54 label={_(msg`External Media`)}
+1 -1
src/components/dialogs/GifSelect.tsx
··· 37 37 onClose, 38 38 onSelectGif: onSelectGifProp, 39 39 }: { 40 - controlRef: React.RefObject<{open: () => void}> 40 + controlRef: React.RefObject<{open: () => void} | null> 41 41 onClose?: () => void 42 42 onSelectGif: (gif: Gif) => void 43 43 }) {
+2 -2
src/components/dialogs/MutedWords.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 - import {AppBskyActorDefs, sanitizeMutedWordValue} from '@atproto/api' 3 + import {type AppBskyActorDefs, sanitizeMutedWordValue} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 ··· 16 16 native, 17 17 useBreakpoints, 18 18 useTheme, 19 - ViewStyleProp, 19 + type ViewStyleProp, 20 20 web, 21 21 } from '#/alf' 22 22 import {Button, ButtonIcon, ButtonText} from '#/components/Button'
+1 -1
src/components/dialogs/SearchablePeopleList.tsx
··· 484 484 value: string 485 485 onChangeText: (text: string) => void 486 486 onEscape: () => void 487 - inputRef: React.RefObject<TextInput> 487 + inputRef: React.RefObject<TextInput | null> 488 488 }) { 489 489 const t = useTheme() 490 490 const {_} = useLingui()
-1
src/components/dms/ActionsWrapper.web.tsx
··· 3 3 import {type ChatBskyConvoDefs} from '@atproto/api' 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 - import type React from 'react' 7 6 8 7 import {useConvoActive} from '#/state/messages/convo' 9 8 import {useSession} from '#/state/session'
+2 -2
src/components/dms/BlockedByListDialog.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 - import {ModerationCause} from '@atproto/api' 3 + import {type ModerationCause} from '@atproto/api' 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 7 import {listUriToHref} from '#/lib/strings/url-helpers' 8 8 import {atoms as a, useTheme} from '#/alf' 9 9 import * as Dialog from '#/components/Dialog' 10 - import {DialogControlProps} from '#/components/Dialog' 10 + import {type DialogControlProps} from '#/components/Dialog' 11 11 import {InlineLinkText} from '#/components/Link' 12 12 import * as Prompt from '#/components/Prompt' 13 13 import {Text} from '#/components/Typography'
+2 -2
src/components/dms/LeaveConvoPrompt.tsx
··· 2 2 import {useLingui} from '@lingui/react' 3 3 import {StackActions, useNavigation} from '@react-navigation/native' 4 4 5 - import {NavigationProp} from '#/lib/routes/types' 5 + import {type NavigationProp} from '#/lib/routes/types' 6 6 import {isNative} from '#/platform/detection' 7 7 import {useLeaveConvo} from '#/state/queries/messages/leave-conversation' 8 8 import * as Toast from '#/view/com/util/Toast' 9 - import {DialogOuterProps} from '#/components/Dialog' 9 + import {type DialogOuterProps} from '#/components/Dialog' 10 10 import * as Prompt from '#/components/Prompt' 11 11 12 12 export function LeaveConvoPrompt({
+2 -2
src/components/dms/MessagesListBlockedFooter.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 - import {ModerationDecision} from '@atproto/api' 3 + import {type ModerationDecision} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 ··· 14 14 import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt' 15 15 import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt' 16 16 import {Text} from '#/components/Typography' 17 - import * as bsky from '#/types/bsky' 17 + import type * as bsky from '#/types/bsky' 18 18 19 19 export function MessagesListBlockedFooter({ 20 20 recipient: initialRecipient,
+1 -1
src/components/dms/ReportConversationPrompt.tsx
··· 1 1 import {msg} from '@lingui/macro' 2 2 import {useLingui} from '@lingui/react' 3 3 4 - import {DialogControlProps} from '#/components/Dialog' 4 + import {type DialogControlProps} from '#/components/Dialog' 5 5 import * as Prompt from '#/components/Prompt' 6 6 7 7 export function ReportConversationPrompt({
+2 -2
src/components/feeds/PostFeedVideoGridRow.tsx
··· 2 2 import {AppBskyEmbedVideo} from '@atproto/api' 3 3 4 4 import {logEvent} from '#/lib/statsig/statsig' 5 - import {FeedPostSliceItem} from '#/state/queries/post-feed' 6 - import {VideoFeedSourceContext} from '#/screens/VideoFeed/types' 5 + import {type FeedPostSliceItem} from '#/state/queries/post-feed' 6 + import {type VideoFeedSourceContext} from '#/screens/VideoFeed/types' 7 7 import {atoms as a, useGutters} from '#/alf' 8 8 import * as Grid from '#/components/Grid' 9 9 import {
+2 -2
src/components/forms/DateField/index.web.tsx
··· 1 1 import React from 'react' 2 - import {StyleSheet, TextInput, TextInputProps} from 'react-native' 2 + import {StyleSheet, type TextInput, type TextInputProps} from 'react-native' 3 3 // @ts-expect-error untyped 4 4 import {unstable_createElement} from 'react-native-web' 5 5 6 - import {DateFieldProps} from '#/components/forms/DateField/types' 6 + import {type DateFieldProps} from '#/components/forms/DateField/types' 7 7 import {toSimpleDateString} from '#/components/forms/DateField/utils' 8 8 import * as TextField from '#/components/forms/TextField' 9 9 import {CalendarDays_Stroke2_Corner0_Rounded as CalendarDays} from '#/components/icons/CalendarDays'
+5 -2
src/components/forms/InputGroup.tsx
··· 23 23 {React.cloneElement(child, { 24 24 // @ts-ignore 25 25 style: [ 26 + // @ts-ignore 26 27 ...(Array.isArray(child.props?.style) 27 - ? child.props.style 28 - : [child.props.style || {}]), 28 + ? // @ts-ignore 29 + child.props.style 30 + : // @ts-ignore 31 + [child.props.style || {}]), 29 32 { 30 33 borderTopLeftRadius: i > 0 ? 0 : undefined, 31 34 borderTopRightRadius: i > 0 ? 0 : undefined,
+1 -1
src/components/forms/SearchInput.tsx
··· 1 1 import React from 'react' 2 - import {TextInput, View} from 'react-native' 2 + import {type TextInput, View} from 'react-native' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5
+2 -2
src/components/forms/TextField.tsx
··· 28 28 import {Text} from '#/components/Typography' 29 29 30 30 const Context = createContext<{ 31 - inputRef: React.RefObject<TextInput> | null 31 + inputRef: React.RefObject<TextInput | null> | null 32 32 isInvalid: boolean 33 33 hovered: boolean 34 34 onHoverIn: () => void ··· 152 152 value?: string 153 153 onChangeText?: (value: string) => void 154 154 isInvalid?: boolean 155 - inputRef?: React.RefObject<TextInput> | React.ForwardedRef<TextInput> 155 + inputRef?: React.RefObject<TextInput | null> | React.ForwardedRef<TextInput> 156 156 } 157 157 158 158 export function createInput(Component: typeof TextInput) {
+7 -2
src/components/forms/ToggleButton.tsx
··· 1 1 import React from 'react' 2 - import {AccessibilityProps, TextStyle, View, ViewStyle} from 'react-native' 2 + import { 3 + type AccessibilityProps, 4 + type TextStyle, 5 + View, 6 + type ViewStyle, 7 + } from 'react-native' 3 8 4 9 import {atoms as a, native, useTheme} from '#/alf' 5 10 import * as Toggle from '#/components/forms/Toggle' ··· 7 12 8 13 type ItemProps = Omit<Toggle.ItemProps, 'style' | 'role' | 'children'> & 9 14 AccessibilityProps & { 10 - children: React.ReactElement 15 + children: React.ReactElement<any> 11 16 testID?: string 12 17 } 13 18
+3 -3
src/components/hooks/useFollowMethods.ts
··· 2 2 import {msg} from '@lingui/macro' 3 3 import {useLingui} from '@lingui/react' 4 4 5 - import {LogEvents} from '#/lib/statsig/statsig' 5 + import {type LogEvents} from '#/lib/statsig/statsig' 6 6 import {logger} from '#/logger' 7 - import {Shadow} from '#/state/cache/types' 7 + import {type Shadow} from '#/state/cache/types' 8 8 import {useProfileFollowMutationQueue} from '#/state/queries/profile' 9 9 import {useRequireAuth} from '#/state/session' 10 10 import * as Toast from '#/view/com/util/Toast' 11 - import * as bsky from '#/types/bsky' 11 + import type * as bsky from '#/types/bsky' 12 12 13 13 export function useFollowMethods({ 14 14 profile,
+1 -1
src/components/hooks/useFullscreen.ts
··· 14 14 return () => document.removeEventListener('fullscreenchange', onChange) 15 15 } 16 16 17 - export function useFullscreen(ref?: React.RefObject<HTMLElement>) { 17 + export function useFullscreen(ref?: React.RefObject<HTMLElement | null>) { 18 18 if (!isWeb) throw new Error("'useFullscreen' is a web-only hook") 19 19 const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () => 20 20 Boolean(document.fullscreenElement),
+1 -1
src/components/icons/TEMPLATE.tsx
··· 1 1 import React from 'react' 2 2 import Svg, {Path} from 'react-native-svg' 3 3 4 - import {Props, useCommonSVGProps} from '#/components/icons/common' 4 + import {type Props, useCommonSVGProps} from '#/components/icons/common' 5 5 6 6 export const IconTemplate_Stroke2_Corner0_Rounded = React.forwardRef( 7 7 function LogoImpl(props: Props, ref) {
+1 -1
src/components/intents/VerifyEmailIntentDialog.tsx
··· 8 8 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 9 9 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 10 10 import * as Dialog from '#/components/Dialog' 11 - import {DialogControlProps} from '#/components/Dialog' 11 + import {type DialogControlProps} from '#/components/Dialog' 12 12 import {Divider} from '#/components/Divider' 13 13 import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Resend} from '#/components/icons/ArrowRotateCounterClockwise' 14 14 import {useIntentDialogs} from '#/components/intents/IntentDialogs'
-1
src/components/moderation/LabelPreference.tsx
··· 5 5 } from '@atproto/api' 6 6 import {msg, Trans} from '@lingui/macro' 7 7 import {useLingui} from '@lingui/react' 8 - import type React from 'react' 9 8 10 9 import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings' 11 10 import {useLabelBehaviorDescription} from '#/lib/moderation/useLabelBehaviorDescription'
+8 -3
src/components/moderation/LabelsOnMe.tsx
··· 1 - import {StyleProp, View, ViewStyle} from 'react-native' 2 - import {AppBskyFeedDefs, ComAtprotoLabelDefs} from '@atproto/api' 1 + import {type StyleProp, View, type ViewStyle} from 'react-native' 2 + import {type AppBskyFeedDefs, type ComAtprotoLabelDefs} from '@atproto/api' 3 3 import {msg, Plural, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 6 import {useSession} from '#/state/session' 7 7 import {atoms as a} from '#/alf' 8 - import {Button, ButtonIcon, ButtonSize, ButtonText} from '#/components/Button' 8 + import { 9 + Button, 10 + ButtonIcon, 11 + type ButtonSize, 12 + ButtonText, 13 + } from '#/components/Button' 9 14 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 10 15 import { 11 16 LabelsOnMeDialog,
+1 -1
src/components/moderation/LabelsOnMeDialog.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 - import {ComAtprotoLabelDefs, ComAtprotoModerationDefs} from '@atproto/api' 3 + import {type ComAtprotoLabelDefs, ComAtprotoModerationDefs} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 import {useMutation} from '@tanstack/react-query'
+2 -2
src/components/moderation/ModerationDetailsDialog.tsx
··· 1 1 import {View} from 'react-native' 2 - import {ModerationCause} from '@atproto/api' 2 + import {type ModerationCause} from '@atproto/api' 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 ··· 12 12 import {atoms as a, useGutters, useTheme} from '#/alf' 13 13 import * as Dialog from '#/components/Dialog' 14 14 import {InlineLinkText} from '#/components/Link' 15 - import {AppModerationCause} from '#/components/Pills' 15 + import {type AppModerationCause} from '#/components/Pills' 16 16 import {Text} from '#/components/Typography' 17 17 18 18 export {useDialogControl as useModerationDetailsDialogControl} from '#/components/Dialog'
+2 -2
src/components/moderation/PostAlerts.tsx
··· 1 - import {StyleProp, ViewStyle} from 'react-native' 2 - import {ModerationCause, ModerationUI} from '@atproto/api' 1 + import {type StyleProp, type ViewStyle} from 'react-native' 2 + import {type ModerationCause, type ModerationUI} from '@atproto/api' 3 3 4 4 import {getModerationCauseKey, unique} from '#/lib/moderation' 5 5 import * as Pills from '#/components/Pills'
+2 -2
src/components/moderation/ProfileHeaderAlerts.tsx
··· 1 - import {StyleProp, ViewStyle} from 'react-native' 2 - import {ModerationDecision} from '@atproto/api' 1 + import {type StyleProp, type ViewStyle} from 'react-native' 2 + import {type ModerationDecision} from '@atproto/api' 3 3 4 4 import {getModerationCauseKey, unique} from '#/lib/moderation' 5 5 import * as Pills from '#/components/Pills'
+5 -5
src/components/moderation/ReportDialog/action.ts
··· 1 1 import { 2 - $Typed, 3 - ChatBskyConvoDefs, 4 - ComAtprotoModerationCreateReport, 2 + type $Typed, 3 + type ChatBskyConvoDefs, 4 + type ComAtprotoModerationCreateReport, 5 5 } from '@atproto/api' 6 6 import {msg} from '@lingui/macro' 7 7 import {useLingui} from '@lingui/react' ··· 9 9 10 10 import {logger} from '#/logger' 11 11 import {useAgent} from '#/state/session' 12 - import {ReportState} from './state' 13 - import {ParsedReportSubject} from './types' 12 + import {type ReportState} from './state' 13 + import {type ParsedReportSubject} from './types' 14 14 15 15 export function useSubmitReportMutation() { 16 16 const {_} = useLingui()
+1 -1
src/components/moderation/ReportDialog/copy.ts
··· 2 2 import {msg} from '@lingui/macro' 3 3 import {useLingui} from '@lingui/react' 4 4 5 - import {ParsedReportSubject} from './types' 5 + import {type ParsedReportSubject} from './types' 6 6 7 7 export function useCopyForSubject(subject: ParsedReportSubject) { 8 8 const {_} = useLingui()
+2 -2
src/components/moderation/ReportDialog/state.ts
··· 1 - import {AppBskyLabelerDefs, ComAtprotoModerationDefs} from '@atproto/api' 1 + import {type AppBskyLabelerDefs, ComAtprotoModerationDefs} from '@atproto/api' 2 2 3 - import {ReportOption} from './utils/useReportOptions' 3 + import {type ReportOption} from './utils/useReportOptions' 4 4 5 5 export type ReportState = { 6 6 selectedOption?: ReportOption
+6 -6
src/components/moderation/ReportDialog/types.ts
··· 1 1 import { 2 - $Typed, 3 - AppBskyActorDefs, 4 - AppBskyFeedDefs, 5 - AppBskyGraphDefs, 6 - ChatBskyConvoDefs, 2 + type $Typed, 3 + type AppBskyActorDefs, 4 + type AppBskyFeedDefs, 5 + type AppBskyGraphDefs, 6 + type ChatBskyConvoDefs, 7 7 } from '@atproto/api' 8 8 9 - import * as Dialog from '#/components/Dialog' 9 + import type * as Dialog from '#/components/Dialog' 10 10 11 11 export type ReportSubject = 12 12 | $Typed<AppBskyActorDefs.ProfileViewBasic>
+2 -2
src/components/moderation/ReportDialog/utils/parseReportSubject.ts
··· 6 6 } from '@atproto/api' 7 7 8 8 import { 9 - ParsedReportSubject, 10 - ReportSubject, 9 + type ParsedReportSubject, 10 + type ReportSubject, 11 11 } from '#/components/moderation/ReportDialog/types' 12 12 import * as bsky from '#/types/bsky' 13 13
+4 -4
src/components/moderation/ScreenHider.tsx
··· 1 1 import React from 'react' 2 2 import { 3 - StyleProp, 3 + type StyleProp, 4 4 TouchableWithoutFeedback, 5 5 View, 6 - ViewStyle, 6 + type ViewStyle, 7 7 } from 'react-native' 8 - import {ModerationUI} from '@atproto/api' 8 + import {type ModerationUI} from '@atproto/api' 9 9 import {msg, Trans} from '@lingui/macro' 10 10 import {useLingui} from '@lingui/react' 11 11 import {useNavigation} from '@react-navigation/native' 12 12 13 13 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 14 14 import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' 15 - import {NavigationProp} from '#/lib/routes/types' 15 + import {type NavigationProp} from '#/lib/routes/types' 16 16 import {CenteredView} from '#/view/com/util/Views' 17 17 import {atoms as a, useTheme, web} from '#/alf' 18 18 import {Button, ButtonText} from '#/components/Button'
+4 -4
src/components/verification/VerificationCheckButton.tsx
··· 85 85 if (size === 'lg') { 86 86 dimensions = gtPhone ? 20 : 18 87 87 } else if (size === 'md') { 88 - dimensions = 16 88 + dimensions = 14 89 89 } 90 90 91 91 const verifiedByHidden = !state.profile.showBadge && state.profile.isViewer ··· 99 99 : _(msg`View this user's verifications`) 100 100 } 101 101 hitSlop={20} 102 - onPress={() => { 102 + onPress={evt => { 103 + evt.preventDefault() 103 104 logger.metric('verification:badge:click', {}, {statsig: true}) 104 105 if (state.profile.role === 'verifier') { 105 106 verifierDialogControl.open() 106 107 } else { 107 108 verificationsDialogControl.open() 108 109 } 109 - }} 110 - style={[]}> 110 + }}> 111 111 {({hovered}) => ( 112 112 <View 113 113 style={[
+3 -3
src/lib/api/feed/custom.ts
··· 1 1 import { 2 - AppBskyFeedDefs, 3 - AppBskyFeedGetFeed as GetCustomFeed, 2 + type AppBskyFeedDefs, 3 + type AppBskyFeedGetFeed as GetCustomFeed, 4 4 BskyAgent, 5 5 jsonStringToLex, 6 6 } from '@atproto/api' ··· 9 9 getAppLanguageAsContentLanguage, 10 10 getContentLanguages, 11 11 } from '#/state/preferences/languages' 12 - import {FeedAPI, FeedAPIResponse} from './types' 12 + import {type FeedAPI, type FeedAPIResponse} from './types' 13 13 import {createBskyTopicsHeader, isBlueskyOwnedFeed} from './utils' 14 14 15 15 export class CustomFeedAPI implements FeedAPI {
+2 -2
src/lib/api/feed/following.ts
··· 1 - import {AppBskyFeedDefs, BskyAgent} from '@atproto/api' 1 + import {type AppBskyFeedDefs, type BskyAgent} from '@atproto/api' 2 2 3 - import {FeedAPI, FeedAPIResponse} from './types' 3 + import {type FeedAPI, type FeedAPIResponse} from './types' 4 4 5 5 export class FollowingFeedAPI implements FeedAPI { 6 6 agent: BskyAgent
+4 -4
src/lib/api/feed/likes.ts
··· 1 1 import { 2 - AppBskyFeedDefs, 3 - AppBskyFeedGetActorLikes as GetActorLikes, 4 - BskyAgent, 2 + type AppBskyFeedDefs, 3 + type AppBskyFeedGetActorLikes as GetActorLikes, 4 + type BskyAgent, 5 5 } from '@atproto/api' 6 6 7 - import {FeedAPI, FeedAPIResponse} from './types' 7 + import {type FeedAPI, type FeedAPIResponse} from './types' 8 8 9 9 export class LikesFeedAPI implements FeedAPI { 10 10 agent: BskyAgent
+12 -4
src/lib/api/feed/merge.ts
··· 1 - import {AppBskyFeedDefs, AppBskyFeedGetTimeline, BskyAgent} from '@atproto/api' 1 + import { 2 + type AppBskyFeedDefs, 3 + type AppBskyFeedGetTimeline, 4 + type BskyAgent, 5 + } from '@atproto/api' 2 6 import shuffle from 'lodash.shuffle' 3 7 4 8 import {bundleAsync} from '#/lib/async/bundle' 5 9 import {timeout} from '#/lib/async/timeout' 6 10 import {feedUriToHref} from '#/lib/strings/url-helpers' 7 11 import {getContentLanguages} from '#/state/preferences/languages' 8 - import {FeedParams} from '#/state/queries/post-feed' 12 + import {type FeedParams} from '#/state/queries/post-feed' 9 13 import {FeedTuner} from '../feed-manip' 10 - import {FeedTunerFn} from '../feed-manip' 11 - import {FeedAPI, FeedAPIResponse, ReasonFeedSource} from './types' 14 + import {type FeedTunerFn} from '../feed-manip' 15 + import { 16 + type FeedAPI, 17 + type FeedAPIResponse, 18 + type ReasonFeedSource, 19 + } from './types' 12 20 import {createBskyTopicsHeader, isBlueskyOwnedFeed} from './utils' 13 21 14 22 const REQUEST_WAIT_MS = 500 // 500ms
+1 -1
src/lib/api/feed/types.ts
··· 1 - import {AppBskyFeedDefs} from '@atproto/api' 1 + import {type AppBskyFeedDefs} from '@atproto/api' 2 2 3 3 export interface FeedAPIResponse { 4 4 cursor?: string
+1 -1
src/lib/api/feed/utils.ts
··· 2 2 3 3 import {BSKY_FEED_OWNER_DIDS} from '#/lib/constants' 4 4 import {isWeb} from '#/platform/detection' 5 - import {UsePreferencesQueryResponse} from '#/state/queries/preferences' 5 + import {type UsePreferencesQueryResponse} from '#/state/queries/preferences' 6 6 7 7 let debugTopics = '' 8 8 if (isWeb && typeof window !== 'undefined') {
+1 -1
src/lib/api/upload-blob.ts
··· 1 1 import {copyAsync} from 'expo-file-system' 2 - import {BskyAgent, ComAtprotoRepoUploadBlob} from '@atproto/api' 2 + import {type BskyAgent, type ComAtprotoRepoUploadBlob} from '@atproto/api' 3 3 4 4 import {safeDeleteAsync} from '#/lib/media/manip' 5 5
+1 -1
src/lib/api/upload-blob.web.ts
··· 1 - import {BskyAgent, ComAtprotoRepoUploadBlob} from '@atproto/api' 1 + import {type BskyAgent, type ComAtprotoRepoUploadBlob} from '@atproto/api' 2 2 3 3 /** 4 4 * @note It is recommended, on web, to use the `file` instance of the file
+1 -1
src/lib/assets.native.ts
··· 1 - import {ImageRequireSource} from 'react-native' 1 + import {type ImageRequireSource} from 'react-native' 2 2 3 3 export const DEF_AVATAR: ImageRequireSource = require('../../assets/default-avatar.png') 4 4 export const CLOUD_SPLASH: ImageRequireSource = require('../../assets/splash.png')
+1 -1
src/lib/assets.ts
··· 1 - import {ImageRequireSource} from 'react-native' 1 + import {type ImageRequireSource} from 'react-native' 2 2 3 3 // @ts-ignore we need to pretend -prf 4 4 export const DEF_AVATAR: ImageRequireSource = {uri: '/img/default-avatar.png'}
+1 -1
src/lib/custom-animations/GestureActionView.web.tsx
··· 1 - import React from 'react' 1 + import type React from 'react' 2 2 3 3 export function GestureActionView({children}: {children: React.ReactNode}) { 4 4 return children
+6 -1
src/lib/custom-animations/PressableScale.tsx
··· 1 - import {Pressable, PressableProps, StyleProp, ViewStyle} from 'react-native' 1 + import { 2 + Pressable, 3 + type PressableProps, 4 + type StyleProp, 5 + type ViewStyle, 6 + } from 'react-native' 2 7 import Animated, { 3 8 cancelAnimation, 4 9 useAnimatedStyle,
+2 -2
src/lib/hooks/useAccountSwitcher.ts
··· 4 4 5 5 import {logger} from '#/logger' 6 6 import {isWeb} from '#/platform/detection' 7 - import {SessionAccount, useSessionApi} from '#/state/session' 7 + import {type SessionAccount, useSessionApi} from '#/state/session' 8 8 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 9 9 import * as Toast from '#/view/com/util/Toast' 10 10 import {logEvent} from '../statsig/statsig' 11 - import {LogEvents} from '../statsig/statsig' 11 + import {type LogEvents} from '../statsig/statsig' 12 12 13 13 export function useAccountSwitcher() { 14 14 const [pendingDid, setPendingDid] = useState<string | null>(null)
+1 -1
src/lib/hooks/useAnimatedValue.ts
··· 2 2 import {Animated} from 'react-native' 3 3 4 4 export function useAnimatedValue(initialValue: number) { 5 - const lazyRef = React.useRef<Animated.Value>() 5 + const lazyRef = React.useRef<Animated.Value>(undefined) 6 6 7 7 if (lazyRef.current === undefined) { 8 8 lazyRef.current = new Animated.Value(initialValue)
+1 -1
src/lib/hooks/useGoBack.ts
··· 1 1 import {StackActions, useNavigation} from '@react-navigation/native' 2 2 3 - import {NavigationProp} from '#/lib/routes/types' 3 + import {type NavigationProp} from '#/lib/routes/types' 4 4 import {router} from '#/routes' 5 5 6 6 export function useGoBack(onGoBack?: () => unknown) {
+1 -1
src/lib/hooks/useOTAUpdates.ts
··· 127 127 const appState = React.useRef<AppStateStatus>('active') 128 128 const lastMinimize = React.useRef(0) 129 129 const ranInitialCheck = React.useRef(false) 130 - const timeout = React.useRef<NodeJS.Timeout>() 130 + const timeout = React.useRef<NodeJS.Timeout>(undefined) 131 131 const {currentlyRunning, isUpdatePending} = useUpdates() 132 132 const currentChannel = currentlyRunning?.channel 133 133
+1 -1
src/lib/hooks/useSetTitle.ts
··· 1 1 import {useEffect} from 'react' 2 2 import {useNavigation} from '@react-navigation/native' 3 3 4 - import {NavigationProp} from '#/lib/routes/types' 4 + import {type NavigationProp} from '#/lib/routes/types' 5 5 import {bskyTitle} from '#/lib/strings/headings' 6 6 import {useUnreadNotifications} from '#/state/queries/notifications/unread' 7 7
+1 -1
src/lib/hooks/useTimeAgo.ts
··· 1 1 import {useCallback} from 'react' 2 - import {I18n} from '@lingui/core' 2 + import {type I18n} from '@lingui/core' 3 3 import {defineMessage, msg, plural} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 import {differenceInSeconds} from 'date-fns'
+1 -1
src/lib/hooks/useWebScrollRestoration.ts
··· 1 1 import {useEffect, useMemo, useState} from 'react' 2 - import {EventArg, useNavigation} from '@react-navigation/core' 2 + import {type EventArg, useNavigation} from '@react-navigation/core' 3 3 4 4 if ('scrollRestoration' in history) { 5 5 // Tell the brower not to mess with the scroll.
+2 -2
src/lib/media/video/compress.web.ts
··· 1 - import {ImagePickerAsset} from 'expo-image-picker' 1 + import {type ImagePickerAsset} from 'expo-image-picker' 2 2 3 3 import {VIDEO_MAX_SIZE} from '#/lib/constants' 4 4 import {VideoTooLargeError} from '#/lib/media/video/errors' 5 - import {CompressedVideo} from './types' 5 + import {type CompressedVideo} from './types' 6 6 7 7 // doesn't actually compress, converts to ArrayBuffer 8 8 export async function compressVideo(
+2 -2
src/lib/media/video/upload.shared.ts
··· 1 - import {BskyAgent} from '@atproto/api' 2 - import {I18n} from '@lingui/core' 1 + import {type BskyAgent} from '@atproto/api' 2 + import {type I18n} from '@lingui/core' 3 3 import {msg} from '@lingui/macro' 4 4 5 5 import {VIDEO_SERVICE_DID} from '#/lib/constants'
+3 -3
src/lib/media/video/upload.ts
··· 1 1 import {createUploadTask, FileSystemUploadType} from 'expo-file-system' 2 - import {AppBskyVideoDefs, BskyAgent} from '@atproto/api' 3 - import {I18n} from '@lingui/core' 2 + import {type AppBskyVideoDefs, type BskyAgent} from '@atproto/api' 3 + import {type I18n} from '@lingui/core' 4 4 import {msg} from '@lingui/macro' 5 5 import {nanoid} from 'nanoid/non-secure' 6 6 7 7 import {AbortError} from '#/lib/async/cancelable' 8 8 import {ServerError} from '#/lib/media/video/errors' 9 - import {CompressedVideo} from '#/lib/media/video/types' 9 + import {type CompressedVideo} from '#/lib/media/video/types' 10 10 import {getServiceAuthToken, getVideoUploadLimits} from './upload.shared' 11 11 import {createVideoEndpointUrl, mimeToExt} from './util' 12 12
+4 -4
src/lib/media/video/upload.web.ts
··· 1 - import {AppBskyVideoDefs} from '@atproto/api' 2 - import {BskyAgent} from '@atproto/api' 3 - import {I18n} from '@lingui/core' 1 + import {type AppBskyVideoDefs} from '@atproto/api' 2 + import {type BskyAgent} from '@atproto/api' 3 + import {type I18n} from '@lingui/core' 4 4 import {msg} from '@lingui/macro' 5 5 import {nanoid} from 'nanoid/non-secure' 6 6 7 7 import {AbortError} from '#/lib/async/cancelable' 8 8 import {ServerError} from '#/lib/media/video/errors' 9 - import {CompressedVideo} from '#/lib/media/video/types' 9 + import {type CompressedVideo} from '#/lib/media/video/types' 10 10 import {getServiceAuthToken, getVideoUploadLimits} from './upload.shared' 11 11 import {createVideoEndpointUrl, mimeToExt} from './util' 12 12
+1 -1
src/lib/media/video/util.ts
··· 1 1 import {AtpAgent} from '@atproto/api' 2 2 3 - import {SupportedMimeTypes, VIDEO_SERVICE} from '#/lib/constants' 3 + import {type SupportedMimeTypes, VIDEO_SERVICE} from '#/lib/constants' 4 4 5 5 export const createVideoEndpointUrl = ( 6 6 route: string,
+1 -1
src/lib/merge-refs.ts
··· 13 13 * returns a ref callback function that can be used to merge multiple refs into a single ref. 14 14 */ 15 15 export function mergeRefs<T = any>( 16 - refs: Array<React.MutableRefObject<T> | React.LegacyRef<T>>, 16 + refs: Array<React.MutableRefObject<T> | React.Ref<T>>, 17 17 ): React.RefCallback<T> { 18 18 return value => { 19 19 refs.forEach(ref => {
+1 -1
src/lib/moderation/blocked-and-muted.ts
··· 1 - import * as bsky from '#/types/bsky' 1 + import type * as bsky from '#/types/bsky' 2 2 3 3 export function isBlockedOrBlocking(profile: bsky.profile.AnyProfileView) { 4 4 return profile.viewer?.blockedBy || profile.viewer?.blocking
+4 -1
src/lib/moderation/useLabelBehaviorDescription.ts
··· 1 - import {InterpretedLabelValueDefinition, LabelPreference} from '@atproto/api' 1 + import { 2 + type InterpretedLabelValueDefinition, 3 + type LabelPreference, 4 + } from '@atproto/api' 2 5 import {msg} from '@lingui/macro' 3 6 import {useLingui} from '@lingui/react' 4 7
+4 -4
src/lib/moderation/useLabelInfo.ts
··· 1 1 import { 2 - AppBskyLabelerDefs, 3 - ComAtprotoLabelDefs, 4 - InterpretedLabelValueDefinition, 2 + type AppBskyLabelerDefs, 3 + type ComAtprotoLabelDefs, 4 + type InterpretedLabelValueDefinition, 5 5 interpretLabelValueDefinition, 6 6 LABELS, 7 7 } from '@atproto/api' ··· 9 9 import * as bcp47Match from 'bcp-47-match' 10 10 11 11 import { 12 - GlobalLabelStrings, 12 + type GlobalLabelStrings, 13 13 useGlobalLabelStrings, 14 14 } from '#/lib/moderation/useGlobalLabelStrings' 15 15 import {useLabelDefinitions} from '#/state/preferences'
+4 -3
src/lib/react-query.tsx
··· 1 - import React, {useRef, useState} from 'react' 2 - import {AppState, AppStateStatus} from 'react-native' 1 + import {useRef, useState} from 'react' 2 + import {AppState, type AppStateStatus} from 'react-native' 3 3 import AsyncStorage from '@react-native-async-storage/async-storage' 4 4 import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister' 5 5 import {focusManager, onlineManager, QueryClient} from '@tanstack/react-query' 6 6 import { 7 7 PersistQueryClientProvider, 8 - PersistQueryClientProviderProps, 8 + type PersistQueryClientProviderProps, 9 9 } from '@tanstack/react-query-persist-client' 10 + import type React from 'react' 10 11 11 12 import {isNative} from '#/platform/detection' 12 13 import {listenNetworkConfirmed, listenNetworkLost} from '#/state/events'
+2 -2
src/lib/routes/helpers.ts
··· 1 - import {NavigationProp} from '@react-navigation/native' 1 + import {type NavigationProp} from '@react-navigation/native' 2 2 3 - import {RouteParams, State} from './types' 3 + import {type RouteParams, type State} from './types' 4 4 5 5 export function getRootNavigation<T extends {}>( 6 6 nav: NavigationProp<T>,
+1 -1
src/lib/strings/display-names.ts
··· 1 - import {ModerationUI} from '@atproto/api' 1 + import {type ModerationUI} from '@atproto/api' 2 2 3 3 // \u2705 = ✅ 4 4 // \u2713 = ✓
+1 -1
src/lib/strings/rich-text-helpers.ts
··· 1 - import {AppBskyRichtextFacet, RichText} from '@atproto/api' 1 + import {AppBskyRichtextFacet, type RichText} from '@atproto/api' 2 2 3 3 import {linkRequiresWarning} from './url-helpers' 4 4
+1 -1
src/lib/strings/rich-text-manip.ts
··· 1 - import {AppBskyRichtextFacet, RichText, UnicodeString} from '@atproto/api' 1 + import {AppBskyRichtextFacet, type RichText, UnicodeString} from '@atproto/api' 2 2 3 3 import {toShortUrl} from './url-helpers' 4 4
+1 -1
src/lib/strings/time.ts
··· 1 - import {I18n} from '@lingui/core' 1 + import {type I18n} from '@lingui/core' 2 2 3 3 export function niceDate(i18n: I18n, date: number | string | Date) { 4 4 const d = new Date(date)
+1 -1
src/lib/themes.ts
··· 4 4 import {darkPalette, dimPalette, lightPalette} from '#/alf/themes' 5 5 import {fontWeight} from '#/alf/tokens' 6 6 import {colors} from './styles' 7 - import type {Theme} from './ThemeContext' 7 + import {type Theme} from './ThemeContext' 8 8 9 9 export const defaultTheme: Theme = { 10 10 colorScheme: 'light',
+1 -1
src/locale/deviceLocales.ts
··· 1 - import {getLocales as defaultGetLocales, Locale} from 'expo-localization' 1 + import {getLocales as defaultGetLocales, type Locale} from 'expo-localization' 2 2 3 3 import {dedupArray} from '#/lib/functions' 4 4
+1 -1
src/locale/i18nProvider.tsx
··· 1 - import React from 'react' 2 1 import {i18n} from '@lingui/core' 3 2 import {I18nProvider as DefaultI18nProvider} from '@lingui/react' 3 + import type React from 'react' 4 4 5 5 import {useLocaleLanguage} from './i18n' 6 6
+562 -480
src/locale/locales/en/messages.po
··· 30 30 msgid "{0, plural, one {# day} other {# days}}" 31 31 msgstr "" 32 32 33 - #: src/screens/Profile/ProfileFollowers.tsx:40 33 + #: src/screens/Profile/ProfileFollowers.tsx:43 34 34 msgid "{0, plural, one {# follower} other {# followers}}" 35 35 msgstr "" 36 36 37 - #: src/screens/Profile/ProfileFollows.tsx:40 37 + #: src/screens/Profile/ProfileFollows.tsx:43 38 38 msgid "{0, plural, one {# following} other {# following}}" 39 39 msgstr "" 40 40 ··· 42 42 msgid "{0, plural, one {# hour} other {# hours}}" 43 43 msgstr "" 44 44 45 - #: src/components/moderation/LabelsOnMe.tsx:53 45 + #: src/components/moderation/LabelsOnMe.tsx:58 46 46 msgid "{0, plural, one {# label has} other {# labels have}} been placed on this account" 47 47 msgstr "" 48 48 49 - #: src/components/moderation/LabelsOnMe.tsx:62 49 + #: src/components/moderation/LabelsOnMe.tsx:67 50 50 msgid "{0, plural, one {# label has} other {# labels have}} been placed on this content" 51 51 msgstr "" 52 52 53 - #: src/screens/Post/PostLikedBy.tsx:41 53 + #: src/screens/Post/PostLikedBy.tsx:44 54 54 msgid "{0, plural, one {# like} other {# likes}}" 55 55 msgstr "" 56 56 ··· 62 62 msgid "{0, plural, one {# month} other {# months}}" 63 63 msgstr "" 64 64 65 - #: src/screens/Post/PostQuotes.tsx:41 65 + #: src/screens/Post/PostQuotes.tsx:44 66 66 msgid "{0, plural, one {# quote} other {# quotes}}" 67 67 msgstr "" 68 68 69 - #: src/screens/Post/PostRepostedBy.tsx:41 69 + #: src/screens/Post/PostRepostedBy.tsx:44 70 70 msgid "{0, plural, one {# repost} other {# reposts}}" 71 71 msgstr "" 72 72 ··· 112 112 msgid "{0, plural, one {repost} other {reposts}}" 113 113 msgstr "" 114 114 115 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:491 115 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:490 116 116 msgid "{0, plural, one {save} other {saves}}" 117 117 msgstr "" 118 118 ··· 159 159 msgid "{0} joined this week" 160 160 msgstr "" 161 161 162 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/Scrubber.tsx:204 162 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/Scrubber.tsx:203 163 163 msgid "{0} of {1}" 164 164 msgstr "" 165 165 ··· 184 184 msgid "{0}, a list by {1}" 185 185 msgstr "" 186 186 187 - #: src/view/com/util/UserAvatar.tsx:586 188 - #: src/view/com/util/UserAvatar.tsx:604 187 + #: src/view/com/util/UserAvatar.tsx:591 188 + #: src/view/com/util/UserAvatar.tsx:609 189 189 msgid "{0}'s avatar" 190 190 msgstr "" 191 191 ··· 423 423 msgid "{notificationCount, plural, one {# unread item} other {# unread items}}" 424 424 msgstr "" 425 425 426 - #: src/components/NewskieDialog.tsx:116 426 + #: src/components/NewskieDialog.tsx:131 427 427 msgid "{profileName} joined Bluesky {0} ago" 428 428 msgstr "" 429 429 430 - #: src/components/NewskieDialog.tsx:111 430 + #: src/components/NewskieDialog.tsx:126 431 431 msgid "{profileName} joined Bluesky using a starter pack {0} ago" 432 432 msgstr "" 433 433 ··· 510 510 msgid "24 hours" 511 511 msgstr "" 512 512 513 - #: src/screens/Login/LoginForm.tsx:293 513 + #: src/screens/Login/LoginForm.tsx:291 514 514 msgid "2FA Confirmation" 515 515 msgstr "" 516 516 ··· 522 522 msgid "7 days" 523 523 msgstr "" 524 524 525 - #: src/screens/Onboarding/StepFinished.tsx:341 525 + #: src/screens/Onboarding/StepFinished.tsx:337 526 526 msgid "A collection of popular feeds you can find on Bluesky, including News, Booksky, Game Dev, Blacksky, and Fountain Pens" 527 527 msgstr "" 528 528 ··· 544 544 msgid "A screenshot of a profile page with a bell icon next to the follow button, indicating the new activity notifications feature." 545 545 msgstr "" 546 546 547 - #: src/Navigation.tsx:529 547 + #: src/Navigation.tsx:516 548 548 #: src/screens/Settings/AboutSettings.tsx:73 549 549 #: src/screens/Settings/Settings.tsx:248 550 550 #: src/screens/Settings/Settings.tsx:251 ··· 571 571 msgid "Accessibility" 572 572 msgstr "" 573 573 574 - #: src/Navigation.tsx:383 574 + #: src/Navigation.tsx:370 575 575 msgid "Accessibility Settings" 576 576 msgstr "" 577 577 578 - #: src/Navigation.tsx:404 579 - #: src/screens/Login/LoginForm.tsx:210 578 + #: src/Navigation.tsx:391 579 + #: src/screens/Login/LoginForm.tsx:208 580 580 #: src/screens/Settings/AccountSettings.tsx:50 581 581 #: src/screens/Settings/Settings.tsx:172 582 582 #: src/screens/Settings/Settings.tsx:175 ··· 641 641 642 642 #: src/lib/hooks/useNotificationHandler.ts:182 643 643 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:102 644 - #: src/screens/Settings/NotificationSettings/index.tsx:192 644 + #: src/screens/Settings/NotificationSettings/index.tsx:129 645 645 msgid "Activity from others" 646 646 msgstr "" 647 647 648 - #: src/Navigation.tsx:497 648 + #: src/Navigation.tsx:484 649 649 msgid "Activity notifications" 650 650 msgstr "" 651 651 ··· 674 674 msgid "Add a temporary live status to your profile. When someone clicks on your avatar, they’ll see information about your live event." 675 675 msgstr "" 676 676 677 + #: src/screens/ProfileList/AboutSection.tsx:62 678 + #: src/screens/ProfileList/AboutSection.tsx:80 677 679 #: src/view/screens/ProfileList.tsx:942 678 680 #: src/view/screens/ProfileList.tsx:960 679 681 msgid "Add a user to this list" ··· 745 747 msgid "Add muted words and tags" 746 748 msgstr "" 747 749 750 + #: src/screens/ProfileList/AboutSection.tsx:70 751 + #: src/screens/ProfileList/AboutSection.tsx:88 748 752 #: src/view/screens/ProfileList.tsx:950 749 753 #: src/view/screens/ProfileList.tsx:968 750 754 msgid "Add people" ··· 766 770 msgid "Add some feeds to your starter pack!" 767 771 msgstr "" 768 772 769 - #: src/screens/Feeds/NoFollowingFeed.tsx:41 773 + #: src/screens/Feeds/NoFollowingFeed.tsx:39 770 774 msgid "Add the default feed of only people you follow" 771 775 msgstr "" 772 776 ··· 821 825 msgid "Adult Content" 822 826 msgstr "" 823 827 824 - #: src/screens/Moderation/index.tsx:343 828 + #: src/screens/Moderation/index.tsx:342 825 829 msgid "Adult content can only be enabled via the Web at <0>bsky.app</0>." 826 830 msgstr "" 827 831 828 - #: src/components/moderation/LabelPreference.tsx:242 832 + #: src/components/moderation/LabelPreference.tsx:244 829 833 msgid "Adult content is disabled." 830 834 msgstr "" 831 835 ··· 834 838 msgid "Adult Content labels" 835 839 msgstr "" 836 840 837 - #: src/screens/Moderation/index.tsx:387 841 + #: src/screens/Moderation/index.tsx:386 838 842 msgid "Advanced" 839 843 msgstr "" 840 844 ··· 868 872 msgid "Allow access to your direct messages" 869 873 msgstr "" 870 874 871 - #: src/screens/Messages/Settings.tsx:70 872 - #: src/screens/Messages/Settings.tsx:73 875 + #: src/screens/Messages/Settings.tsx:57 876 + #: src/screens/Messages/Settings.tsx:60 873 877 msgid "Allow new messages from" 874 878 msgstr "" 875 879 ··· 958 962 msgid "An error occurred while fetching the feed." 959 963 msgstr "" 960 964 961 - #: src/components/StarterPack/ProfileStarterPacks.tsx:343 965 + #: src/components/StarterPack/ProfileStarterPacks.tsx:339 962 966 msgid "An error occurred while generating your starter pack. Want to try again?" 963 967 msgstr "" 964 968 ··· 966 970 msgid "An error occurred while loading the video. Please try again later." 967 971 msgstr "" 968 972 969 - #: src/components/Post/Embed/VideoEmbed/index.web.tsx:227 973 + #: src/components/Post/Embed/VideoEmbed/index.web.tsx:232 970 974 msgid "An error occurred while loading the video. Please try again." 971 975 msgstr "" 972 976 973 - #: src/components/StarterPack/QrCodeDialog.tsx:72 977 + #: src/components/StarterPack/QrCodeDialog.tsx:75 974 978 msgid "An error occurred while saving the QR code!" 975 979 msgstr "" 976 980 ··· 983 987 msgid "An error occurred while uploading the video." 984 988 msgstr "" 985 989 986 - #: src/screens/Onboarding/StepFinished.tsx:359 990 + #: src/screens/Onboarding/StepFinished.tsx:355 987 991 msgid "An illustration of several Bluesky posts alongside repost, like, and comment icons" 988 992 msgstr "" 989 993 ··· 1063 1067 msgid "Anyone who follows me" 1064 1068 msgstr "" 1065 1069 1066 - #: src/Navigation.tsx:537 1070 + #: src/Navigation.tsx:524 1067 1071 #: src/screens/Settings/AppIconSettings/index.tsx:67 1068 1072 #: src/screens/Settings/AppIconSettings/SettingsListItem.tsx:18 1069 1073 #: src/screens/Settings/AppIconSettings/SettingsListItem.tsx:23 ··· 1100 1104 msgid "App passwords" 1101 1105 msgstr "" 1102 1106 1103 - #: src/Navigation.tsx:352 1107 + #: src/Navigation.tsx:339 1104 1108 #: src/screens/Settings/AppPasswords.tsx:51 1105 1109 msgid "App Passwords" 1106 1110 msgstr "" ··· 1136 1140 msgid "Appeal this decision" 1137 1141 msgstr "" 1138 1142 1139 - #: src/Navigation.tsx:397 1143 + #: src/Navigation.tsx:384 1140 1144 #: src/screens/Settings/AppearanceSettings.tsx:86 1141 1145 #: src/screens/Settings/Settings.tsx:210 1142 1146 #: src/screens/Settings/Settings.tsx:213 1143 1147 msgid "Appearance" 1144 1148 msgstr "" 1145 1149 1146 - #: src/screens/Feeds/NoSavedFeedsOfAnyType.tsx:47 1150 + #: src/screens/Feeds/NoSavedFeedsOfAnyType.tsx:51 1147 1151 #: src/screens/Home/NoFeedsPinned.tsx:93 1148 1152 msgid "Apply default recommended feeds" 1149 1153 msgstr "" ··· 1153 1157 msgid "Apply Pull Request" 1154 1158 msgstr "" 1155 1159 1156 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:665 1160 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:659 1157 1161 msgid "Archived from {0}" 1158 1162 msgstr "" 1159 1163 1160 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:634 1161 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:673 1164 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:628 1165 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:667 1162 1166 msgid "Archived post" 1163 1167 msgstr "" 1164 1168 ··· 1202 1206 msgid "Are you sure?" 1203 1207 msgstr "" 1204 1208 1205 - #: src/view/com/composer/select-language/SuggestedLanguage.tsx:87 1209 + #: src/view/com/composer/select-language/SuggestedLanguage.tsx:89 1206 1210 msgid "Are you writing in <0>{suggestedLanguageName}</0>?" 1207 1211 msgstr "" 1208 1212 ··· 1248 1252 #: src/screens/Login/ChooseAccountForm.tsx:95 1249 1253 #: src/screens/Login/ForgotPasswordForm.tsx:123 1250 1254 #: src/screens/Login/ForgotPasswordForm.tsx:129 1251 - #: src/screens/Login/LoginForm.tsx:335 1252 - #: src/screens/Login/LoginForm.tsx:341 1255 + #: src/screens/Login/LoginForm.tsx:333 1256 + #: src/screens/Login/LoginForm.tsx:339 1253 1257 #: src/screens/Login/SetNewPasswordForm.tsx:168 1254 1258 #: src/screens/Login/SetNewPasswordForm.tsx:174 1255 1259 #: src/screens/Messages/components/ChatDisabled.tsx:140 ··· 1262 1266 msgid "Back" 1263 1267 msgstr "" 1264 1268 1265 - #: src/screens/Messages/Inbox.tsx:238 1269 + #: src/screens/Messages/Inbox.tsx:244 1266 1270 msgid "Back to Chats" 1267 1271 msgstr "" 1268 1272 ··· 1276 1280 msgstr "" 1277 1281 1278 1282 #: src/components/dialogs/StarterPackDialog.tsx:71 1279 - #: src/components/StarterPack/ProfileStarterPacks.tsx:235 1280 - #: src/components/StarterPack/ProfileStarterPacks.tsx:245 1283 + #: src/components/StarterPack/ProfileStarterPacks.tsx:231 1284 + #: src/components/StarterPack/ProfileStarterPacks.tsx:241 1281 1285 msgid "Before creating a starter pack, you must first verify your email." 1282 1286 msgstr "" 1283 1287 ··· 1323 1327 msgid "Block Account?" 1324 1328 msgstr "" 1325 1329 1330 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:97 1331 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:100 1326 1332 #: src/view/screens/ProfileList.tsx:687 1327 1333 msgid "Block accounts" 1328 1334 msgstr "" ··· 1335 1341 msgid "Block and/or delete this conversation" 1336 1342 msgstr "" 1337 1343 1344 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:125 1338 1345 #: src/view/screens/ProfileList.tsx:807 1339 1346 msgid "Block list" 1340 1347 msgstr "" ··· 1343 1350 msgid "Block or report" 1344 1351 msgstr "" 1345 1352 1353 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:120 1346 1354 #: src/view/screens/ProfileList.tsx:802 1347 1355 msgid "Block these accounts?" 1348 1356 msgstr "" ··· 1361 1369 msgid "Blocked" 1362 1370 msgstr "" 1363 1371 1364 - #: src/screens/Moderation/index.tsx:275 1372 + #: src/screens/Moderation/index.tsx:274 1365 1373 msgid "Blocked accounts" 1366 1374 msgstr "" 1367 1375 1368 - #: src/Navigation.tsx:193 1376 + #: src/Navigation.tsx:180 1369 1377 #: src/view/screens/ModerationBlockedAccounts.tsx:104 1370 1378 msgid "Blocked Accounts" 1371 1379 msgstr "" ··· 1379 1387 msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you. You will not see their content and they will be prevented from seeing yours." 1380 1388 msgstr "" 1381 1389 1382 - #: src/screens/Profile/Sections/Labels.tsx:203 1390 + #: src/screens/Profile/Sections/Labels.tsx:204 1383 1391 msgid "Blocking does not prevent this labeler from placing labels on your account." 1384 1392 msgstr "" 1385 1393 1394 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:122 1386 1395 #: src/view/screens/ProfileList.tsx:804 1387 1396 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you." 1388 1397 msgstr "" ··· 1391 1400 msgid "Blocking will not prevent labels from being applied on your account, but it will stop this account from replying in your threads or interacting with you." 1392 1401 msgstr "" 1393 1402 1394 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:690 1403 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:684 1395 1404 msgid "Bluesky cannot confirm the authenticity of the claimed date." 1396 1405 msgstr "" 1397 1406 ··· 1412 1421 msgid "Bluesky Social Terms of Service" 1413 1422 msgstr "" 1414 1423 1415 - #: src/components/StarterPack/ProfileStarterPacks.tsx:310 1424 + #: src/components/StarterPack/ProfileStarterPacks.tsx:306 1416 1425 msgid "Bluesky will choose a set of recommended accounts from people in your network." 1417 1426 msgstr "" 1418 1427 ··· 1440 1449 msgid "Bluesky+ icons" 1441 1450 msgstr "" 1442 1451 1443 - #: src/lib/moderation/useLabelBehaviorDescription.ts:53 1452 + #: src/lib/moderation/useLabelBehaviorDescription.ts:56 1444 1453 msgid "Blur images" 1445 1454 msgstr "" 1446 1455 1447 - #: src/lib/moderation/useLabelBehaviorDescription.ts:51 1456 + #: src/lib/moderation/useLabelBehaviorDescription.ts:54 1448 1457 msgid "Blur images and filter from feeds" 1449 1458 msgstr "" 1450 1459 ··· 1648 1657 msgid "Change password dialog" 1649 1658 msgstr "" 1650 1659 1651 - #: src/view/com/composer/select-language/SuggestedLanguage.tsx:98 1660 + #: src/view/com/composer/select-language/SuggestedLanguage.tsx:100 1652 1661 msgid "Change post language to {suggestedLanguageName}" 1653 1662 msgstr "" 1654 1663 ··· 1674 1683 msgstr "" 1675 1684 1676 1685 #: src/lib/hooks/useNotificationHandler.ts:99 1677 - #: src/Navigation.tsx:554 1686 + #: src/Navigation.tsx:541 1678 1687 #: src/view/shell/bottom-bar/BottomBar.tsx:221 1679 1688 #: src/view/shell/desktop/LeftNav.tsx:609 1680 1689 #: src/view/shell/Drawer.tsx:466 ··· 1700 1709 msgid "Chat muted" 1701 1710 msgstr "" 1702 1711 1703 - #: src/Navigation.tsx:564 1712 + #: src/Navigation.tsx:551 1704 1713 #: src/screens/Messages/components/InboxPreview.tsx:22 1705 1714 msgid "Chat request inbox" 1706 1715 msgstr "" 1707 1716 1708 1717 #: src/screens/Messages/components/InboxPreview.tsx:62 1709 - #: src/screens/Messages/Inbox.tsx:77 1718 + #: src/screens/Messages/Inbox.tsx:83 1710 1719 msgid "Chat requests" 1711 1720 msgstr "" 1712 1721 1713 1722 #: src/components/dms/ConvoMenu.tsx:76 1714 - #: src/Navigation.tsx:559 1723 + #: src/Navigation.tsx:546 1715 1724 #: src/screens/Messages/ChatList.tsx:351 1716 1725 msgid "Chat settings" 1717 1726 msgstr "" 1718 1727 1719 - #: src/screens/Messages/Settings.tsx:62 1728 + #: src/screens/Messages/Settings.tsx:49 1720 1729 msgid "Chat Settings" 1721 1730 msgstr "" 1722 1731 ··· 1735 1744 msgid "Check my status" 1736 1745 msgstr "" 1737 1746 1738 - #: src/screens/Login/LoginForm.tsx:326 1747 + #: src/screens/Login/LoginForm.tsx:324 1739 1748 msgid "Check your email for a sign in code and enter it here." 1740 1749 msgstr "" 1741 1750 ··· 1751 1760 msgid "Choose Feeds" 1752 1761 msgstr "" 1753 1762 1754 - #: src/components/StarterPack/ProfileStarterPacks.tsx:318 1763 + #: src/components/StarterPack/ProfileStarterPacks.tsx:314 1755 1764 msgid "Choose for me" 1756 1765 msgstr "" 1757 1766 ··· 1763 1772 msgid "Choose Post Languages" 1764 1773 msgstr "" 1765 1774 1766 - #: src/screens/Onboarding/StepFinished.tsx:575 1775 + #: src/screens/Onboarding/StepFinished.tsx:571 1767 1776 msgid "Choose the algorithms that power your custom feeds." 1768 1777 msgstr "" 1769 1778 ··· 1808 1817 msgid "Click for information" 1809 1818 msgstr "" 1810 1819 1811 - #: src/view/screens/Support.tsx:41 1820 + #: src/view/screens/Support.tsx:44 1812 1821 msgid "click here" 1813 1822 msgstr "" 1814 1823 ··· 1858 1867 #: src/components/dms/ReportDialog.tsx:395 1859 1868 #: src/components/live/EditLiveDialog.tsx:229 1860 1869 #: src/components/live/EditLiveDialog.tsx:235 1861 - #: src/components/NewskieDialog.tsx:146 1862 - #: src/components/NewskieDialog.tsx:153 1870 + #: src/components/NewskieDialog.tsx:159 1871 + #: src/components/NewskieDialog.tsx:165 1863 1872 #: src/components/Post/Embed/ExternalEmbed/Gif.tsx:197 1864 1873 #: src/components/ProgressGuide/FollowDialog.tsx:379 1865 1874 #: src/components/StarterPack/Wizard/WizardEditListDialog.tsx:118 ··· 1885 1894 msgid "Close alert" 1886 1895 msgstr "" 1887 1896 1888 - #: src/view/com/util/BottomSheetCustomBackdrop.tsx:36 1897 + #: src/view/com/util/BottomSheetCustomBackdrop.tsx:37 1889 1898 msgid "Close bottom drawer" 1890 1899 msgstr "" 1891 1900 ··· 1983 1992 msgstr "" 1984 1993 1985 1994 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:45 1986 - #: src/Navigation.tsx:342 1987 - #: src/view/screens/CommunityGuidelines.tsx:34 1995 + #: src/Navigation.tsx:329 1996 + #: src/view/screens/CommunityGuidelines.tsx:37 1988 1997 msgid "Community Guidelines" 1989 1998 msgstr "" 1990 1999 1991 - #: src/screens/Onboarding/StepFinished.tsx:473 1992 - #: src/screens/Onboarding/StepFinished.tsx:588 2000 + #: src/screens/Onboarding/StepFinished.tsx:469 2001 + #: src/screens/Onboarding/StepFinished.tsx:584 1993 2002 msgid "Complete onboarding and start using your account" 1994 2003 msgstr "" 1995 2004 ··· 2013 2022 msgid "Compressing video..." 2014 2023 msgstr "" 2015 2024 2016 - #: src/components/moderation/LabelPreference.tsx:82 2025 + #: src/components/moderation/LabelPreference.tsx:84 2017 2026 msgid "Configure content filtering setting for category: {name}" 2018 2027 msgstr "" 2019 2028 2020 - #: src/components/moderation/LabelPreference.tsx:244 2029 + #: src/components/moderation/LabelPreference.tsx:246 2021 2030 msgid "Configured in <0>moderation settings</0>." 2022 2031 msgstr "" 2023 2032 ··· 2037 2046 msgstr "" 2038 2047 2039 2048 #: src/components/dialogs/EmailDialog/components/TokenField.tsx:36 2040 - #: src/screens/Login/LoginForm.tsx:299 2049 + #: src/screens/Login/LoginForm.tsx:297 2041 2050 #: src/screens/Settings/components/ChangePasswordDialog.tsx:186 2042 2051 #: src/screens/Settings/components/ChangePasswordDialog.tsx:190 2043 2052 #: src/screens/Settings/components/DisableEmail2FADialog.tsx:144 ··· 2047 2056 msgid "Confirmation code" 2048 2057 msgstr "" 2049 2058 2050 - #: src/screens/Login/LoginForm.tsx:362 2059 + #: src/screens/Login/LoginForm.tsx:360 2051 2060 msgid "Connecting..." 2052 2061 msgstr "" 2053 2062 ··· 2077 2086 msgid "Content and media" 2078 2087 msgstr "" 2079 2088 2080 - #: src/Navigation.tsx:513 2089 + #: src/Navigation.tsx:500 2081 2090 msgid "Content and Media" 2082 2091 msgstr "" 2083 2092 ··· 2117 2126 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:162 2118 2127 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:170 2119 2128 #: src/screens/Onboarding/StepInterests/index.tsx:254 2120 - #: src/screens/Onboarding/StepProfile/index.tsx:280 2129 + #: src/screens/Onboarding/StepProfile/index.tsx:273 2121 2130 #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:246 2122 2131 msgid "Continue" 2123 2132 msgstr "" ··· 2135 2144 msgstr "" 2136 2145 2137 2146 #: src/screens/Onboarding/StepInterests/index.tsx:251 2138 - #: src/screens/Onboarding/StepProfile/index.tsx:277 2147 + #: src/screens/Onboarding/StepProfile/index.tsx:270 2139 2148 #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:243 2140 2149 #: src/screens/Signup/BackNextButtons.tsx:60 2141 2150 msgid "Continue to next step" ··· 2182 2191 msgid "Copies build version to clipboard" 2183 2192 msgstr "" 2184 2193 2185 - #: src/components/StarterPack/QrCodeDialog.tsx:182 2194 + #: src/components/StarterPack/QrCodeDialog.tsx:192 2186 2195 msgid "Copy" 2187 2196 msgstr "" 2188 2197 ··· 2195 2204 msgid "Copy at:// URI" 2196 2205 msgstr "" 2197 2206 2198 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:169 2199 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:172 2207 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:168 2208 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:171 2200 2209 msgid "Copy author DID" 2201 2210 msgstr "" 2202 2211 ··· 2215 2224 msgid "Copy host" 2216 2225 msgstr "" 2217 2226 2218 - #: src/components/StarterPack/ShareDialog.tsx:104 2227 + #: src/components/StarterPack/ShareDialog.tsx:113 2219 2228 #: src/screens/StarterPack/StarterPackScreen.tsx:617 2220 2229 msgid "Copy link" 2221 2230 msgstr "" 2222 2231 2223 - #: src/components/StarterPack/ShareDialog.tsx:111 2232 + #: src/components/StarterPack/ShareDialog.tsx:119 2224 2233 msgid "Copy Link" 2225 2234 msgstr "" 2226 2235 2236 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:172 2237 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:176 2227 2238 #: src/view/screens/ProfileList.tsx:518 2228 2239 msgid "Copy link to list" 2229 2240 msgstr "" 2230 2241 2231 2242 #: src/components/PostControls/ShareMenu/ShareMenuItems.tsx:125 2232 2243 #: src/components/PostControls/ShareMenu/ShareMenuItems.tsx:128 2233 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:93 2234 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:96 2235 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:102 2244 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:92 2245 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:95 2246 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:101 2236 2247 msgid "Copy link to post" 2237 2248 msgstr "" 2238 2249 ··· 2250 2261 msgid "Copy message text" 2251 2262 msgstr "" 2252 2263 2253 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:160 2254 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:163 2264 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:159 2265 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:162 2255 2266 msgid "Copy post at:// URI" 2256 2267 msgstr "" 2257 2268 ··· 2260 2271 msgid "Copy post text" 2261 2272 msgstr "" 2262 2273 2263 - #: src/components/StarterPack/QrCodeDialog.tsx:176 2274 + #: src/components/StarterPack/QrCodeDialog.tsx:178 2264 2275 msgid "Copy QR code" 2265 2276 msgstr "" 2266 2277 ··· 2268 2279 msgid "Copy TXT record value" 2269 2280 msgstr "" 2270 2281 2271 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:105 2282 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:104 2272 2283 #: src/view/com/profile/ProfileMenu.tsx:279 2273 2284 #: src/view/com/profile/ProfileMenu.tsx:289 2274 2285 #: src/view/screens/ProfileList.tsx:530 ··· 2277 2288 2278 2289 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:40 2279 2290 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:107 2280 - #: src/Navigation.tsx:347 2281 - #: src/view/screens/CopyrightPolicy.tsx:31 2291 + #: src/Navigation.tsx:334 2292 + #: src/view/screens/CopyrightPolicy.tsx:34 2282 2293 msgid "Copyright Policy" 2283 2294 msgstr "" 2284 2295 ··· 2303 2314 msgid "Could not load feed" 2304 2315 msgstr "" 2305 2316 2317 + #: src/screens/ProfileList/components/ErrorScreen.tsx:26 2318 + #: src/screens/ProfileList/index.tsx:79 2319 + #: src/screens/ProfileList/index.tsx:101 2306 2320 #: src/view/screens/ProfileList.tsx:1047 2307 2321 msgid "Could not load list" 2308 2322 msgstr "" ··· 2327 2341 #. Text on button to create a new starter pack 2328 2342 #: src/components/dialogs/StarterPackDialog.tsx:112 2329 2343 #: src/components/dialogs/StarterPackDialog.tsx:201 2330 - #: src/components/StarterPack/ProfileStarterPacks.tsx:300 2344 + #: src/components/StarterPack/ProfileStarterPacks.tsx:296 2331 2345 msgid "Create" 2332 2346 msgstr "" 2333 2347 2334 - #: src/components/StarterPack/QrCodeDialog.tsx:160 2348 + #: src/components/StarterPack/QrCodeDialog.tsx:163 2335 2349 msgid "Create a QR code for a starter pack" 2336 2350 msgstr "" 2337 2351 2338 - #: src/components/StarterPack/ProfileStarterPacks.tsx:178 2339 - #: src/components/StarterPack/ProfileStarterPacks.tsx:287 2340 - #: src/Navigation.tsx:594 2352 + #: src/components/StarterPack/ProfileStarterPacks.tsx:174 2353 + #: src/components/StarterPack/ProfileStarterPacks.tsx:283 2354 + #: src/Navigation.tsx:581 2341 2355 msgid "Create a starter pack" 2342 2356 msgstr "" 2343 2357 2344 - #: src/components/StarterPack/ProfileStarterPacks.tsx:274 2358 + #: src/components/StarterPack/ProfileStarterPacks.tsx:270 2345 2359 msgid "Create a starter pack for me" 2346 2360 msgstr "" 2347 2361 ··· 2375 2389 msgid "Create an account without using this starter pack" 2376 2390 msgstr "" 2377 2391 2378 - #: src/screens/Onboarding/StepProfile/index.tsx:295 2392 + #: src/screens/Onboarding/StepProfile/index.tsx:288 2379 2393 msgid "Create an avatar instead" 2380 2394 msgstr "" 2381 2395 2382 - #: src/components/StarterPack/ProfileStarterPacks.tsx:185 2396 + #: src/components/StarterPack/ProfileStarterPacks.tsx:181 2383 2397 msgid "Create another" 2384 2398 msgstr "" 2385 2399 ··· 2389 2403 msgstr "" 2390 2404 2391 2405 #: src/components/moderation/ReportDialog/index.tsx:585 2392 - #: src/components/ReportDialog/SelectReportOptionView.tsx:99 2406 + #: src/components/ReportDialog/SelectReportOptionView.tsx:102 2393 2407 msgid "Create report for {0}" 2394 2408 msgstr "" 2395 2409 ··· 2467 2481 msgid "Deer" 2468 2482 msgstr "" 2469 2483 2470 - #: src/Navigation.tsx:390 2484 + #: src/Navigation.tsx:377 2471 2485 msgid "Deer Settings" 2472 2486 msgstr "" 2473 2487 ··· 2486 2500 #: src/components/dms/MessageContextMenu.tsx:185 2487 2501 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:802 2488 2502 #: src/screens/Messages/components/ChatStatusInfo.tsx:55 2503 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:285 2489 2504 #: src/screens/Settings/AppPasswords.tsx:212 2490 2505 #: src/screens/StarterPack/StarterPackScreen.tsx:599 2491 2506 #: src/screens/StarterPack/StarterPackScreen.tsx:688 ··· 2535 2550 msgid "Delete for me" 2536 2551 msgstr "" 2537 2552 2553 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:211 2554 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:214 2538 2555 #: src/view/screens/ProfileList.tsx:573 2539 2556 msgid "Delete list" 2540 2557 msgstr "" ··· 2566 2583 msgid "Delete starter pack?" 2567 2584 msgstr "" 2568 2585 2586 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:280 2569 2587 #: src/view/screens/ProfileList.tsx:781 2570 2588 msgid "Delete this list?" 2571 2589 msgstr "" ··· 2655 2673 msgid "Disable subtitles" 2656 2674 msgstr "" 2657 2675 2658 - #: src/lib/moderation/useLabelBehaviorDescription.ts:32 2659 - #: src/lib/moderation/useLabelBehaviorDescription.ts:42 2660 - #: src/lib/moderation/useLabelBehaviorDescription.ts:68 2661 - #: src/screens/Messages/Settings.tsx:139 2662 - #: src/screens/Messages/Settings.tsx:142 2663 - #: src/screens/Moderation/index.tsx:333 2676 + #: src/lib/moderation/useLabelBehaviorDescription.ts:35 2677 + #: src/lib/moderation/useLabelBehaviorDescription.ts:45 2678 + #: src/lib/moderation/useLabelBehaviorDescription.ts:71 2679 + #: src/screens/Moderation/index.tsx:332 2664 2680 msgid "Disabled" 2665 2681 msgstr "" 2666 2682 ··· 2733 2749 msgid "Display name" 2734 2750 msgstr "" 2735 2751 2736 - #: src/screens/Onboarding/StepFinished.tsx:347 2752 + #: src/screens/Onboarding/StepFinished.tsx:343 2737 2753 msgid "Ditch the trolls and clickbait. Find real people and conversations that matter to you." 2738 2754 msgstr "" 2739 2755 ··· 2786 2802 #: src/components/forms/DateField/index.tsx:109 2787 2803 #: src/components/Select/index.tsx:185 2788 2804 #: src/components/Select/index.tsx:192 2789 - #: src/screens/Onboarding/StepProfile/index.tsx:333 2790 - #: src/screens/Onboarding/StepProfile/index.tsx:336 2805 + #: src/screens/Onboarding/StepProfile/index.tsx:326 2806 + #: src/screens/Onboarding/StepProfile/index.tsx:329 2791 2807 #: src/screens/Settings/components/AddAppPasswordDialog.tsx:215 2792 2808 #: src/screens/Settings/components/AddAppPasswordDialog.tsx:222 2793 2809 #: src/view/com/auth/server-input/index.tsx:201 ··· 2821 2837 msgid "Double tap to close the dialog" 2822 2838 msgstr "" 2823 2839 2824 - #: src/screens/VideoFeed/index.tsx:1084 2840 + #: src/screens/VideoFeed/index.tsx:1085 2825 2841 msgid "Double tap to like" 2826 2842 msgstr "" 2827 2843 ··· 2829 2845 msgid "Download Bluesky" 2830 2846 msgstr "" 2831 2847 2832 - #: src/screens/Settings/components/ExportCarDialog.tsx:79 2833 - #: src/screens/Settings/components/ExportCarDialog.tsx:84 2848 + #: src/screens/Settings/components/ExportCarDialog.tsx:78 2849 + #: src/screens/Settings/components/ExportCarDialog.tsx:83 2834 2850 msgid "Download CAR file" 2835 2851 msgstr "" 2836 2852 ··· 2937 2953 msgid "Edit interests" 2938 2954 msgstr "" 2939 2955 2956 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:203 2957 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:206 2940 2958 #: src/view/screens/ProfileList.tsx:561 2941 2959 msgid "Edit list details" 2942 2960 msgstr "" ··· 2950 2968 msgid "Edit Moderation List" 2951 2969 msgstr "" 2952 2970 2953 - #: src/Navigation.tsx:357 2971 + #: src/Navigation.tsx:344 2954 2972 #: src/view/screens/Feeds.tsx:518 2955 2973 msgid "Edit My Feeds" 2956 2974 msgstr "" ··· 2992 3010 msgid "Edit who can reply" 2993 3011 msgstr "" 2994 3012 2995 - #: src/Navigation.tsx:599 3013 + #: src/Navigation.tsx:586 2996 3014 msgid "Edit your starter pack" 2997 3015 msgstr "" 2998 3016 ··· 3045 3063 3046 3064 #: src/components/dialogs/Embed.tsx:104 3047 3065 #: src/components/dialogs/Embed.tsx:108 3048 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:135 3049 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:140 3066 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:134 3067 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:139 3050 3068 msgid "Embed post" 3051 3069 msgstr "" 3052 3070 ··· 3068 3086 msgid "Enable {0} only" 3069 3087 msgstr "" 3070 3088 3071 - #: src/screens/Moderation/index.tsx:320 3089 + #: src/screens/Moderation/index.tsx:319 3072 3090 msgid "Enable adult content" 3073 3091 msgstr "" 3074 3092 ··· 3089 3107 msgid "Enable notifications for an account by visiting their profile and pressing the <0>bell icon</0> <1/>." 3090 3108 msgstr "" 3091 3109 3092 - #: src/screens/Settings/NotificationSettings/index.tsx:102 3093 - #: src/screens/Settings/NotificationSettings/index.tsx:106 3094 - msgid "Enable push notifications" 3095 - msgstr "" 3096 - 3097 3110 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:389 3098 3111 msgid "Enable subtitles" 3099 3112 msgstr "" ··· 3112 3125 msgid "Enable trending videos in your Discover feed" 3113 3126 msgstr "" 3114 3127 3115 - #: src/screens/Messages/Settings.tsx:130 3116 - #: src/screens/Messages/Settings.tsx:133 3117 - #: src/screens/Moderation/index.tsx:331 3128 + #: src/screens/Moderation/index.tsx:330 3118 3129 msgid "Enabled" 3119 3130 msgstr "" 3120 3131 3121 - #: src/screens/Profile/Sections/Feed.tsx:113 3132 + #: src/screens/Profile/Sections/Feed.tsx:109 3122 3133 msgid "End of feed" 3123 3134 msgstr "" 3124 3135 ··· 3153 3164 msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." 3154 3165 msgstr "" 3155 3166 3156 - #: src/screens/Login/LoginForm.tsx:243 3167 + #: src/screens/Login/LoginForm.tsx:241 3157 3168 msgid "Enter the username or email address you used when you created your account" 3158 3169 msgstr "" 3159 3170 ··· 3166 3177 msgid "Enter your email address" 3167 3178 msgstr "" 3168 3179 3169 - #: src/screens/Login/LoginForm.tsx:268 3180 + #: src/screens/Login/LoginForm.tsx:266 3170 3181 msgid "Enter your password" 3171 3182 msgstr "" 3172 3183 ··· 3227 3238 msgid "Everybody can reply to this post." 3228 3239 msgstr "" 3229 3240 3230 - #: src/screens/Messages/Settings.tsx:83 3231 - #: src/screens/Messages/Settings.tsx:86 3241 + #: src/screens/Messages/Settings.tsx:70 3242 + #: src/screens/Messages/Settings.tsx:73 3232 3243 #: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:164 3233 3244 #: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:174 3234 3245 msgid "Everyone" 3235 3246 msgstr "" 3236 3247 3237 - #: src/screens/Settings/NotificationSettings/index.tsx:235 3248 + #: src/screens/Settings/NotificationSettings/index.tsx:172 3238 3249 #: src/screens/Settings/NotificationSettings/MiscellaneousNotificationSettings.tsx:41 3239 3250 msgid "Everything else" 3240 3251 msgstr "" ··· 3289 3300 msgid "Expand post text" 3290 3301 msgstr "" 3291 3302 3292 - #: src/screens/VideoFeed/index.tsx:969 3303 + #: src/screens/VideoFeed/index.tsx:970 3293 3304 msgid "Expands or collapses post text" 3294 3305 msgstr "" 3295 3306 ··· 3327 3338 msgid "Explicit sexual images." 3328 3339 msgstr "" 3329 3340 3330 - #: src/Navigation.tsx:764 3341 + #: src/Navigation.tsx:751 3331 3342 #: src/screens/Search/Shell.tsx:307 3332 3343 #: src/view/shell/desktop/LeftNav.tsx:691 3333 3344 #: src/view/shell/Drawer.tsx:414 ··· 3363 3374 msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." 3364 3375 msgstr "" 3365 3376 3366 - #: src/Navigation.tsx:376 3377 + #: src/Navigation.tsx:363 3367 3378 #: src/screens/Settings/ExternalMediaPreferences.tsx:34 3368 3379 msgid "External Media Preferences" 3369 3380 msgstr "" ··· 3373 3384 msgid "Failed to accept chat" 3374 3385 msgstr "" 3375 3386 3376 - #: src/components/dms/ActionsWrapper.web.tsx:67 3387 + #: src/components/dms/ActionsWrapper.web.tsx:66 3377 3388 #: src/components/dms/MessageContextMenu.tsx:99 3378 3389 msgid "Failed to add emoji reaction" 3379 3390 msgstr "" ··· 3426 3437 msgstr "" 3427 3438 3428 3439 #: src/screens/Messages/ChatList.tsx:254 3429 - #: src/screens/Messages/Inbox.tsx:187 3440 + #: src/screens/Messages/Inbox.tsx:193 3430 3441 msgid "Failed to load conversations" 3431 3442 msgstr "" 3432 3443 ··· 3442 3453 msgstr "" 3443 3454 3444 3455 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:114 3445 - #: src/screens/Settings/NotificationSettings/index.tsx:115 3456 + #: src/screens/Settings/NotificationSettings/index.tsx:52 3446 3457 #: src/screens/Settings/NotificationSettings/LikeNotificationSettings.tsx:50 3447 3458 #: src/screens/Settings/NotificationSettings/LikesOnRepostsNotificationSettings.tsx:52 3448 3459 #: src/screens/Settings/NotificationSettings/MentionNotificationSettings.tsx:50 ··· 3474 3485 msgid "Failed to load suggested follows" 3475 3486 msgstr "" 3476 3487 3477 - #: src/screens/Messages/Inbox.tsx:295 3478 - #: src/screens/Messages/Inbox.tsx:318 3488 + #: src/screens/Messages/Inbox.tsx:301 3489 + #: src/screens/Messages/Inbox.tsx:324 3479 3490 msgid "Failed to mark all requests as read" 3480 3491 msgstr "" 3481 3492 ··· 3483 3494 msgid "Failed to pin post" 3484 3495 msgstr "" 3485 3496 3486 - #: src/components/dms/ActionsWrapper.web.tsx:61 3497 + #: src/components/dms/ActionsWrapper.web.tsx:60 3487 3498 #: src/components/dms/MessageContextMenu.tsx:93 3488 3499 msgid "Failed to remove emoji reaction" 3489 3500 msgstr "" ··· 3527 3538 msgid "Failed to toggle thread mute, please try again" 3528 3539 msgstr "" 3529 3540 3541 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:111 3542 + msgid "Failed to unpin list" 3543 + msgstr "" 3544 + 3530 3545 #: src/components/dialogs/EmailDialog/screens/Manage2FA/Disable.tsx:149 3531 3546 #: src/components/dialogs/EmailDialog/screens/Manage2FA/Enable.tsx:83 3532 3547 msgid "Failed to update email 2FA settings" ··· 3544 3559 msgid "Failed to update notification declaration" 3545 3560 msgstr "" 3546 3561 3547 - #: src/screens/Messages/Settings.tsx:34 3562 + #: src/screens/Messages/Settings.tsx:30 3548 3563 msgid "Failed to update settings" 3549 3564 msgstr "" 3550 3565 ··· 3567 3582 msgid "Fall back to constellation api to find blocked replies" 3568 3583 msgstr "" 3569 3584 3570 - #: src/Navigation.tsx:292 3585 + #: src/Navigation.tsx:279 3571 3586 msgid "Feed" 3572 3587 msgstr "" 3573 3588 ··· 3608 3623 msgid "Feedback sent to feed operator" 3609 3624 msgstr "" 3610 3625 3611 - #: src/Navigation.tsx:579 3626 + #: src/Navigation.tsx:566 3627 + #: src/screens/SavedFeeds.tsx:108 3612 3628 #: src/screens/Search/SearchResults.tsx:73 3613 3629 #: src/screens/StarterPack/StarterPackScreen.tsx:190 3614 3630 #: src/view/screens/Feeds.tsx:511 3615 3631 #: src/view/screens/Profile.tsx:230 3616 - #: src/view/screens/SavedFeeds.tsx:104 3617 3632 #: src/view/shell/desktop/LeftNav.tsx:729 3618 3633 #: src/view/shell/Drawer.tsx:530 3619 3634 msgid "Feeds" 3620 3635 msgstr "" 3621 3636 3622 - #: src/view/screens/SavedFeeds.tsx:206 3623 - msgid "Feeds are custom algorithms that users build with a little coding expertise. <0/> for more information." 3637 + #: src/screens/SavedFeeds.tsx:215 3638 + msgid "Feeds are custom algorithms that users build with a little coding expertise. <0>See this guide</0> for more information." 3624 3639 msgstr "" 3625 3640 3626 3641 #: src/components/FeedCard.tsx:282 3627 - #: src/view/screens/SavedFeeds.tsx:86 3642 + #: src/screens/SavedFeeds.tsx:90 3628 3643 msgctxt "toast" 3629 3644 msgid "Feeds updated!" 3630 3645 msgstr "" ··· 3649 3664 msgid "File saved successfully!" 3650 3665 msgstr "" 3651 3666 3652 - #: src/lib/moderation/useLabelBehaviorDescription.ts:66 3667 + #: src/lib/moderation/useLabelBehaviorDescription.ts:69 3653 3668 msgid "Filter from feeds" 3654 3669 msgstr "" 3655 3670 ··· 3669 3684 msgid "Filter who you receive notifications from" 3670 3685 msgstr "" 3671 3686 3672 - #: src/screens/Onboarding/StepFinished.tsx:479 3673 - #: src/screens/Onboarding/StepFinished.tsx:591 3687 + #: src/screens/Onboarding/StepFinished.tsx:475 3688 + #: src/screens/Onboarding/StepFinished.tsx:587 3674 3689 msgid "Finalizing" 3675 3690 msgstr "" 3676 3691 ··· 3694 3709 msgid "Find posts, users, and feeds on Bluesky" 3695 3710 msgstr "" 3696 3711 3697 - #: src/screens/Onboarding/StepFinished.tsx:345 3712 + #: src/screens/Onboarding/StepFinished.tsx:341 3698 3713 msgid "Find your people" 3699 3714 msgstr "" 3700 3715 ··· 3706 3721 msgid "Fitness" 3707 3722 msgstr "" 3708 3723 3709 - #: src/screens/Onboarding/StepFinished.tsx:571 3724 + #: src/screens/Onboarding/StepFinished.tsx:567 3710 3725 msgid "Flexible" 3711 3726 msgstr "" 3712 3727 ··· 3790 3805 msgid "Followed by <0>{0}</0>, <1>{1}</1>, and {2, plural, one {# other} other {# others}}" 3791 3806 msgstr "" 3792 3807 3793 - #: src/Navigation.tsx:246 3808 + #: src/Navigation.tsx:233 3794 3809 msgid "Followers of @{0} that you know" 3795 3810 msgstr "" 3796 3811 3797 - #: src/screens/Profile/KnownFollowers.tsx:104 3798 - #: src/screens/Profile/KnownFollowers.tsx:121 3812 + #: src/screens/Profile/KnownFollowers.tsx:107 3813 + #: src/screens/Profile/KnownFollowers.tsx:124 3799 3814 msgid "Followers you know" 3800 3815 msgstr "" 3801 3816 ··· 3809 3824 msgid "Following" 3810 3825 msgstr "" 3811 3826 3827 + #: src/screens/SavedFeeds.tsx:410 3812 3828 #: src/view/screens/Feeds.tsx:603 3813 - #: src/view/screens/SavedFeeds.tsx:420 3814 3829 msgctxt "feed-name" 3815 3830 msgid "Following" 3816 3831 msgstr "" ··· 3829 3844 msgid "Following feed preferences" 3830 3845 msgstr "" 3831 3846 3832 - #: src/Navigation.tsx:363 3847 + #: src/Navigation.tsx:350 3833 3848 #: src/screens/Settings/FollowingFeedPreferences.tsx:56 3834 3849 msgid "Following Feed Preferences" 3835 3850 msgstr "" ··· 3876 3891 msgid "Forever" 3877 3892 msgstr "" 3878 3893 3879 - #: src/screens/Onboarding/StepFinished.tsx:354 3894 + #: src/screens/Onboarding/StepFinished.tsx:350 3880 3895 msgid "Forget the noise" 3881 3896 msgstr "" 3882 3897 ··· 3885 3900 msgid "Forgot Password" 3886 3901 msgstr "" 3887 3902 3888 - #: src/screens/Login/LoginForm.tsx:273 3903 + #: src/screens/Login/LoginForm.tsx:271 3889 3904 msgid "Forgot password?" 3890 3905 msgstr "" 3891 3906 3892 - #: src/screens/Login/LoginForm.tsx:284 3907 + #: src/screens/Login/LoginForm.tsx:282 3893 3908 msgid "Forgot?" 3894 3909 msgstr "" 3895 3910 3896 - #: src/screens/Onboarding/StepFinished.tsx:336 3911 + #: src/screens/Onboarding/StepFinished.tsx:332 3897 3912 msgid "Free your feed" 3898 3913 msgstr "" 3899 3914 ··· 3919 3934 msgid "Gates" 3920 3935 msgstr "" 3921 3936 3922 - #: src/components/StarterPack/ProfileStarterPacks.tsx:307 3937 + #: src/components/StarterPack/ProfileStarterPacks.tsx:303 3923 3938 msgid "Generate a starter pack" 3924 3939 msgstr "" 3925 3940 ··· 4000 4015 msgid "Github" 4001 4016 msgstr "" 4002 4017 4003 - #: src/screens/Onboarding/StepProfile/index.tsx:235 4018 + #: src/screens/Onboarding/StepProfile/index.tsx:228 4004 4019 msgid "Give your profile a face" 4005 4020 msgstr "" 4006 4021 ··· 4014 4029 #: src/components/Layout/Header/index.tsx:128 4015 4030 #: src/components/moderation/ScreenHider.tsx:154 4016 4031 #: src/components/moderation/ScreenHider.tsx:163 4017 - #: src/screens/Messages/Inbox.tsx:228 4032 + #: src/screens/Messages/Inbox.tsx:234 4018 4033 #: src/screens/Profile/ProfileFeed/index.tsx:92 4034 + #: src/screens/ProfileList/components/ErrorScreen.tsx:34 4035 + #: src/screens/ProfileList/components/ErrorScreen.tsx:40 4019 4036 #: src/screens/VideoFeed/components/Header.tsx:163 4020 - #: src/screens/VideoFeed/index.tsx:1145 4021 - #: src/screens/VideoFeed/index.tsx:1149 4037 + #: src/screens/VideoFeed/index.tsx:1146 4038 + #: src/screens/VideoFeed/index.tsx:1150 4022 4039 #: src/view/com/auth/LoggedOut.tsx:72 4023 4040 #: src/view/screens/NotFound.tsx:57 4024 4041 #: src/view/screens/ProfileList.tsx:1056 ··· 4037 4054 msgstr "" 4038 4055 4039 4056 #: src/components/dms/ReportDialog.tsx:197 4040 - #: src/components/ReportDialog/SelectReportOptionView.tsx:78 4057 + #: src/components/ReportDialog/SelectReportOptionView.tsx:81 4041 4058 #: src/components/ReportDialog/SubmitView.tsx:110 4042 4059 #: src/screens/Onboarding/Layout.tsx:121 4043 4060 #: src/screens/Onboarding/Layout.tsx:214 ··· 4136 4153 msgid "Harassment, trolling, or intolerance" 4137 4154 msgstr "" 4138 4155 4139 - #: src/Navigation.tsx:544 4156 + #: src/Navigation.tsx:531 4140 4157 msgid "Hashtag" 4141 4158 msgstr "" 4142 4159 ··· 4161 4178 msgid "Help" 4162 4179 msgstr "" 4163 4180 4164 - #: src/screens/Onboarding/StepProfile/index.tsx:238 4181 + #: src/screens/Onboarding/StepProfile/index.tsx:231 4165 4182 msgid "Help people know you're not a bot by uploading a picture or creating an avatar." 4166 4183 msgstr "" 4167 4184 ··· 4190 4207 #: src/components/interstitials/Trending.tsx:131 4191 4208 #: src/components/interstitials/TrendingVideos.tsx:138 4192 4209 #: src/components/moderation/ContentHider.tsx:203 4193 - #: src/components/moderation/LabelPreference.tsx:135 4210 + #: src/components/moderation/LabelPreference.tsx:137 4194 4211 #: src/components/moderation/PostHider.tsx:134 4195 4212 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:813 4196 - #: src/lib/moderation/useLabelBehaviorDescription.ts:15 4197 - #: src/lib/moderation/useLabelBehaviorDescription.ts:20 4198 - #: src/lib/moderation/useLabelBehaviorDescription.ts:25 4199 - #: src/lib/moderation/useLabelBehaviorDescription.ts:30 4213 + #: src/lib/moderation/useLabelBehaviorDescription.ts:18 4214 + #: src/lib/moderation/useLabelBehaviorDescription.ts:23 4215 + #: src/lib/moderation/useLabelBehaviorDescription.ts:28 4216 + #: src/lib/moderation/useLabelBehaviorDescription.ts:33 4200 4217 #: src/view/shell/desktop/SidebarTrendingTopics.tsx:111 4201 4218 msgid "Hide" 4202 4219 msgstr "" ··· 4291 4308 msgid "Hmm, we're having trouble finding this feed. It may have been deleted." 4292 4309 msgstr "" 4293 4310 4294 - #: src/screens/Moderation/index.tsx:55 4311 + #: src/screens/Moderation/index.tsx:54 4295 4312 msgid "Hmmmm, it seems we're having trouble loading this data. See below for more details. If this issue persists, please contact us." 4296 4313 msgstr "" 4297 4314 ··· 4303 4320 msgid "Hold up! We’re gradually giving access to video, and you’re still waiting in line. Check back soon!" 4304 4321 msgstr "" 4305 4322 4306 - #: src/Navigation.tsx:759 4307 - #: src/Navigation.tsx:779 4323 + #: src/Navigation.tsx:746 4324 + #: src/Navigation.tsx:766 4308 4325 #: src/view/shell/bottom-bar/BottomBar.tsx:178 4309 4326 #: src/view/shell/desktop/LeftNav.tsx:673 4310 4327 #: src/view/shell/Drawer.tsx:440 ··· 4316 4333 msgstr "" 4317 4334 4318 4335 #: src/screens/Login/ForgotPasswordForm.tsx:83 4319 - #: src/screens/Login/LoginForm.tsx:193 4336 + #: src/screens/Login/LoginForm.tsx:191 4320 4337 msgid "Hosting provider" 4321 4338 msgstr "" 4322 4339 ··· 4352 4369 msgid "If you are not yet an adult according to the laws of your country, your parent or legal guardian must read these Terms on your behalf." 4353 4370 msgstr "" 4354 4371 4372 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:282 4355 4373 #: src/view/screens/ProfileList.tsx:783 4356 4374 msgid "If you delete this list, you won't be able to recover it." 4357 4375 msgstr "" ··· 4397 4415 msgid "Illegal and Urgent" 4398 4416 msgstr "" 4399 4417 4400 - #: src/view/com/util/images/Gallery.tsx:76 4418 + #: src/view/com/util/images/Gallery.tsx:75 4401 4419 msgid "Image" 4402 4420 msgstr "" 4403 4421 ··· 4432 4450 msgid "Impersonation, misinformation, or false claims" 4433 4451 msgstr "" 4434 4452 4435 - #: src/screens/Settings/NotificationSettings/index.tsx:284 4453 + #: src/screens/Settings/NotificationSettings/index.tsx:221 4436 4454 msgid "In-app" 4437 4455 msgstr "" 4438 4456 ··· 4440 4458 msgid "In-app notifications" 4441 4459 msgstr "" 4442 4460 4443 - #: src/screens/Settings/NotificationSettings/index.tsx:267 4461 + #: src/screens/Settings/NotificationSettings/index.tsx:204 4444 4462 msgid "In-app, Everyone" 4445 4463 msgstr "" 4446 4464 4447 - #: src/screens/Settings/NotificationSettings/index.tsx:275 4465 + #: src/screens/Settings/NotificationSettings/index.tsx:212 4448 4466 msgid "In-app, People you follow" 4449 4467 msgstr "" 4450 4468 4451 - #: src/screens/Settings/NotificationSettings/index.tsx:282 4469 + #: src/screens/Settings/NotificationSettings/index.tsx:219 4452 4470 msgid "In-app, Push" 4453 4471 msgstr "" 4454 4472 4455 - #: src/screens/Settings/NotificationSettings/index.tsx:265 4473 + #: src/screens/Settings/NotificationSettings/index.tsx:202 4456 4474 msgid "In-app, Push, Everyone" 4457 4475 msgstr "" 4458 4476 4459 - #: src/screens/Settings/NotificationSettings/index.tsx:273 4477 + #: src/screens/Settings/NotificationSettings/index.tsx:210 4460 4478 msgid "In-app, Push, People you follow" 4461 4479 msgstr "" 4462 4480 ··· 4466 4484 msgstr "" 4467 4485 4468 4486 #. Title message shown in chat requests inbox when it's empty 4469 - #: src/screens/Messages/Inbox.tsx:208 4487 + #: src/screens/Messages/Inbox.tsx:214 4470 4488 msgid "Inbox zero!" 4471 4489 msgstr "" 4472 4490 4473 - #: src/screens/Login/LoginForm.tsx:173 4491 + #: src/screens/Login/LoginForm.tsx:171 4474 4492 msgid "Incorrect username or password" 4475 4493 msgstr "" 4476 4494 ··· 4490 4508 msgid "Input password for account deletion" 4491 4509 msgstr "" 4492 4510 4493 - #: src/screens/Login/LoginForm.tsx:314 4511 + #: src/screens/Login/LoginForm.tsx:312 4494 4512 msgid "Input the code which has been emailed to you" 4495 4513 msgstr "" 4496 4514 ··· 4502 4520 msgid "Interaction limited" 4503 4521 msgstr "" 4504 4522 4505 - #: src/screens/Moderation/index.tsx:215 4523 + #: src/screens/Moderation/index.tsx:214 4506 4524 msgid "Interaction settings" 4507 4525 msgstr "" 4508 4526 ··· 4514 4532 msgid "Introducing saved posts AKA bookmarks" 4515 4533 msgstr "" 4516 4534 4517 - #: src/screens/Login/LoginForm.tsx:165 4535 + #: src/screens/Login/LoginForm.tsx:163 4518 4536 #: src/screens/Settings/components/DisableEmail2FADialog.tsx:70 4519 4537 msgid "Invalid 2FA confirmation code." 4520 4538 msgstr "" ··· 4551 4569 msgid "Invite codes: 1 available" 4552 4570 msgstr "" 4553 4571 4554 - #: src/components/StarterPack/ShareDialog.tsx:77 4572 + #: src/components/StarterPack/ShareDialog.tsx:81 4555 4573 msgid "Invite people to this starter pack!" 4556 4574 msgstr "" 4557 4575 ··· 4622 4640 msgid "Labels added" 4623 4641 msgstr "" 4624 4642 4625 - #: src/screens/Profile/Sections/Labels.tsx:194 4643 + #: src/screens/Profile/Sections/Labels.tsx:195 4626 4644 msgid "Labels are annotations on users and content. They can be used to hide, warn, and categorize the network." 4627 4645 msgstr "" 4628 4646 ··· 4634 4652 msgid "Labels on your content" 4635 4653 msgstr "" 4636 4654 4637 - #: src/Navigation.tsx:219 4655 + #: src/Navigation.tsx:206 4638 4656 msgid "Language Settings" 4639 4657 msgstr "" 4640 4658 ··· 4736 4754 msgid "left to go." 4737 4755 msgstr "" 4738 4756 4739 - #: src/components/StarterPack/ProfileStarterPacks.tsx:323 4757 + #: src/components/StarterPack/ProfileStarterPacks.tsx:319 4740 4758 msgid "Let me choose" 4741 4759 msgstr "" 4742 4760 ··· 4745 4763 msgid "Let's get your password reset!" 4746 4764 msgstr "" 4747 4765 4748 - #: src/screens/Onboarding/StepFinished.tsx:481 4749 - #: src/screens/Onboarding/StepFinished.tsx:591 4766 + #: src/screens/Onboarding/StepFinished.tsx:477 4767 + #: src/screens/Onboarding/StepFinished.tsx:587 4750 4768 msgid "Let's go!" 4751 4769 msgstr "" 4752 4770 ··· 4779 4797 msgid "Like 10 posts to train the Discover feed" 4780 4798 msgstr "" 4781 4799 4782 - #: src/Navigation.tsx:457 4800 + #: src/Navigation.tsx:444 4783 4801 msgid "Like notifications" 4784 4802 msgstr "" 4785 4803 ··· 4791 4809 msgid "Like this labeler" 4792 4810 msgstr "" 4793 4811 4794 - #: src/Navigation.tsx:297 4795 - #: src/Navigation.tsx:302 4812 + #: src/Navigation.tsx:284 4813 + #: src/Navigation.tsx:289 4796 4814 msgid "Liked by" 4797 4815 msgstr "" 4798 4816 4799 - #: src/screens/Post/PostLikedBy.tsx:38 4800 - #: src/screens/Profile/ProfileLabelerLikedBy.tsx:29 4801 - #: src/view/screens/ProfileFeedLikedBy.tsx:30 4817 + #: src/screens/Post/PostLikedBy.tsx:41 4818 + #: src/screens/Profile/ProfileLabelerLikedBy.tsx:32 4819 + #: src/view/screens/ProfileFeedLikedBy.tsx:33 4802 4820 msgid "Liked By" 4803 4821 msgstr "" 4804 4822 ··· 4815 4833 msgstr "" 4816 4834 4817 4835 #: src/lib/hooks/useNotificationHandler.ts:126 4818 - #: src/screens/Settings/NotificationSettings/index.tsx:126 4836 + #: src/screens/Settings/NotificationSettings/index.tsx:63 4819 4837 #: src/screens/Settings/NotificationSettings/LikeNotificationSettings.tsx:41 4820 4838 #: src/view/screens/Profile.tsx:229 4821 4839 msgid "Likes" 4822 4840 msgstr "" 4823 4841 4824 4842 #: src/lib/hooks/useNotificationHandler.ts:168 4825 - #: src/screens/Settings/NotificationSettings/index.tsx:207 4843 + #: src/screens/Settings/NotificationSettings/index.tsx:144 4826 4844 #: src/screens/Settings/NotificationSettings/LikesOnRepostsNotificationSettings.tsx:41 4827 4845 msgid "Likes of your reposts" 4828 4846 msgstr "" 4829 4847 4830 - #: src/Navigation.tsx:481 4848 + #: src/Navigation.tsx:468 4831 4849 msgid "Likes of your reposts notifications" 4832 4850 msgstr "" 4833 4851 ··· 4840 4858 msgid "Linear" 4841 4859 msgstr "" 4842 4860 4843 - #: src/Navigation.tsx:252 4861 + #: src/Navigation.tsx:239 4844 4862 msgid "List" 4845 4863 msgstr "" 4846 4864 ··· 4848 4866 msgid "List Avatar" 4849 4867 msgstr "" 4850 4868 4869 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:50 4851 4870 #: src/view/screens/ProfileList.tsx:438 4852 4871 msgctxt "toast" 4853 4872 msgid "List blocked" ··· 4870 4889 msgid "List creator" 4871 4890 msgstr "" 4872 4891 4892 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:97 4873 4893 #: src/view/screens/ProfileList.tsx:485 4874 4894 msgctxt "toast" 4875 4895 msgid "List deleted" ··· 4879 4899 msgid "List has been hidden" 4880 4900 msgstr "" 4881 4901 4902 + #: src/screens/ProfileList/index.tsx:172 4882 4903 #: src/view/screens/ProfileList.tsx:176 4883 4904 msgid "List Hidden" 4884 4905 msgstr "" 4885 4906 4907 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:31 4886 4908 #: src/view/screens/ProfileList.tsx:402 4887 4909 msgctxt "toast" 4888 4910 msgid "List muted" ··· 4892 4914 msgid "List Name" 4893 4915 msgstr "" 4894 4916 4917 + #: src/screens/ProfileList/components/Header.tsx:116 4918 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:138 4895 4919 #: src/view/screens/ProfileList.tsx:456 4896 4920 msgctxt "toast" 4897 4921 msgid "List unblocked" 4898 4922 msgstr "" 4899 4923 4924 + #: src/screens/ProfileList/components/Header.tsx:98 4925 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:120 4900 4926 #: src/view/screens/ProfileList.tsx:420 4901 4927 msgctxt "toast" 4902 4928 msgid "List unmuted" 4903 4929 msgstr "" 4904 4930 4905 - #: src/Navigation.tsx:173 4931 + #: src/Navigation.tsx:160 4906 4932 #: src/view/screens/Lists.tsx:65 4907 4933 #: src/view/screens/Profile.tsx:224 4908 4934 #: src/view/screens/Profile.tsx:232 ··· 4945 4971 msgstr "" 4946 4972 4947 4973 #: src/screens/Profile/ProfileFeed/index.tsx:224 4948 - #: src/screens/Profile/Sections/Feed.tsx:98 4949 - #: src/view/com/feeds/FeedPage.tsx:162 4974 + #: src/screens/Profile/Sections/Feed.tsx:94 4975 + #: src/screens/ProfileList/FeedSection.tsx:105 4976 + #: src/view/com/feeds/FeedPage.tsx:169 4950 4977 #: src/view/screens/ProfileList.tsx:896 4951 4978 msgid "Load new posts" 4952 4979 msgstr "" ··· 4955 4982 msgid "Loading..." 4956 4983 msgstr "" 4957 4984 4958 - #: src/Navigation.tsx:322 4985 + #: src/Navigation.tsx:309 4959 4986 msgid "Log" 4960 4987 msgstr "" 4961 4988 ··· 4980 5007 msgid "Looks like XXXXX-XXXXX" 4981 5008 msgstr "" 4982 5009 4983 - #: src/screens/Feeds/NoSavedFeedsOfAnyType.tsx:39 5010 + #: src/screens/Feeds/NoSavedFeedsOfAnyType.tsx:43 4984 5011 msgid "Looks like you haven't saved any feeds! Use our recommendations or browse more below." 4985 5012 msgstr "" 4986 5013 ··· 4988 5015 msgid "Looks like you unpinned all your feeds. But don't worry, you can add some below 😄" 4989 5016 msgstr "" 4990 5017 4991 - #: src/screens/Feeds/NoFollowingFeed.tsx:37 5018 + #: src/screens/Feeds/NoFollowingFeed.tsx:35 4992 5019 msgid "Looks like you're missing a following feed. <0>Click here to add one.</0>" 4993 5020 msgstr "" 4994 5021 ··· 4996 5023 msgid "Make adjustments to email settings for your account" 4997 5024 msgstr "" 4998 5025 4999 - #: src/components/StarterPack/ProfileStarterPacks.tsx:282 5026 + #: src/components/StarterPack/ProfileStarterPacks.tsx:278 5000 5027 msgid "Make one for me" 5001 5028 msgstr "" 5002 5029 ··· 5009 5036 msgid "Manage saved feeds" 5010 5037 msgstr "" 5011 5038 5012 - #: src/screens/Moderation/index.tsx:285 5039 + #: src/screens/Moderation/index.tsx:284 5013 5040 msgid "Manage verification settings" 5014 5041 msgstr "" 5015 5042 ··· 5017 5044 msgid "Manage your muted words and tags" 5018 5045 msgstr "" 5019 5046 5020 - #: src/screens/Messages/Inbox.tsx:305 5021 - #: src/screens/Messages/Inbox.tsx:324 5022 - #: src/screens/Messages/Inbox.tsx:331 5047 + #: src/screens/Messages/Inbox.tsx:311 5048 + #: src/screens/Messages/Inbox.tsx:330 5049 + #: src/screens/Messages/Inbox.tsx:337 5023 5050 msgid "Mark all as read" 5024 5051 msgstr "" 5025 5052 ··· 5028 5055 msgid "Mark as read" 5029 5056 msgstr "" 5030 5057 5031 - #: src/screens/Messages/Inbox.tsx:292 5032 - #: src/screens/Messages/Inbox.tsx:315 5058 + #: src/screens/Messages/Inbox.tsx:298 5059 + #: src/screens/Messages/Inbox.tsx:321 5033 5060 msgid "Marked all as read" 5034 5061 msgstr "" 5035 5062 ··· 5046 5073 msgid "Media that may be disturbing or inappropriate for some audiences." 5047 5074 msgstr "" 5048 5075 5049 - #: src/Navigation.tsx:441 5076 + #: src/Navigation.tsx:428 5050 5077 msgid "Mention notifications" 5051 5078 msgstr "" 5052 5079 ··· 5059 5086 msgstr "" 5060 5087 5061 5088 #: src/lib/hooks/useNotificationHandler.ts:147 5062 - #: src/screens/Settings/NotificationSettings/index.tsx:159 5089 + #: src/screens/Settings/NotificationSettings/index.tsx:96 5063 5090 #: src/screens/Settings/NotificationSettings/MentionNotificationSettings.tsx:41 5064 5091 #: src/view/screens/Notifications.tsx:101 5065 5092 msgid "Mentions" ··· 5103 5130 msgid "Message options" 5104 5131 msgstr "" 5105 5132 5106 - #: src/Navigation.tsx:774 5133 + #: src/Navigation.tsx:761 5107 5134 msgid "Messages" 5108 5135 msgstr "" 5109 5136 5110 - #: src/Navigation.tsx:505 5137 + #: src/Navigation.tsx:492 5111 5138 msgid "Miscellaneous notifications" 5112 5139 msgstr "" 5113 5140 ··· 5121 5148 msgid "Misleading Post" 5122 5149 msgstr "" 5123 5150 5124 - #: src/Navigation.tsx:178 5125 - #: src/screens/Moderation/index.tsx:94 5151 + #: src/Navigation.tsx:165 5152 + #: src/screens/Moderation/index.tsx:93 5126 5153 #: src/screens/Settings/Settings.tsx:186 5127 5154 #: src/screens/Settings/Settings.tsx:189 5128 5155 msgid "Moderation" ··· 5156 5183 msgid "Moderation list updated" 5157 5184 msgstr "" 5158 5185 5159 - #: src/screens/Moderation/index.tsx:245 5186 + #: src/screens/Moderation/index.tsx:244 5160 5187 msgid "Moderation lists" 5161 5188 msgstr "" 5162 5189 5163 - #: src/Navigation.tsx:183 5190 + #: src/Navigation.tsx:170 5164 5191 #: src/view/screens/ModerationModlists.tsx:65 5165 5192 msgid "Moderation Lists" 5166 5193 msgstr "" 5167 5194 5168 - #: src/components/moderation/LabelPreference.tsx:247 5195 + #: src/components/moderation/LabelPreference.tsx:249 5169 5196 msgid "moderation settings" 5170 5197 msgstr "" 5171 5198 5172 - #: src/Navigation.tsx:312 5199 + #: src/Navigation.tsx:299 5173 5200 msgid "Moderation states" 5174 5201 msgstr "" 5175 5202 5176 - #: src/screens/Moderation/index.tsx:199 5203 + #: src/screens/Moderation/index.tsx:198 5177 5204 msgid "Moderation tools" 5178 5205 msgstr "" 5179 5206 ··· 5192 5219 msgid "More languages..." 5193 5220 msgstr "" 5194 5221 5222 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:156 5195 5223 #: src/view/com/profile/ProfileMenu.tsx:236 5196 5224 #: src/view/com/profile/ProfileMenu.tsx:242 5197 5225 #: src/view/screens/ProfileList.tsx:768 5198 5226 msgid "More options" 5199 5227 msgstr "" 5200 5228 5229 + #: src/screens/SavedFeeds.tsx:329 5230 + msgid "Move feed down" 5231 + msgstr "" 5232 + 5233 + #: src/screens/SavedFeeds.tsx:320 5234 + msgid "Move feed up" 5235 + msgstr "" 5236 + 5201 5237 #: src/screens/Onboarding/state.ts:113 5202 5238 msgid "Movies" 5203 5239 msgstr "" ··· 5207 5243 msgstr "" 5208 5244 5209 5245 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:153 5210 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:96 5246 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:95 5211 5247 msgctxt "video" 5212 5248 msgid "Mute" 5213 5249 msgstr "" ··· 5224 5260 msgid "Mute account" 5225 5261 msgstr "" 5226 5262 5263 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:89 5264 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:92 5227 5265 #: src/view/screens/ProfileList.tsx:675 5228 5266 msgid "Mute accounts" 5229 5267 msgstr "" ··· 5237 5275 msgid "Mute in:" 5238 5276 msgstr "" 5239 5277 5278 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:115 5240 5279 #: src/view/screens/ProfileList.tsx:797 5241 5280 msgid "Mute list" 5242 5281 msgstr "" 5243 5282 5283 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:110 5244 5284 #: src/view/screens/ProfileList.tsx:792 5245 5285 msgid "Mute these accounts?" 5246 5286 msgstr "" ··· 5279 5319 msgid "Mute words & tags" 5280 5320 msgstr "" 5281 5321 5282 - #: src/screens/Moderation/index.tsx:260 5322 + #: src/screens/Moderation/index.tsx:259 5283 5323 msgid "Muted accounts" 5284 5324 msgstr "" 5285 5325 5286 - #: src/Navigation.tsx:188 5326 + #: src/Navigation.tsx:175 5287 5327 #: src/view/screens/ModerationMutedAccounts.tsx:118 5288 5328 msgid "Muted Accounts" 5289 5329 msgstr "" ··· 5296 5336 msgid "Muted by \"{0}\"" 5297 5337 msgstr "" 5298 5338 5299 - #: src/screens/Moderation/index.tsx:230 5339 + #: src/screens/Moderation/index.tsx:229 5300 5340 msgid "Muted words & tags" 5301 5341 msgstr "" 5302 5342 5343 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:112 5303 5344 #: src/view/screens/ProfileList.tsx:794 5304 5345 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." 5305 5346 msgstr "" ··· 5347 5388 msgstr "" 5348 5389 5349 5390 #: src/screens/Login/ForgotPasswordForm.tsx:166 5350 - #: src/screens/Login/LoginForm.tsx:369 5391 + #: src/screens/Login/LoginForm.tsx:367 5351 5392 msgid "Navigates to the next screen" 5352 5393 msgstr "" 5353 5394 ··· 5360 5401 msgid "Need to report a copyright violation, legal request, or regulatory compliance issue?" 5361 5402 msgstr "" 5362 5403 5363 - #: src/components/ReportDialog/SelectReportOptionView.tsx:128 5404 + #: src/components/ReportDialog/SelectReportOptionView.tsx:131 5364 5405 msgid "Need to report a copyright violation?" 5365 5406 msgstr "" 5366 5407 5367 - #: src/screens/Onboarding/StepFinished.tsx:559 5408 + #: src/screens/Onboarding/StepFinished.tsx:555 5368 5409 msgid "Never lose access to your followers or data." 5369 5410 msgstr "" 5370 5411 ··· 5406 5447 msgid "New Feature" 5407 5448 msgstr "" 5408 5449 5409 - #: src/Navigation.tsx:473 5450 + #: src/Navigation.tsx:460 5410 5451 msgid "New follower notifications" 5411 5452 msgstr "" 5412 5453 5413 5454 #: src/lib/hooks/useNotificationHandler.ts:161 5414 - #: src/screens/Settings/NotificationSettings/index.tsx:137 5455 + #: src/screens/Settings/NotificationSettings/index.tsx:74 5415 5456 #: src/screens/Settings/NotificationSettings/NewFollowerNotificationSettings.tsx:41 5416 5457 msgid "New followers" 5417 5458 msgstr "" ··· 5442 5483 msgstr "" 5443 5484 5444 5485 #: src/screens/Profile/ProfileFeed/index.tsx:241 5486 + #: src/screens/ProfileList/index.tsx:246 5487 + #: src/screens/ProfileList/index.tsx:284 5445 5488 #: src/view/screens/Feeds.tsx:552 5446 5489 #: src/view/screens/Notifications.tsx:167 5447 5490 #: src/view/screens/Profile.tsx:510 ··· 5450 5493 msgid "New post" 5451 5494 msgstr "" 5452 5495 5453 - #: src/view/com/feeds/FeedPage.tsx:173 5496 + #: src/view/com/feeds/FeedPage.tsx:180 5454 5497 msgctxt "action" 5455 5498 msgid "New post" 5456 5499 msgstr "" ··· 5472 5515 msgid "New starter pack" 5473 5516 msgstr "" 5474 5517 5475 - #: src/components/NewskieDialog.tsx:83 5518 + #: src/components/NewskieDialog.tsx:102 5476 5519 msgid "New user info dialog" 5477 5520 msgstr "" 5478 5521 ··· 5495 5538 5496 5539 #: src/screens/Login/ForgotPasswordForm.tsx:137 5497 5540 #: src/screens/Login/ForgotPasswordForm.tsx:143 5498 - #: src/screens/Login/LoginForm.tsx:368 5499 - #: src/screens/Login/LoginForm.tsx:375 5541 + #: src/screens/Login/LoginForm.tsx:366 5542 + #: src/screens/Login/LoginForm.tsx:374 5500 5543 #: src/screens/Login/SetNewPasswordForm.tsx:182 5501 5544 #: src/screens/Login/SetNewPasswordForm.tsx:188 5502 - #: src/screens/Onboarding/StepFinished.tsx:474 5503 - #: src/screens/Onboarding/StepFinished.tsx:483 5545 + #: src/screens/Onboarding/StepFinished.tsx:470 5546 + #: src/screens/Onboarding/StepFinished.tsx:479 5504 5547 #: src/screens/Settings/components/AddAppPasswordDialog.tsx:157 5505 5548 #: src/screens/Settings/components/AddAppPasswordDialog.tsx:165 5506 5549 #: src/screens/Signup/BackNextButtons.tsx:67 ··· 5520 5563 msgid "Next image" 5521 5564 msgstr "" 5522 5565 5523 - #: src/screens/Onboarding/StepFinished.tsx:356 5566 + #: src/screens/Onboarding/StepFinished.tsx:352 5524 5567 msgid "No ads, no invasive tracking, no engagement traps. Bluesky respects your time and attention." 5525 5568 msgstr "" 5526 5569 ··· 5563 5606 msgid "No messages yet" 5564 5607 msgstr "" 5565 5608 5566 - #: src/screens/Onboarding/StepFinished.tsx:338 5609 + #: src/screens/Onboarding/StepFinished.tsx:334 5567 5610 msgid "No more doomscrolling junk-filled algorithms. Find feeds that work for you, not against you." 5568 5611 msgstr "" 5569 5612 ··· 5571 5614 msgid "No notifications yet!" 5572 5615 msgstr "" 5573 5616 5574 - #: src/screens/Messages/Settings.tsx:101 5575 - #: src/screens/Messages/Settings.tsx:104 5617 + #: src/screens/Messages/Settings.tsx:88 5618 + #: src/screens/Messages/Settings.tsx:91 5576 5619 #: src/screens/Settings/ActivityPrivacySettings.tsx:129 5577 5620 #: src/screens/Settings/ActivityPrivacySettings.tsx:134 5578 5621 #: src/screens/Settings/PrivacyAndSecuritySettings.tsx:160 ··· 5587 5630 msgid "No posts here" 5588 5631 msgstr "" 5589 5632 5590 - #: src/screens/Profile/Sections/Feed.tsx:66 5633 + #: src/screens/Profile/Sections/Feed.tsx:62 5591 5634 msgid "No posts yet." 5592 5635 msgstr "" 5593 5636 ··· 5613 5656 msgid "No results for \"{0}\"." 5614 5657 msgstr "" 5615 5658 5616 - #: src/components/Lists.tsx:190 5659 + #: src/components/Lists.tsx:189 5617 5660 msgid "No results found" 5618 5661 msgstr "" 5619 5662 ··· 5673 5716 msgid "Not followed by anyone you're following" 5674 5717 msgstr "" 5675 5718 5676 - #: src/Navigation.tsx:168 5719 + #: src/Navigation.tsx:155 5677 5720 #: src/view/screens/Profile.tsx:125 5678 5721 msgid "Not Found" 5679 5722 msgstr "" ··· 5686 5729 msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." 5687 5730 msgstr "" 5688 5731 5689 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:150 5732 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:149 5690 5733 msgid "Note: This post is only visible to logged-in users." 5691 5734 msgstr "" 5692 5735 ··· 5698 5741 msgid "Nothing saved yet" 5699 5742 msgstr "" 5700 5743 5701 - #: src/Navigation.tsx:427 5702 - #: src/Navigation.tsx:574 5744 + #: src/Navigation.tsx:414 5745 + #: src/Navigation.tsx:561 5703 5746 #: src/view/screens/Notifications.tsx:136 5704 5747 msgid "Notification settings" 5705 5748 msgstr "" 5706 5749 5707 - #: src/screens/Messages/Settings.tsx:123 5708 - msgid "Notification sounds" 5709 - msgstr "" 5710 - 5711 - #: src/screens/Messages/Settings.tsx:120 5712 - msgid "Notification Sounds" 5713 - msgstr "" 5714 - 5715 - #: src/Navigation.tsx:569 5716 - #: src/Navigation.tsx:769 5750 + #: src/Navigation.tsx:556 5751 + #: src/Navigation.tsx:756 5717 5752 #: src/screens/Notifications/ActivityList.tsx:29 5718 5753 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:90 5719 - #: src/screens/Settings/NotificationSettings/index.tsx:92 5754 + #: src/screens/Settings/NotificationSettings/index.tsx:42 5720 5755 #: src/screens/Settings/NotificationSettings/LikeNotificationSettings.tsx:30 5721 5756 #: src/screens/Settings/NotificationSettings/LikesOnRepostsNotificationSettings.tsx:30 5722 5757 #: src/screens/Settings/NotificationSettings/MentionNotificationSettings.tsx:30 ··· 5757 5792 msgid "Nudity or adult content not labeled as such" 5758 5793 msgstr "" 5759 5794 5760 - #: src/lib/moderation/useLabelBehaviorDescription.ts:11 5761 - #: src/screens/Settings/NotificationSettings/index.tsx:291 5795 + #: src/lib/moderation/useLabelBehaviorDescription.ts:14 5796 + #: src/screens/Settings/NotificationSettings/index.tsx:228 5762 5797 msgid "Off" 5763 5798 msgstr "" 5764 5799 ··· 5781 5816 msgstr "" 5782 5817 5783 5818 #: src/screens/Login/PasswordUpdatedForm.tsx:37 5784 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:695 5819 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:689 5785 5820 msgid "Okay" 5786 5821 msgstr "" 5787 5822 ··· 5825 5860 msgid "One or more videos is missing alt text." 5826 5861 msgstr "" 5827 5862 5828 - #: src/screens/Onboarding/StepProfile/index.tsx:118 5863 + #: src/screens/Onboarding/StepProfile/index.tsx:111 5829 5864 msgid "Only .jpg and .png files are supported" 5830 5865 msgstr "" 5831 5866 ··· 5843 5878 msgid "Only image files are supported" 5844 5879 msgstr "" 5845 5880 5846 - #: src/view/com/composer/videos/SubtitleFilePicker.tsx:40 5881 + #: src/view/com/composer/videos/SubtitleFilePicker.tsx:41 5847 5882 msgid "Only WebVTT (.vtt) files are supported" 5848 5883 msgstr "" 5849 5884 5850 - #: src/components/Lists.tsx:95 5885 + #: src/components/Lists.tsx:94 5851 5886 msgid "Oops, something went wrong!" 5852 5887 msgstr "" 5853 5888 5854 - #: src/components/Lists.tsx:174 5855 - #: src/components/StarterPack/ProfileStarterPacks.tsx:332 5856 - #: src/components/StarterPack/ProfileStarterPacks.tsx:341 5889 + #: src/components/Lists.tsx:173 5890 + #: src/components/StarterPack/ProfileStarterPacks.tsx:328 5891 + #: src/components/StarterPack/ProfileStarterPacks.tsx:337 5857 5892 #: src/screens/Settings/AppPasswords.tsx:59 5858 5893 #: src/screens/Settings/components/ChangeHandleDialog.tsx:106 5859 5894 #: src/view/screens/Profile.tsx:125 5860 5895 msgid "Oops!" 5861 5896 msgstr "" 5862 5897 5863 - #: src/screens/Onboarding/StepFinished.tsx:555 5898 + #: src/screens/Onboarding/StepFinished.tsx:551 5864 5899 msgid "Open" 5865 5900 msgstr "" 5866 5901 ··· 5868 5903 msgid "Open a Github Issue" 5869 5904 msgstr "" 5870 5905 5871 - #: src/screens/Onboarding/StepProfile/index.tsx:289 5906 + #: src/screens/Onboarding/StepProfile/index.tsx:282 5872 5907 msgid "Open avatar creator" 5873 5908 msgstr "" 5874 5909 ··· 5911 5946 msgid "Open moderation debug page" 5912 5947 msgstr "" 5913 5948 5914 - #: src/screens/Moderation/index.tsx:226 5949 + #: src/screens/Moderation/index.tsx:225 5915 5950 msgid "Open muted words and tags settings" 5916 5951 msgstr "" 5917 5952 ··· 5919 5954 msgid "Open pack" 5920 5955 msgstr "" 5921 5956 5922 - #: src/components/PostControls/PostMenu/index.tsx:65 5957 + #: src/components/PostControls/PostMenu/index.tsx:64 5923 5958 msgid "Open post options menu" 5924 5959 msgstr "" 5925 5960 ··· 5928 5963 msgid "Open profile" 5929 5964 msgstr "" 5930 5965 5931 - #: src/components/PostControls/ShareMenu/index.tsx:90 5966 + #: src/components/PostControls/ShareMenu/index.tsx:89 5932 5967 msgid "Open share menu" 5933 5968 msgstr "" 5934 5969 ··· 6016 6051 msgid "Opens list of invite codes" 6017 6052 msgstr "" 6018 6053 6019 - #: src/view/com/util/UserAvatar.tsx:590 6054 + #: src/view/com/util/UserAvatar.tsx:595 6020 6055 msgid "Opens live status dialog" 6021 6056 msgstr "" 6022 6057 6023 - #: src/screens/Login/LoginForm.tsx:274 6058 + #: src/screens/Login/LoginForm.tsx:272 6024 6059 msgid "Opens password reset form" 6025 6060 msgstr "" 6026 6061 ··· 6029 6064 msgstr "" 6030 6065 6031 6066 #: src/view/com/notifications/NotificationFeedItem.tsx:911 6032 - #: src/view/com/util/UserAvatar.tsx:608 6067 + #: src/view/com/util/UserAvatar.tsx:613 6033 6068 msgid "Opens this profile" 6034 6069 msgstr "" 6035 6070 ··· 6092 6127 msgid "Our moderators have reviewed reports and decided to disable your access to chats on Bluesky." 6093 6128 msgstr "" 6094 6129 6095 - #: src/components/Lists.tsx:191 6130 + #: src/components/Lists.tsx:190 6096 6131 #: src/view/screens/NotFound.tsx:47 6097 6132 msgid "Page not found" 6098 6133 msgstr "" ··· 6101 6136 msgid "Page Not Found" 6102 6137 msgstr "" 6103 6138 6104 - #: src/screens/Login/LoginForm.tsx:253 6139 + #: src/screens/Login/LoginForm.tsx:251 6105 6140 #: src/screens/Settings/AccountSettings.tsx:130 6106 6141 #: src/screens/Settings/AccountSettings.tsx:134 6107 6142 #: src/screens/Signup/StepInfo/index.tsx:303 ··· 6136 6171 msgid "Pause video" 6137 6172 msgstr "" 6138 6173 6174 + #: src/screens/ProfileList/index.tsx:166 6139 6175 #: src/screens/Search/SearchResults.tsx:67 6140 6176 #: src/screens/StarterPack/StarterPackScreen.tsx:189 6141 6177 #: src/view/screens/ProfileList.tsx:170 6142 6178 msgid "People" 6143 6179 msgstr "" 6144 6180 6145 - #: src/Navigation.tsx:239 6181 + #: src/Navigation.tsx:226 6146 6182 msgid "People followed by @{0}" 6147 6183 msgstr "" 6148 6184 6149 - #: src/Navigation.tsx:232 6185 + #: src/Navigation.tsx:219 6150 6186 msgid "People following @{0}" 6151 6187 msgstr "" 6152 6188 ··· 6178 6214 6179 6215 #: src/screens/Profile/components/ProfileFeedHeader.tsx:523 6180 6216 #: src/screens/Profile/components/ProfileFeedHeader.tsx:530 6217 + #: src/screens/SavedFeeds.tsx:351 6181 6218 msgid "Pin feed" 6182 6219 msgstr "" 6183 6220 ··· 6185 6222 msgid "Pin Feed" 6186 6223 msgstr "" 6187 6224 6225 + #: src/screens/ProfileList/components/Header.tsx:156 6226 + #: src/screens/ProfileList/components/Header.tsx:163 6188 6227 #: src/view/screens/ProfileList.tsx:732 6189 6228 msgid "Pin to home" 6190 6229 msgstr "" ··· 6207 6246 msgid "Pinned {0} to Home" 6208 6247 msgstr "" 6209 6248 6210 - #: src/view/screens/SavedFeeds.tsx:131 6249 + #: src/screens/SavedFeeds.tsx:142 6211 6250 msgid "Pinned Feeds" 6212 6251 msgstr "" 6213 6252 6253 + #: src/screens/ProfileList/components/Header.tsx:74 6214 6254 #: src/view/screens/ProfileList.tsx:361 6215 6255 msgid "Pinned to your feeds" 6216 6256 msgstr "" ··· 6305 6345 msgid "Please enter a valid word, tag, or phrase to mute" 6306 6346 msgstr "" 6307 6347 6308 - #: src/screens/Login/LoginForm.tsx:108 6348 + #: src/screens/Login/LoginForm.tsx:107 6309 6349 msgid "Please enter hosting provider URL" 6310 6350 msgstr "" 6311 6351 ··· 6334 6374 msgid "Please enter your new email address." 6335 6375 msgstr "" 6336 6376 6337 - #: src/screens/Login/LoginForm.tsx:103 6377 + #: src/screens/Login/LoginForm.tsx:102 6338 6378 msgid "Please enter your password" 6339 6379 msgstr "" 6340 6380 ··· 6342 6382 msgid "Please enter your password as well:" 6343 6383 msgstr "" 6344 6384 6345 - #: src/screens/Login/LoginForm.tsx:98 6385 + #: src/screens/Login/LoginForm.tsx:97 6346 6386 msgid "Please enter your username" 6347 6387 msgstr "" 6348 6388 ··· 6409 6449 msgid "Post blocked" 6410 6450 msgstr "" 6411 6451 6412 - #: src/Navigation.tsx:265 6413 - #: src/Navigation.tsx:272 6414 - #: src/Navigation.tsx:279 6415 - #: src/Navigation.tsx:286 6452 + #: src/Navigation.tsx:252 6453 + #: src/Navigation.tsx:259 6454 + #: src/Navigation.tsx:266 6455 + #: src/Navigation.tsx:273 6416 6456 msgid "Post by @{0}" 6417 6457 msgstr "" 6418 6458 ··· 6446 6486 msgid "Post interaction settings" 6447 6487 msgstr "" 6448 6488 6449 - #: src/Navigation.tsx:199 6489 + #: src/Navigation.tsx:186 6450 6490 #: src/screens/ModerationInteractionSettings/index.tsx:34 6451 6491 msgid "Post Interaction Settings" 6452 6492 msgstr "" ··· 6477 6517 6478 6518 #: src/components/activity-notifications/SubscribeProfileDialog.tsx:250 6479 6519 #: src/components/activity-notifications/SubscribeProfileDialog.tsx:262 6520 + #: src/screens/ProfileList/index.tsx:166 6480 6521 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:213 6481 6522 #: src/screens/StarterPack/StarterPackScreen.tsx:191 6482 6523 #: src/view/screens/Profile.tsx:225 ··· 6509 6550 msgstr "" 6510 6551 6511 6552 #: src/components/Error.tsx:60 6512 - #: src/components/Lists.tsx:100 6553 + #: src/components/Lists.tsx:99 6513 6554 #: src/screens/Messages/components/MessageListError.tsx:24 6514 6555 #: src/screens/Signup/BackNextButtons.tsx:47 6515 6556 msgid "Press to retry" ··· 6542 6583 msgid "Privacy and security" 6543 6584 msgstr "" 6544 6585 6545 - #: src/Navigation.tsx:412 6546 - #: src/Navigation.tsx:420 6586 + #: src/Navigation.tsx:399 6587 + #: src/Navigation.tsx:407 6547 6588 #: src/screens/Settings/ActivityPrivacySettings.tsx:40 6548 6589 #: src/screens/Settings/PrivacyAndSecuritySettings.tsx:45 6549 6590 msgid "Privacy and Security" ··· 6555 6596 6556 6597 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:35 6557 6598 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:102 6558 - #: src/Navigation.tsx:332 6599 + #: src/Navigation.tsx:319 6559 6600 #: src/screens/Settings/AboutSettings.tsx:90 6560 6601 #: src/screens/Settings/AboutSettings.tsx:93 6561 6602 #: src/view/screens/PrivacyPolicy.tsx:34 ··· 6590 6631 msgid "Profile updated" 6591 6632 msgstr "" 6592 6633 6593 - #: src/screens/Onboarding/StepFinished.tsx:541 6634 + #: src/screens/Onboarding/StepFinished.tsx:537 6594 6635 msgid "Public" 6595 6636 msgstr "" 6596 6637 ··· 6622 6663 msgid "Publish reply" 6623 6664 msgstr "" 6624 6665 6625 - #: src/screens/Settings/NotificationSettings/index.tsx:286 6666 + #: src/screens/Settings/NotificationSettings/index.tsx:223 6626 6667 msgid "Push" 6627 6668 msgstr "" 6628 6669 ··· 6630 6671 msgid "Push notifications" 6631 6672 msgstr "" 6632 6673 6633 - #: src/screens/Settings/NotificationSettings/index.tsx:269 6674 + #: src/screens/Settings/NotificationSettings/index.tsx:206 6634 6675 msgid "Push, Everyone" 6635 6676 msgstr "" 6636 6677 6637 - #: src/screens/Settings/NotificationSettings/index.tsx:277 6678 + #: src/screens/Settings/NotificationSettings/index.tsx:214 6638 6679 msgid "Push, People you follow" 6639 6680 msgstr "" 6640 6681 6641 - #: src/components/StarterPack/QrCodeDialog.tsx:134 6682 + #: src/components/StarterPack/QrCodeDialog.tsx:137 6642 6683 msgid "QR code copied to your clipboard!" 6643 6684 msgstr "" 6644 6685 6645 - #: src/components/StarterPack/QrCodeDialog.tsx:112 6686 + #: src/components/StarterPack/QrCodeDialog.tsx:115 6646 6687 msgid "QR code has been downloaded!" 6647 6688 msgstr "" 6648 6689 6649 - #: src/components/StarterPack/QrCodeDialog.tsx:113 6690 + #: src/components/StarterPack/QrCodeDialog.tsx:116 6650 6691 msgid "QR code saved to your camera roll!" 6651 6692 msgstr "" 6652 6693 6653 - #: src/Navigation.tsx:449 6694 + #: src/Navigation.tsx:436 6654 6695 msgid "Quote notifications" 6655 6696 msgstr "" 6656 6697 ··· 6681 6722 msgstr "" 6682 6723 6683 6724 #: src/lib/hooks/useNotificationHandler.ts:154 6684 - #: src/screens/Post/PostQuotes.tsx:38 6685 - #: src/screens/Settings/NotificationSettings/index.tsx:170 6725 + #: src/screens/Post/PostQuotes.tsx:41 6726 + #: src/screens/Settings/NotificationSettings/index.tsx:107 6686 6727 #: src/screens/Settings/NotificationSettings/QuoteNotificationSettings.tsx:41 6687 6728 msgid "Quotes" 6688 6729 msgstr "" ··· 6717 6758 msgid "Read blog post" 6718 6759 msgstr "" 6719 6760 6720 - #: src/screens/VideoFeed/index.tsx:970 6761 + #: src/screens/VideoFeed/index.tsx:971 6721 6762 msgid "Read less" 6722 6763 msgstr "" 6723 6764 6724 - #: src/screens/VideoFeed/index.tsx:970 6765 + #: src/screens/VideoFeed/index.tsx:971 6725 6766 msgid "Read more" 6726 6767 msgstr "" 6727 6768 ··· 6807 6848 msgstr "" 6808 6849 6809 6850 #: src/screens/Messages/ChatList.tsx:258 6810 - #: src/screens/Messages/Inbox.tsx:191 6851 + #: src/screens/Messages/Inbox.tsx:197 6811 6852 msgid "Reload conversations" 6812 6853 msgstr "" 6813 6854 ··· 6852 6893 msgid "Remove Banner" 6853 6894 msgstr "" 6854 6895 6855 - #: src/screens/Messages/components/MessageInputEmbed.tsx:209 6896 + #: src/screens/Messages/components/MessageInputEmbed.tsx:212 6856 6897 msgid "Remove embed" 6857 6898 msgstr "" 6858 6899 ··· 6868 6909 6869 6910 #: src/screens/Profile/components/ProfileFeedHeader.tsx:319 6870 6911 #: src/screens/Profile/components/ProfileFeedHeader.tsx:325 6912 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:188 6913 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:191 6914 + #: src/screens/SavedFeeds.tsx:340 6871 6915 #: src/view/screens/ProfileList.tsx:545 6872 - #: src/view/screens/SavedFeeds.tsx:350 6873 6916 msgid "Remove from my feeds" 6874 6917 msgstr "" 6875 6918 ··· 6969 7012 msgstr "" 6970 7013 6971 7014 #: src/screens/Profile/components/ProfileFeedHeader.tsx:122 7015 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:74 6972 7016 #: src/view/com/posts/FeedShutdownMsg.tsx:44 6973 7017 #: src/view/screens/ProfileList.tsx:392 6974 7018 msgid "Removed from your feeds" ··· 7007 7051 #: src/components/activity-notifications/SubscribeProfileDialog.tsx:279 7008 7052 #: src/lib/hooks/useNotificationHandler.ts:140 7009 7053 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:215 7010 - #: src/screens/Settings/NotificationSettings/index.tsx:148 7054 + #: src/screens/Settings/NotificationSettings/index.tsx:85 7011 7055 #: src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx:41 7012 7056 #: src/view/screens/Profile.tsx:226 7013 7057 msgid "Replies" ··· 7041 7085 msgid "Reply Hidden by You" 7042 7086 msgstr "" 7043 7087 7044 - #: src/Navigation.tsx:433 7088 + #: src/Navigation.tsx:420 7045 7089 msgid "Reply notifications" 7046 7090 msgstr "" 7047 7091 ··· 7096 7140 msgid "Report feed" 7097 7141 msgstr "" 7098 7142 7143 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:222 7144 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:225 7099 7145 #: src/view/screens/ProfileList.tsx:587 7100 7146 msgid "Report list" 7101 7147 msgstr "" ··· 7118 7164 msgid "Report submitted" 7119 7165 msgstr "" 7120 7166 7121 - #: src/components/ReportDialog/SelectReportOptionView.tsx:41 7167 + #: src/components/ReportDialog/SelectReportOptionView.tsx:44 7122 7168 msgid "Report this content" 7123 7169 msgstr "" 7124 7170 7125 7171 #: src/components/moderation/ReportDialog/copy.ts:31 7126 - #: src/components/ReportDialog/SelectReportOptionView.tsx:54 7172 + #: src/components/ReportDialog/SelectReportOptionView.tsx:57 7127 7173 msgid "Report this feed" 7128 7174 msgstr "" 7129 7175 7130 7176 #: src/components/moderation/ReportDialog/copy.ts:25 7131 - #: src/components/ReportDialog/SelectReportOptionView.tsx:51 7177 + #: src/components/ReportDialog/SelectReportOptionView.tsx:54 7132 7178 msgid "Report this list" 7133 7179 msgstr "" 7134 7180 7135 7181 #: src/components/dms/ReportDialog.tsx:61 7136 7182 #: src/components/dms/ReportDialog.tsx:185 7137 7183 #: src/components/moderation/ReportDialog/copy.ts:43 7138 - #: src/components/ReportDialog/SelectReportOptionView.tsx:60 7184 + #: src/components/ReportDialog/SelectReportOptionView.tsx:63 7139 7185 msgid "Report this message" 7140 7186 msgstr "" 7141 7187 7142 7188 #: src/components/moderation/ReportDialog/copy.ts:19 7143 - #: src/components/ReportDialog/SelectReportOptionView.tsx:48 7189 + #: src/components/ReportDialog/SelectReportOptionView.tsx:51 7144 7190 msgid "Report this post" 7145 7191 msgstr "" 7146 7192 7147 7193 #: src/components/moderation/ReportDialog/copy.ts:37 7148 - #: src/components/ReportDialog/SelectReportOptionView.tsx:57 7194 + #: src/components/ReportDialog/SelectReportOptionView.tsx:60 7149 7195 msgid "Report this starter pack" 7150 7196 msgstr "" 7151 7197 7152 7198 #: src/components/moderation/ReportDialog/copy.ts:13 7153 - #: src/components/ReportDialog/SelectReportOptionView.tsx:45 7199 + #: src/components/ReportDialog/SelectReportOptionView.tsx:48 7154 7200 msgid "Report this user" 7155 7201 msgstr "" 7156 7202 ··· 7167 7213 msgid "Repost ({0, plural, one {# repost} other {# reposts}})" 7168 7214 msgstr "" 7169 7215 7170 - #: src/Navigation.tsx:465 7216 + #: src/Navigation.tsx:452 7171 7217 msgid "Repost notifications" 7172 7218 msgstr "" 7173 7219 ··· 7178 7224 msgid "Repost or quote post" 7179 7225 msgstr "" 7180 7226 7181 - #: src/screens/Post/PostRepostedBy.tsx:38 7227 + #: src/screens/Post/PostRepostedBy.tsx:41 7182 7228 msgid "Reposted By" 7183 7229 msgstr "" 7184 7230 ··· 7196 7242 msgstr "" 7197 7243 7198 7244 #: src/lib/hooks/useNotificationHandler.ts:133 7199 - #: src/screens/Settings/NotificationSettings/index.tsx:181 7245 + #: src/screens/Settings/NotificationSettings/index.tsx:118 7200 7246 #: src/screens/Settings/NotificationSettings/RepostNotificationSettings.tsx:41 7201 7247 msgid "Reposts" 7202 7248 msgstr "" ··· 7206 7252 msgstr "" 7207 7253 7208 7254 #: src/lib/hooks/useNotificationHandler.ts:175 7209 - #: src/screens/Settings/NotificationSettings/index.tsx:222 7255 + #: src/screens/Settings/NotificationSettings/index.tsx:159 7210 7256 #: src/screens/Settings/NotificationSettings/RepostsOnRepostsNotificationSettings.tsx:41 7211 7257 msgid "Reposts of your reposts" 7212 7258 msgstr "" 7213 7259 7214 - #: src/Navigation.tsx:489 7260 + #: src/Navigation.tsx:476 7215 7261 msgid "Reposts of your reposts notifications" 7216 7262 msgstr "" 7217 7263 ··· 7280 7326 msgid "Restart app after changing this setting." 7281 7327 msgstr "" 7282 7328 7283 - #: src/screens/Login/LoginForm.tsx:349 7329 + #: src/screens/Login/LoginForm.tsx:347 7284 7330 msgid "Retries signing in" 7285 7331 msgstr "" 7286 7332 ··· 7291 7337 7292 7338 #: src/components/dms/MessageItem.tsx:322 7293 7339 #: src/components/Error.tsx:65 7294 - #: src/components/Lists.tsx:111 7340 + #: src/components/Lists.tsx:110 7295 7341 #: src/components/moderation/ReportDialog/index.tsx:229 7296 7342 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:55 7297 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:57 7298 - #: src/components/StarterPack/ProfileStarterPacks.tsx:346 7299 - #: src/screens/Login/LoginForm.tsx:348 7300 - #: src/screens/Login/LoginForm.tsx:355 7343 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:58 7344 + #: src/components/StarterPack/ProfileStarterPacks.tsx:342 7345 + #: src/screens/Login/LoginForm.tsx:346 7346 + #: src/screens/Login/LoginForm.tsx:353 7301 7347 #: src/screens/Messages/ChatList.tsx:264 7302 7348 #: src/screens/Messages/components/MessageListError.tsx:25 7303 - #: src/screens/Messages/Inbox.tsx:197 7349 + #: src/screens/Messages/Inbox.tsx:203 7304 7350 #: src/screens/Onboarding/StepInterests/index.tsx:226 7305 7351 #: src/screens/Onboarding/StepInterests/index.tsx:229 7306 7352 #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:209 ··· 7328 7374 msgstr "" 7329 7375 7330 7376 #: src/screens/Profile/ProfileFeed/index.tsx:93 7377 + #: src/screens/ProfileList/components/ErrorScreen.tsx:35 7331 7378 #: src/screens/Settings/components/ChangeHandleDialog.tsx:569 7332 - #: src/screens/VideoFeed/index.tsx:1146 7379 + #: src/screens/VideoFeed/index.tsx:1147 7333 7380 #: src/view/screens/NotFound.tsx:60 7334 7381 #: src/view/screens/ProfileList.tsx:1057 7335 7382 msgid "Returns to previous page" ··· 7344 7391 #: src/components/dialogs/PostInteractionSettingsDialog.tsx:489 7345 7392 #: src/components/live/EditLiveDialog.tsx:216 7346 7393 #: src/components/live/EditLiveDialog.tsx:223 7347 - #: src/components/StarterPack/QrCodeDialog.tsx:192 7394 + #: src/components/StarterPack/QrCodeDialog.tsx:204 7348 7395 #: src/screens/Profile/Header/EditProfileDialog.tsx:238 7349 7396 #: src/screens/Profile/Header/EditProfileDialog.tsx:252 7397 + #: src/screens/SavedFeeds.tsx:120 7350 7398 #: src/screens/Settings/components/ChangeHandleDialog.tsx:267 7351 7399 #: src/screens/Settings/DeerSettings.tsx:136 7352 7400 #: src/screens/Settings/DeerSettings.tsx:143 ··· 7357 7405 #: src/view/com/composer/photos/ImageAltTextDialog.tsx:152 7358 7406 #: src/view/com/composer/photos/ImageAltTextDialog.tsx:162 7359 7407 #: src/view/com/modals/CreateOrEditList.tsx:315 7360 - #: src/view/screens/SavedFeeds.tsx:117 7361 7408 msgid "Save" 7362 7409 msgstr "" 7363 7410 ··· 7373 7420 7374 7421 #: src/components/activity-notifications/SubscribeProfileDialog.tsx:191 7375 7422 #: src/components/activity-notifications/SubscribeProfileDialog.tsx:200 7376 - #: src/view/screens/SavedFeeds.tsx:113 7377 - #: src/view/screens/SavedFeeds.tsx:117 7423 + #: src/screens/SavedFeeds.tsx:116 7424 + #: src/screens/SavedFeeds.tsx:120 7378 7425 msgid "Save changes" 7379 7426 msgstr "" 7380 7427 7381 - #: src/components/StarterPack/ShareDialog.tsx:131 7382 7428 #: src/components/StarterPack/ShareDialog.tsx:138 7429 + #: src/components/StarterPack/ShareDialog.tsx:144 7383 7430 msgid "Save image" 7384 7431 msgstr "" 7385 7432 ··· 7391 7438 msgid "Save new handle" 7392 7439 msgstr "" 7393 7440 7394 - #: src/components/StarterPack/QrCodeDialog.tsx:186 7441 + #: src/components/StarterPack/QrCodeDialog.tsx:196 7395 7442 msgid "Save QR code" 7396 7443 msgstr "" 7397 7444 ··· 7406 7453 msgid "Saved" 7407 7454 msgstr "" 7408 7455 7409 - #: src/view/screens/SavedFeeds.tsx:172 7456 + #: src/screens/SavedFeeds.tsx:184 7410 7457 msgid "Saved Feeds" 7411 7458 msgstr "" 7412 7459 7413 7460 #: src/components/dialogs/nuxs/BookmarksAnnouncement.tsx:143 7414 - #: src/Navigation.tsx:613 7461 + #: src/Navigation.tsx:600 7415 7462 #: src/screens/Bookmarks/index.tsx:55 7416 7463 msgid "Saved Posts" 7417 7464 msgstr "" 7418 7465 7419 7466 #: src/screens/Profile/components/ProfileFeedHeader.tsx:132 7467 + #: src/screens/ProfileList/components/Header.tsx:85 7420 7468 #: src/view/screens/ProfileList.tsx:372 7421 7469 msgid "Saved to your feeds" 7422 7470 msgstr "" ··· 7425 7473 msgid "Saves image crop settings" 7426 7474 msgstr "" 7427 7475 7428 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:484 7429 - msgid "Saves of this post" 7430 - msgstr "" 7431 - 7432 7476 #: src/components/dms/ChatEmptyPill.tsx:33 7433 - #: src/components/NewskieDialog.tsx:105 7477 + #: src/components/NewskieDialog.tsx:121 7434 7478 #: src/view/com/notifications/NotificationFeedItem.tsx:756 7435 7479 #: src/view/com/notifications/NotificationFeedItem.tsx:781 7436 7480 msgid "Say hello!" ··· 7457 7501 msgid "Scroll right" 7458 7502 msgstr "" 7459 7503 7504 + #: src/screens/ProfileList/AboutSection.tsx:130 7460 7505 #: src/view/screens/ProfileList.tsx:1014 7461 7506 msgid "Scroll to top" 7462 7507 msgstr "" ··· 7470 7515 msgid "Search" 7471 7516 msgstr "" 7472 7517 7473 - #: src/Navigation.tsx:258 7518 + #: src/Navigation.tsx:245 7474 7519 #: src/screens/Profile/ProfileSearch.tsx:37 7475 7520 msgid "Search @{0}'s posts" 7476 7521 msgstr "" ··· 7586 7631 msgid "See more suggested profiles on the Explore page" 7587 7632 msgstr "" 7588 7633 7589 - #: src/view/screens/SavedFeeds.tsx:213 7634 + #: src/screens/SavedFeeds.tsx:220 7590 7635 msgid "See this guide" 7591 7636 msgstr "" 7592 7637 7593 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/Scrubber.tsx:197 7638 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/Scrubber.tsx:196 7594 7639 msgid "Seek slider. Use the arrow keys to seek forwards and backwards, and space to play/pause" 7595 7640 msgstr "" 7596 7641 ··· 7685 7730 msgid "Select primary language" 7686 7731 msgstr "" 7687 7732 7688 - #: src/view/com/composer/videos/SubtitleFilePicker.tsx:59 7689 - #: src/view/com/composer/videos/SubtitleFilePicker.tsx:66 7733 + #: src/view/com/composer/videos/SubtitleFilePicker.tsx:60 7734 + #: src/view/com/composer/videos/SubtitleFilePicker.tsx:67 7690 7735 msgid "Select subtitle file (.vtt)" 7691 7736 msgstr "" 7692 7737 ··· 7796 7841 7797 7842 #: src/components/PostControls/ShareMenu/ShareMenuItems.tsx:99 7798 7843 #: src/components/PostControls/ShareMenu/ShareMenuItems.tsx:105 7799 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:120 7800 - #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:126 7844 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:119 7845 + #: src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx:125 7801 7846 msgid "Send via direct message" 7802 7847 msgstr "" 7803 7848 ··· 7825 7870 msgid "Sets email for password reset" 7826 7871 msgstr "" 7827 7872 7828 - #: src/Navigation.tsx:214 7873 + #: src/Navigation.tsx:201 7829 7874 #: src/screens/Settings/Settings.tsx:99 7830 7875 #: src/view/shell/desktop/LeftNav.tsx:806 7831 7876 #: src/view/shell/Drawer.tsx:609 7832 7877 msgid "Settings" 7833 7878 msgstr "" 7834 7879 7835 - #: src/screens/Settings/NotificationSettings/index.tsx:187 7880 + #: src/screens/Settings/NotificationSettings/index.tsx:124 7836 7881 msgid "Settings for activity from others" 7837 7882 msgstr "" 7838 7883 ··· 7840 7885 msgid "Settings for allowing others to be notified of your posts" 7841 7886 msgstr "" 7842 7887 7843 - #: src/screens/Settings/NotificationSettings/index.tsx:121 7888 + #: src/screens/Settings/NotificationSettings/index.tsx:58 7844 7889 msgid "Settings for like notifications" 7845 7890 msgstr "" 7846 7891 7847 - #: src/screens/Settings/NotificationSettings/index.tsx:154 7892 + #: src/screens/Settings/NotificationSettings/index.tsx:91 7848 7893 msgid "Settings for mention notifications" 7849 7894 msgstr "" 7850 7895 7851 - #: src/screens/Settings/NotificationSettings/index.tsx:132 7896 + #: src/screens/Settings/NotificationSettings/index.tsx:69 7852 7897 msgid "Settings for new follower notifications" 7853 7898 msgstr "" 7854 7899 7855 - #: src/screens/Settings/NotificationSettings/index.tsx:230 7900 + #: src/screens/Settings/NotificationSettings/index.tsx:167 7856 7901 msgid "Settings for notifications for everything else" 7857 7902 msgstr "" 7858 7903 7859 - #: src/screens/Settings/NotificationSettings/index.tsx:201 7904 + #: src/screens/Settings/NotificationSettings/index.tsx:138 7860 7905 msgid "Settings for notifications for likes of your reposts" 7861 7906 msgstr "" 7862 7907 7863 - #: src/screens/Settings/NotificationSettings/index.tsx:216 7908 + #: src/screens/Settings/NotificationSettings/index.tsx:153 7864 7909 msgid "Settings for notifications for reposts of your reposts" 7865 7910 msgstr "" 7866 7911 7867 - #: src/screens/Settings/NotificationSettings/index.tsx:165 7912 + #: src/screens/Settings/NotificationSettings/index.tsx:102 7868 7913 msgid "Settings for quote notifications" 7869 7914 msgstr "" 7870 7915 7871 - #: src/screens/Settings/NotificationSettings/index.tsx:143 7916 + #: src/screens/Settings/NotificationSettings/index.tsx:80 7872 7917 msgid "Settings for reply notifications" 7873 7918 msgstr "" 7874 7919 7875 - #: src/screens/Settings/NotificationSettings/index.tsx:176 7920 + #: src/screens/Settings/NotificationSettings/index.tsx:113 7876 7921 msgid "Settings for repost notifications" 7877 7922 msgstr "" 7878 7923 ··· 7889 7934 msgid "Sexually Suggestive" 7890 7935 msgstr "" 7891 7936 7892 - #: src/components/StarterPack/QrCodeDialog.tsx:182 7937 + #: src/components/StarterPack/QrCodeDialog.tsx:192 7893 7938 #: src/screens/Hashtag.tsx:126 7894 7939 #: src/screens/StarterPack/StarterPackScreen.tsx:433 7895 7940 #: src/screens/Topic.tsx:102 ··· 7922 7967 7923 7968 #: src/components/dialogs/LinkWarning.tsx:96 7924 7969 #: src/components/dialogs/LinkWarning.tsx:104 7925 - #: src/components/StarterPack/ShareDialog.tsx:104 7926 - #: src/components/StarterPack/ShareDialog.tsx:111 7970 + #: src/components/StarterPack/ShareDialog.tsx:113 7971 + #: src/components/StarterPack/ShareDialog.tsx:119 7927 7972 msgid "Share link" 7928 7973 msgstr "" 7929 7974 7930 - #: src/components/StarterPack/ShareDialog.tsx:68 7975 + #: src/components/StarterPack/ShareDialog.tsx:72 7931 7976 msgid "Share link dialog" 7932 7977 msgstr "" 7933 7978 ··· 7936 7981 msgid "Share post at:// URI" 7937 7982 msgstr "" 7938 7983 7939 - #: src/components/StarterPack/ShareDialog.tsx:115 7940 - #: src/components/StarterPack/ShareDialog.tsx:126 7984 + #: src/components/StarterPack/ShareDialog.tsx:123 7985 + #: src/components/StarterPack/ShareDialog.tsx:133 7941 7986 msgid "Share QR code" 7942 7987 msgstr "" 7943 7988 ··· 7949 7994 msgid "Share this starter pack" 7950 7995 msgstr "" 7951 7996 7952 - #: src/components/StarterPack/ShareDialog.tsx:80 7997 + #: src/components/StarterPack/ShareDialog.tsx:84 7953 7998 msgid "Share this starter pack and help people join your community on Bluesky." 7954 7999 msgstr "" 7955 8000 7956 8001 #: src/components/PostControls/ShareMenu/ShareMenuItems.tsx:115 7957 8002 #: src/components/PostControls/ShareMenu/ShareMenuItems.tsx:118 8003 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:172 8004 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:178 7958 8005 #: src/screens/StarterPack/StarterPackScreen.tsx:611 7959 8006 #: src/screens/StarterPack/StarterPackScreen.tsx:619 7960 8007 #: src/view/com/profile/ProfileMenu.tsx:259 ··· 7968 8015 msgid "Share your favorite feed!" 7969 8016 msgstr "" 7970 8017 7971 - #: src/Navigation.tsx:317 8018 + #: src/Navigation.tsx:304 7972 8019 msgid "Shared Preferences Tester" 7973 8020 msgstr "" 7974 8021 7975 8022 #: src/components/moderation/ContentHider.tsx:203 7976 - #: src/components/moderation/LabelPreference.tsx:137 8023 + #: src/components/moderation/LabelPreference.tsx:139 7977 8024 #: src/components/moderation/PostHider.tsx:134 7978 8025 msgid "Show" 7979 8026 msgstr "" ··· 7990 8037 msgid "Show anyway" 7991 8038 msgstr "" 7992 8039 7993 - #: src/lib/moderation/useLabelBehaviorDescription.ts:27 7994 - #: src/lib/moderation/useLabelBehaviorDescription.ts:63 8040 + #: src/lib/moderation/useLabelBehaviorDescription.ts:30 8041 + #: src/lib/moderation/useLabelBehaviorDescription.ts:66 7995 8042 msgid "Show badge" 7996 8043 msgstr "" 7997 8044 7998 - #: src/lib/moderation/useLabelBehaviorDescription.ts:61 8045 + #: src/lib/moderation/useLabelBehaviorDescription.ts:64 7999 8046 msgid "Show badge and filter from feeds" 8000 8047 msgstr "" 8001 8048 ··· 8062 8109 msgid "Show samples of your saved feeds in your Following feed" 8063 8110 msgstr "" 8064 8111 8065 - #: src/lib/moderation/useLabelBehaviorDescription.ts:58 8112 + #: src/lib/moderation/useLabelBehaviorDescription.ts:61 8066 8113 msgid "Show warning" 8067 8114 msgstr "" 8068 8115 8069 - #: src/lib/moderation/useLabelBehaviorDescription.ts:56 8116 + #: src/lib/moderation/useLabelBehaviorDescription.ts:59 8070 8117 msgid "Show warning and filter from feeds" 8071 8118 msgstr "" 8072 8119 8073 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:636 8120 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:630 8074 8121 msgid "Shows information about when this post was created" 8075 8122 msgstr "" 8076 8123 ··· 8089 8136 #: src/components/WelcomeModal.tsx:206 8090 8137 #: src/screens/Login/index.tsx:163 8091 8138 #: src/screens/Login/index.tsx:186 8092 - #: src/screens/Login/LoginForm.tsx:190 8139 + #: src/screens/Login/LoginForm.tsx:188 8093 8140 #: src/screens/Search/SearchResults.tsx:258 8094 8141 #: src/view/com/auth/SplashScreen.tsx:61 8095 8142 #: src/view/com/auth/SplashScreen.tsx:69 ··· 8174 8221 msgid "Similar accounts" 8175 8222 msgstr "" 8176 8223 8177 - #: src/screens/Onboarding/StepFinished.tsx:380 8178 - #: src/screens/Onboarding/StepFinished.tsx:462 8224 + #: src/screens/Onboarding/StepFinished.tsx:376 8225 + #: src/screens/Onboarding/StepFinished.tsx:458 8179 8226 #: src/screens/Onboarding/StepInterests/index.tsx:240 8180 8227 #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:222 8181 8228 #: src/screens/StarterPack/Wizard/index.tsx:218 8182 8229 msgid "Skip" 8183 8230 msgstr "" 8184 8231 8185 - #: src/screens/Onboarding/StepFinished.tsx:373 8186 - #: src/screens/Onboarding/StepFinished.tsx:459 8232 + #: src/screens/Onboarding/StepFinished.tsx:369 8233 + #: src/screens/Onboarding/StepFinished.tsx:455 8187 8234 msgid "Skip introduction and start using your account" 8188 8235 msgstr "" 8189 8236 ··· 8248 8295 msgstr "" 8249 8296 8250 8297 #: src/components/ReportDialog/index.tsx:54 8251 - #: src/screens/Moderation/index.tsx:106 8252 - #: src/screens/Profile/Sections/Labels.tsx:184 8298 + #: src/screens/Moderation/index.tsx:105 8299 + #: src/screens/Profile/Sections/Labels.tsx:185 8253 8300 msgid "Something went wrong, please try again." 8254 8301 msgstr "" 8255 8302 8256 - #: src/components/Lists.tsx:175 8303 + #: src/components/Lists.tsx:174 8257 8304 msgid "Something went wrong!" 8258 8305 msgstr "" 8259 8306 ··· 8317 8364 msgid "Start a new chat" 8318 8365 msgstr "" 8319 8366 8367 + #: src/screens/ProfileList/AboutSection.tsx:102 8368 + #: src/screens/ProfileList/FeedSection.tsx:74 8320 8369 #: src/view/screens/ProfileList.tsx:864 8321 8370 #: src/view/screens/ProfileList.tsx:985 8322 8371 msgid "Start adding people" 8323 8372 msgstr "" 8324 8373 8374 + #: src/screens/ProfileList/AboutSection.tsx:108 8375 + #: src/screens/ProfileList/FeedSection.tsx:80 8325 8376 #: src/view/screens/ProfileList.tsx:871 8326 8377 #: src/view/screens/ProfileList.tsx:992 8327 8378 msgid "Start adding people!" ··· 8331 8382 msgid "Start chat with {displayName}" 8332 8383 msgstr "" 8333 8384 8334 - #: src/Navigation.tsx:584 8335 - #: src/Navigation.tsx:589 8385 + #: src/Navigation.tsx:571 8386 + #: src/Navigation.tsx:576 8336 8387 #: src/screens/StarterPack/Wizard/index.tsx:209 8337 8388 msgid "Starter Pack" 8338 8389 msgstr "" ··· 8359 8410 msgid "Starter Packs" 8360 8411 msgstr "" 8361 8412 8362 - #: src/components/StarterPack/ProfileStarterPacks.tsx:266 8413 + #: src/components/StarterPack/ProfileStarterPacks.tsx:262 8363 8414 msgid "Starter packs let you easily share your favorite feeds and people with your friends." 8364 8415 msgstr "" 8365 8416 ··· 8376 8427 msgid "Storage cleared, you need to restart the app now." 8377 8428 msgstr "" 8378 8429 8379 - #: src/Navigation.tsx:307 8430 + #: src/Navigation.tsx:294 8380 8431 #: src/screens/Settings/Settings.tsx:452 8381 8432 msgid "Storybook" 8382 8433 msgstr "" ··· 8402 8453 msgid "Submit report" 8403 8454 msgstr "" 8404 8455 8456 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:81 8405 8457 #: src/view/screens/ProfileList.tsx:759 8406 8458 msgid "Subscribe" 8407 8459 msgstr "" 8408 8460 8409 - #: src/screens/Profile/Sections/Labels.tsx:231 8461 + #: src/screens/Profile/Sections/Labels.tsx:232 8410 8462 msgid "Subscribe to @{0} to use these labels:" 8411 8463 msgstr "" 8412 8464 ··· 8422 8474 msgid "Subscribe to this labeler" 8423 8475 msgstr "" 8424 8476 8477 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:69 8425 8478 #: src/view/screens/ProfileList.tsx:755 8426 8479 msgid "Subscribe to this list" 8427 8480 msgstr "" ··· 8449 8502 msgid "Suggestive" 8450 8503 msgstr "" 8451 8504 8452 - #: src/Navigation.tsx:327 8453 - #: src/view/screens/Support.tsx:31 8505 + #: src/Navigation.tsx:314 8454 8506 #: src/view/screens/Support.tsx:34 8507 + #: src/view/screens/Support.tsx:37 8455 8508 msgid "Support" 8456 8509 msgstr "" 8457 8510 ··· 8552 8605 #: src/components/dialogs/BirthDateSettings.tsx:135 8553 8606 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:30 8554 8607 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:97 8555 - #: src/Navigation.tsx:337 8608 + #: src/Navigation.tsx:324 8556 8609 #: src/screens/Settings/AboutSettings.tsx:82 8557 8610 #: src/screens/Settings/AboutSettings.tsx:85 8558 8611 #: src/view/screens/TermsOfService.tsx:34 ··· 8618 8671 msgid "That's all, folks!" 8619 8672 msgstr "" 8620 8673 8621 - #: src/screens/VideoFeed/index.tsx:1118 8674 + #: src/screens/VideoFeed/index.tsx:1119 8622 8675 msgid "That's everything!" 8623 8676 msgstr "" 8624 8677 ··· 8645 8698 msgid "The birthdate you've entered means you are under 18 years old. Certain content and features may be unavailable to you." 8646 8699 msgstr "" 8647 8700 8648 - #: src/screens/Moderation/index.tsx:346 8701 + #: src/screens/Moderation/index.tsx:345 8649 8702 msgid "The Bluesky web application" 8650 8703 msgstr "" 8651 8704 8652 - #: src/view/screens/CommunityGuidelines.tsx:38 8705 + #: src/view/screens/CommunityGuidelines.tsx:41 8653 8706 msgid "The Community Guidelines have been moved to <0/>" 8654 8707 msgstr "" 8655 8708 8656 - #: src/view/screens/CopyrightPolicy.tsx:35 8709 + #: src/view/screens/CopyrightPolicy.tsx:38 8657 8710 msgid "The Copyright Policy has been moved to <0/>" 8658 8711 msgstr "" 8659 8712 ··· 8707 8760 msgid "The starter pack that you are trying to view is invalid. You may delete this starter pack instead." 8708 8761 msgstr "" 8709 8762 8710 - #: src/components/ContextMenu/index.tsx:433 8763 + #: src/components/ContextMenu/index.tsx:434 8711 8764 msgid "The subject of the context menu" 8712 8765 msgstr "" 8713 8766 8714 - #: src/view/screens/Support.tsx:37 8767 + #: src/view/screens/Support.tsx:40 8715 8768 msgid "The support form has been moved. If you need help, please <0/> or visit {HELP_DESK_URL} to get in touch with us." 8716 8769 msgstr "" 8717 8770 ··· 8736 8789 msgstr "" 8737 8790 8738 8791 #: src/screens/Profile/components/ProfileFeedHeader.tsx:178 8792 + #: src/screens/ProfileList/components/Header.tsx:88 8793 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:76 8794 + #: src/screens/SavedFeeds.tsx:97 8739 8795 #: src/view/screens/ProfileList.tsx:375 8740 8796 #: src/view/screens/ProfileList.tsx:394 8741 - #: src/view/screens/SavedFeeds.tsx:93 8742 8797 msgid "There was an issue contacting the server" 8743 8798 msgstr "" 8744 8799 ··· 8752 8807 msgstr "" 8753 8808 8754 8809 #: src/screens/Search/Explore.tsx:986 8755 - #: src/view/com/posts/PostFeed.tsx:787 8810 + #: src/view/com/posts/PostFeed.tsx:751 8756 8811 msgid "There was an issue fetching posts. Tap here to try again." 8757 8812 msgstr "" 8758 8813 ··· 8764 8819 msgid "There was an issue fetching your app passwords" 8765 8820 msgstr "" 8766 8821 8767 - #: src/view/com/feeds/ProfileFeedgens.tsx:151 8768 - #: src/view/com/lists/ProfileLists.tsx:150 8822 + #: src/view/com/feeds/ProfileFeedgens.tsx:163 8823 + #: src/view/com/lists/ProfileLists.tsx:161 8769 8824 msgid "There was an issue fetching your lists. Tap here to try again." 8770 8825 msgstr "" 8771 8826 ··· 8809 8864 #: src/screens/List/ListHiddenScreen.tsx:63 8810 8865 #: src/screens/List/ListHiddenScreen.tsx:77 8811 8866 #: src/screens/List/ListHiddenScreen.tsx:99 8867 + #: src/screens/ProfileList/components/Header.tsx:107 8868 + #: src/screens/ProfileList/components/Header.tsx:125 8869 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:129 8870 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:147 8871 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:40 8872 + #: src/screens/ProfileList/components/SubscribeMenu.tsx:59 8812 8873 #: src/view/screens/ProfileList.tsx:411 8813 8874 #: src/view/screens/ProfileList.tsx:429 8814 8875 #: src/view/screens/ProfileList.tsx:447 ··· 8907 8968 msgid "This feature allows users to receive notifications for your new posts and replies. Who do you want to enable this for?" 8908 8969 msgstr "" 8909 8970 8910 - #: src/screens/Settings/components/ExportCarDialog.tsx:96 8971 + #: src/screens/Settings/components/ExportCarDialog.tsx:95 8911 8972 msgid "This feature is in beta. You can read more about repository exports in <0>this blogpost</0>." 8912 8973 msgstr "" 8913 8974 ··· 8929 8990 8930 8991 #: src/components/StarterPack/Main/PostsList.tsx:36 8931 8992 #: src/screens/Profile/ProfileFeed/index.tsx:192 8993 + #: src/screens/ProfileList/FeedSection.tsx:71 8932 8994 #: src/view/screens/ProfileList.tsx:861 8933 8995 msgid "This feed is empty." 8934 8996 msgstr "" ··· 8958 9020 msgid "This label was applied by you." 8959 9021 msgstr "" 8960 9022 8961 - #: src/screens/Profile/Sections/Labels.tsx:218 9023 + #: src/screens/Profile/Sections/Labels.tsx:219 8962 9024 msgid "This labeler hasn't declared what labels it publishes, and may not be active." 8963 9025 msgstr "" 8964 9026 ··· 8974 9036 msgid "This list – created by you – contains possible violations of Bluesky's community guidelines in its name or description." 8975 9037 msgstr "" 8976 9038 9039 + #: src/screens/ProfileList/AboutSection.tsx:98 8977 9040 #: src/view/screens/ProfileList.tsx:980 8978 9041 msgid "This list is empty." 8979 9042 msgstr "" ··· 8982 9045 msgid "This moderation service is unavailable. See below for more details. If this issue persists, contact us." 8983 9046 msgstr "" 8984 9047 8985 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:676 9048 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:670 8986 9049 msgid "This post claims to have been created on <0>{0}</0>, but was first seen by Bluesky on <1>{1}</1>." 8987 9050 msgstr "" 8988 9051 ··· 9051 9114 msgid "This user is included in the <0>{0}</0> list which you have muted." 9052 9115 msgstr "" 9053 9116 9054 - #: src/components/NewskieDialog.tsx:65 9117 + #: src/components/NewskieDialog.tsx:47 9055 9118 msgid "This user is new here. Press for more info about when they joined." 9056 9119 msgstr "" 9057 9120 ··· 9090 9153 msgid "Threaded" 9091 9154 msgstr "" 9092 9155 9093 - #: src/Navigation.tsx:370 9156 + #: src/Navigation.tsx:357 9094 9157 msgid "Threads Preferences" 9095 9158 msgstr "" 9096 9159 ··· 9123 9186 msgid "TODO: Fall back to constellation api to find blocked replies" 9124 9187 msgstr "" 9125 9188 9126 - #: src/screens/Moderation/index.tsx:323 9189 + #: src/screens/Moderation/index.tsx:322 9127 9190 msgid "Toggle to enable or disable adult content" 9128 9191 msgstr "" 9129 9192 ··· 9144 9207 msgid "Top replies first" 9145 9208 msgstr "" 9146 9209 9147 - #: src/Navigation.tsx:549 9210 + #: src/Navigation.tsx:536 9148 9211 msgid "Topic" 9149 9212 msgstr "" 9150 9213 ··· 9152 9215 #: src/components/dms/MessageContextMenu.tsx:139 9153 9216 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:542 9154 9217 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:544 9155 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:598 9156 - #: src/screens/PostThread/components/ThreadItemAnchor.tsx:601 9218 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:592 9219 + #: src/screens/PostThread/components/ThreadItemAnchor.tsx:595 9157 9220 msgid "Translate" 9158 9221 msgstr "" 9159 9222 ··· 9222 9285 9223 9286 #: src/screens/Login/ForgotPasswordForm.tsx:68 9224 9287 #: src/screens/Login/index.tsx:83 9225 - #: src/screens/Login/LoginForm.tsx:178 9288 + #: src/screens/Login/LoginForm.tsx:176 9226 9289 #: src/screens/Login/SetNewPasswordForm.tsx:81 9227 9290 #: src/screens/Signup/index.tsx:82 9228 9291 msgid "Unable to contact your service. Please check your Internet connection." ··· 9250 9313 #: src/components/dms/MessagesListBlockedFooter.tsx:119 9251 9314 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:208 9252 9315 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:328 9316 + #: src/screens/ProfileList/components/Header.tsx:171 9317 + #: src/screens/ProfileList/components/Header.tsx:178 9253 9318 #: src/view/com/profile/ProfileMenu.tsx:547 9254 9319 #: src/view/screens/ProfileList.tsx:741 9255 9320 msgid "Unblock" ··· 9272 9337 msgid "Unblock Account?" 9273 9338 msgstr "" 9274 9339 9340 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:254 9341 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:257 9275 9342 #: src/view/screens/ProfileList.tsx:637 9276 9343 msgid "Unblock list" 9277 9344 msgstr "" ··· 9327 9394 msgstr "" 9328 9395 9329 9396 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:152 9330 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:95 9397 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:94 9331 9398 msgctxt "video" 9332 9399 msgid "Unmute" 9333 9400 msgstr "" 9334 9401 9402 + #: src/screens/ProfileList/components/Header.tsx:185 9403 + #: src/screens/ProfileList/components/Header.tsx:192 9335 9404 #: src/view/screens/ProfileList.tsx:748 9336 9405 msgid "Unmute" 9337 9406 msgstr "" ··· 9352 9421 msgid "Unmute conversation" 9353 9422 msgstr "" 9354 9423 9424 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:264 9425 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:267 9355 9426 #: src/view/screens/ProfileList.tsx:622 9356 9427 msgid "Unmute list" 9357 9428 msgstr "" ··· 9365 9436 msgid "Unmute video" 9366 9437 msgstr "" 9367 9438 9439 + #: src/screens/ProfileList/components/Header.tsx:156 9440 + #: src/screens/ProfileList/components/Header.tsx:163 9368 9441 #: src/view/screens/ProfileList.tsx:732 9369 9442 msgid "Unpin" 9370 9443 msgstr "" 9371 9444 9372 9445 #: src/screens/Profile/components/ProfileFeedHeader.tsx:523 9373 9446 #: src/screens/Profile/components/ProfileFeedHeader.tsx:530 9447 + #: src/screens/SavedFeeds.tsx:351 9374 9448 msgid "Unpin feed" 9375 9449 msgstr "" 9376 9450 ··· 9388 9462 msgid "Unpin from profile" 9389 9463 msgstr "" 9390 9464 9465 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:237 9466 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:240 9391 9467 #: src/view/screens/ProfileList.tsx:602 9392 9468 msgid "Unpin moderation list" 9393 9469 msgstr "" ··· 9396 9472 msgid "Unpinned {0} from Home" 9397 9473 msgstr "" 9398 9474 9475 + #: src/screens/ProfileList/components/Header.tsx:75 9399 9476 #: src/view/screens/ProfileList.tsx:362 9400 9477 msgid "Unpinned from your feeds" 9478 + msgstr "" 9479 + 9480 + #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:109 9481 + msgid "Unpinned list" 9401 9482 msgstr "" 9402 9483 9403 9484 #: src/screens/Settings/Settings.tsx:478 ··· 9472 9553 msgid "Updating..." 9473 9554 msgstr "" 9474 9555 9475 - #: src/screens/Onboarding/StepProfile/index.tsx:293 9556 + #: src/screens/Onboarding/StepProfile/index.tsx:286 9476 9557 msgid "Upload a photo instead" 9477 9558 msgstr "" 9478 9559 ··· 9535 9616 msgid "Use my default browser" 9536 9617 msgstr "" 9537 9618 9538 - #: src/screens/Feeds/NoSavedFeedsOfAnyType.tsx:53 9619 + #: src/screens/Feeds/NoSavedFeedsOfAnyType.tsx:56 9539 9620 msgid "Use recommended" 9540 9621 msgstr "" 9541 9622 ··· 9607 9688 msgid "Username must only contain letters (a-z), numbers, and hyphens" 9608 9689 msgstr "" 9609 9690 9610 - #: src/screens/Login/LoginForm.tsx:217 9691 + #: src/screens/Login/LoginForm.tsx:215 9611 9692 msgid "Username or email address" 9612 9693 msgstr "" 9613 9694 ··· 9619 9700 msgid "users following <0>@{0}</0>" 9620 9701 msgstr "" 9621 9702 9622 - #: src/screens/Messages/Settings.tsx:92 9623 - #: src/screens/Messages/Settings.tsx:95 9703 + #: src/screens/Messages/Settings.tsx:79 9704 + #: src/screens/Messages/Settings.tsx:82 9624 9705 msgid "Users I follow" 9625 9706 msgstr "" 9626 9707 ··· 9644 9725 msgid "Verification failed, please try again." 9645 9726 msgstr "" 9646 9727 9647 - #: src/screens/Moderation/index.tsx:290 9728 + #: src/screens/Moderation/index.tsx:289 9648 9729 msgid "Verification settings" 9649 9730 msgstr "" 9650 9731 9651 - #: src/Navigation.tsx:207 9732 + #: src/Navigation.tsx:194 9652 9733 #: src/screens/Moderation/VerificationSettings.tsx:32 9653 9734 msgid "Verification Settings" 9654 9735 msgstr "" ··· 9719 9800 msgid "Video failed to process" 9720 9801 msgstr "" 9721 9802 9722 - #: src/Navigation.tsx:605 9803 + #: src/Navigation.tsx:592 9723 9804 msgid "Video Feed" 9724 9805 msgstr "" 9725 9806 ··· 9733 9814 msgid "Video Games" 9734 9815 msgstr "" 9735 9816 9736 - #: src/screens/VideoFeed/index.tsx:1076 9817 + #: src/screens/VideoFeed/index.tsx:1077 9737 9818 msgid "Video is paused" 9738 9819 msgstr "" 9739 9820 9740 - #: src/screens/VideoFeed/index.tsx:1076 9821 + #: src/screens/VideoFeed/index.tsx:1077 9741 9822 msgid "Video is playing" 9742 9823 msgstr "" 9743 9824 9744 - #: src/components/Post/Embed/VideoEmbed/index.web.tsx:220 9825 + #: src/components/Post/Embed/VideoEmbed/index.web.tsx:225 9745 9826 msgid "Video not found." 9746 9827 msgstr "" 9747 9828 ··· 9794 9875 msgid "View blocked user's profile" 9795 9876 msgstr "" 9796 9877 9797 - #: src/screens/Settings/components/ExportCarDialog.tsx:100 9878 + #: src/screens/Settings/components/ExportCarDialog.tsx:99 9798 9879 msgid "View blogpost for more details" 9799 9880 msgstr "" 9800 9881 ··· 9802 9883 msgid "View debug entry" 9803 9884 msgstr "" 9804 9885 9805 - #: src/components/ReportDialog/SelectReportOptionView.tsx:137 9886 + #: src/components/ReportDialog/SelectReportOptionView.tsx:140 9806 9887 #: src/screens/VideoFeed/index.tsx:659 9807 9888 #: src/screens/VideoFeed/index.tsx:677 9808 9889 msgid "View details" 9809 9890 msgstr "" 9810 9891 9811 - #: src/components/ReportDialog/SelectReportOptionView.tsx:132 9892 + #: src/components/ReportDialog/SelectReportOptionView.tsx:135 9812 9893 msgid "View details for reporting a copyright violation" 9813 9894 msgstr "" 9814 9895 ··· 9816 9897 msgid "View full thread" 9817 9898 msgstr "" 9818 9899 9819 - #: src/components/moderation/LabelsOnMe.tsx:46 9900 + #: src/components/moderation/LabelsOnMe.tsx:51 9820 9901 msgid "View information about these labels" 9821 9902 msgstr "" 9822 9903 ··· 9839 9920 #: src/components/ProfileHoverCard/index.web.tsx:486 9840 9921 #: src/components/ProfileHoverCard/index.web.tsx:513 9841 9922 #: src/view/com/posts/PostFeedErrorMessage.tsx:179 9842 - #: src/view/com/util/PostMeta.tsx:91 9843 - #: src/view/com/util/PostMeta.tsx:128 9923 + #: src/view/com/util/PostMeta.tsx:90 9924 + #: src/view/com/util/PostMeta.tsx:127 9844 9925 msgid "View profile" 9845 9926 msgstr "" 9846 9927 ··· 9868 9949 msgid "View video" 9869 9950 msgstr "" 9870 9951 9871 - #: src/screens/Moderation/index.tsx:270 9952 + #: src/screens/Moderation/index.tsx:269 9872 9953 msgid "View your blocked accounts" 9873 9954 msgstr "" 9874 9955 9875 - #: src/screens/Moderation/index.tsx:210 9956 + #: src/screens/Moderation/index.tsx:209 9876 9957 msgid "View your default post interaction settings" 9877 9958 msgstr "" 9878 9959 9879 - #: src/view/com/home/HomeHeaderLayout.web.tsx:56 9880 - #: src/view/com/home/HomeHeaderLayoutMobile.tsx:71 9960 + #: src/view/com/home/HomeHeaderLayout.web.tsx:57 9961 + #: src/view/com/home/HomeHeaderLayoutMobile.tsx:72 9881 9962 msgid "View your feeds and explore more" 9882 9963 msgstr "" 9883 9964 9884 - #: src/screens/Moderation/index.tsx:240 9965 + #: src/screens/Moderation/index.tsx:239 9885 9966 msgid "View your moderation lists" 9886 9967 msgstr "" 9887 9968 9888 - #: src/screens/Moderation/index.tsx:255 9969 + #: src/screens/Moderation/index.tsx:254 9889 9970 msgid "View your muted accounts" 9890 9971 msgstr "" 9891 9972 ··· 9915 9996 msgid "Visit your notification settings" 9916 9997 msgstr "" 9917 9998 9918 - #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:81 9999 + #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:80 9919 10000 msgid "Volume" 9920 10001 msgstr "" 9921 10002 9922 - #: src/components/moderation/LabelPreference.tsx:136 9923 - #: src/lib/moderation/useLabelBehaviorDescription.ts:17 9924 - #: src/lib/moderation/useLabelBehaviorDescription.ts:22 10003 + #: src/components/moderation/LabelPreference.tsx:138 10004 + #: src/lib/moderation/useLabelBehaviorDescription.ts:20 10005 + #: src/lib/moderation/useLabelBehaviorDescription.ts:25 9925 10006 msgid "Warn" 9926 10007 msgstr "" 9927 10008 9928 - #: src/lib/moderation/useLabelBehaviorDescription.ts:48 10009 + #: src/lib/moderation/useLabelBehaviorDescription.ts:51 9929 10010 msgid "Warn content" 9930 10011 msgstr "" 9931 10012 9932 - #: src/lib/moderation/useLabelBehaviorDescription.ts:46 10013 + #: src/lib/moderation/useLabelBehaviorDescription.ts:49 9933 10014 msgid "Warn content and filter from feeds" 9934 10015 msgstr "" 9935 10016 ··· 9966 10047 msgid "We have sent another verification email to <0>{0}</0>." 9967 10048 msgstr "" 9968 10049 9969 - #: src/screens/Onboarding/StepFinished.tsx:533 10050 + #: src/screens/Onboarding/StepFinished.tsx:529 9970 10051 msgid "We hope you have a wonderful time. Remember, Bluesky is:" 9971 10052 msgstr "" 9972 10053 ··· 9990 10071 msgid "We were unable to load your birth date preferences. Please try again." 9991 10072 msgstr "" 9992 10073 9993 - #: src/screens/Moderation/index.tsx:397 10074 + #: src/screens/Moderation/index.tsx:396 9994 10075 msgid "We were unable to load your configured labelers at this time." 9995 10076 msgstr "" 9996 10077 ··· 10027 10108 msgid "We’re introducing a new layer of verification on Bluesky — an easy-to-see checkmark." 10028 10109 msgstr "" 10029 10110 10111 + #: src/screens/ProfileList/index.tsx:87 10030 10112 #: src/view/screens/ProfileList.tsx:117 10031 10113 msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." 10032 10114 msgstr "" ··· 10043 10125 msgid "We're sorry! The post you are replying to has been deleted." 10044 10126 msgstr "" 10045 10127 10046 - #: src/components/Lists.tsx:195 10128 + #: src/components/Lists.tsx:194 10047 10129 #: src/view/screens/NotFound.tsx:50 10048 10130 msgid "We're sorry! We can't find the page you were looking for." 10049 10131 msgstr "" ··· 10076 10158 msgid "Welcome to the ATmosphere!" 10077 10159 msgstr "" 10078 10160 10079 - #: src/components/NewskieDialog.tsx:103 10161 + #: src/components/NewskieDialog.tsx:121 10080 10162 msgid "Welcome, friend!" 10081 10163 msgstr "" 10082 10164 ··· 10116 10198 10117 10199 #: src/screens/Home/NoFeedsPinned.tsx:79 10118 10200 #: src/screens/Messages/ChatList.tsx:242 10119 - #: src/screens/Messages/Inbox.tsx:176 10201 + #: src/screens/Messages/Inbox.tsx:182 10120 10202 msgid "Whoops!" 10121 10203 msgstr "" 10122 10204 ··· 10129 10211 msgid "Why are you appealing?" 10130 10212 msgstr "" 10131 10213 10132 - #: src/components/ReportDialog/SelectReportOptionView.tsx:42 10214 + #: src/components/ReportDialog/SelectReportOptionView.tsx:45 10133 10215 msgid "Why should this content be reviewed?" 10134 10216 msgstr "" 10135 10217 10136 10218 #: src/components/moderation/ReportDialog/copy.ts:32 10137 - #: src/components/ReportDialog/SelectReportOptionView.tsx:55 10219 + #: src/components/ReportDialog/SelectReportOptionView.tsx:58 10138 10220 msgid "Why should this feed be reviewed?" 10139 10221 msgstr "" 10140 10222 10141 10223 #: src/components/moderation/ReportDialog/copy.ts:26 10142 - #: src/components/ReportDialog/SelectReportOptionView.tsx:52 10224 + #: src/components/ReportDialog/SelectReportOptionView.tsx:55 10143 10225 msgid "Why should this list be reviewed?" 10144 10226 msgstr "" 10145 10227 10146 10228 #: src/components/moderation/ReportDialog/copy.ts:44 10147 - #: src/components/ReportDialog/SelectReportOptionView.tsx:61 10229 + #: src/components/ReportDialog/SelectReportOptionView.tsx:64 10148 10230 msgid "Why should this message be reviewed?" 10149 10231 msgstr "" 10150 10232 10151 10233 #: src/components/moderation/ReportDialog/copy.ts:20 10152 - #: src/components/ReportDialog/SelectReportOptionView.tsx:49 10234 + #: src/components/ReportDialog/SelectReportOptionView.tsx:52 10153 10235 msgid "Why should this post be reviewed?" 10154 10236 msgstr "" 10155 10237 10156 10238 #: src/components/moderation/ReportDialog/copy.ts:38 10157 - #: src/components/ReportDialog/SelectReportOptionView.tsx:58 10239 + #: src/components/ReportDialog/SelectReportOptionView.tsx:61 10158 10240 msgid "Why should this starter pack be reviewed?" 10159 10241 msgstr "" 10160 10242 10161 10243 #: src/components/moderation/ReportDialog/copy.ts:14 10162 - #: src/components/ReportDialog/SelectReportOptionView.tsx:46 10244 + #: src/components/ReportDialog/SelectReportOptionView.tsx:49 10163 10245 msgid "Why should this user be reviewed?" 10164 10246 msgstr "" 10165 10247 ··· 10195 10277 msgid "www.mylivestream.tv" 10196 10278 msgstr "" 10197 10279 10198 - #: src/view/com/composer/select-language/SuggestedLanguage.tsx:100 10280 + #: src/view/com/composer/select-language/SuggestedLanguage.tsx:102 10199 10281 msgid "Yes" 10200 10282 msgstr "" 10201 10283 ··· 10224 10306 msgid "Yesterday" 10225 10307 msgstr "" 10226 10308 10227 - #: src/components/NewskieDialog.tsx:43 10309 + #: src/components/NewskieDialog.tsx:91 10228 10310 msgid "You" 10229 10311 msgstr "" 10230 10312 ··· 10298 10380 msgid "You can choose whether chat notifications have sound in the chat settings within the app" 10299 10381 msgstr "" 10300 10382 10301 - #: src/screens/Messages/Settings.tsx:111 10383 + #: src/screens/Messages/Settings.tsx:98 10302 10384 msgid "You can continue ongoing conversations regardless of which setting you choose." 10303 10385 msgstr "" 10304 10386 ··· 10342 10424 msgid "You do not have any followers." 10343 10425 msgstr "" 10344 10426 10345 - #: src/screens/Profile/KnownFollowers.tsx:109 10427 + #: src/screens/Profile/KnownFollowers.tsx:112 10346 10428 msgid "You don't follow any users who follow @{name}." 10347 10429 msgstr "" 10348 10430 10349 - #: src/screens/Messages/Inbox.tsx:220 10431 + #: src/screens/Messages/Inbox.tsx:226 10350 10432 msgid "You don't have any chat requests at the moment." 10351 10433 msgstr "" 10352 10434 ··· 10354 10436 msgid "You don't have any invite codes yet! We'll send you some when you've been on Bluesky for a little longer." 10355 10437 msgstr "" 10356 10438 10357 - #: src/view/screens/SavedFeeds.tsx:145 10439 + #: src/screens/SavedFeeds.tsx:149 10358 10440 msgid "You don't have any pinned feeds." 10359 10441 msgstr "" 10360 10442 10361 - #: src/view/screens/SavedFeeds.tsx:185 10443 + #: src/screens/SavedFeeds.tsx:191 10362 10444 msgid "You don't have any saved feeds." 10363 10445 msgstr "" 10364 10446 ··· 10403 10485 msgid "You have no conversations yet. Start one!" 10404 10486 msgstr "" 10405 10487 10406 - #: src/view/com/feeds/ProfileFeedgens.tsx:139 10488 + #: src/view/com/feeds/ProfileFeedgens.tsx:151 10407 10489 msgid "You have no feeds." 10408 10490 msgstr "" 10409 10491 10410 10492 #: src/view/com/lists/MyLists.tsx:81 10411 - #: src/view/com/lists/ProfileLists.tsx:135 10493 + #: src/view/com/lists/ProfileLists.tsx:149 10412 10494 msgid "You have no lists." 10413 10495 msgstr "" 10414 10496 ··· 10424 10506 msgid "You have not muted any accounts yet. To mute an account, go to their profile and select \"Mute account\" from the menu on their account." 10425 10507 msgstr "" 10426 10508 10427 - #: src/components/Lists.tsx:58 10509 + #: src/components/Lists.tsx:57 10428 10510 msgid "You have reached the end" 10429 10511 msgstr "" 10430 10512 ··· 10436 10518 msgid "You have temporarily reached the limit for video uploads. Please try again later." 10437 10519 msgstr "" 10438 10520 10439 - #: src/components/StarterPack/ProfileStarterPacks.tsx:263 10521 + #: src/components/StarterPack/ProfileStarterPacks.tsx:259 10440 10522 msgid "You haven't created a starter pack yet!" 10441 10523 msgstr "" 10442 10524 ··· 10473 10555 msgid "You must be at least 13 years old to use Bluesky. Read our <0>Terms of Service</0> for more information." 10474 10556 msgstr "" 10475 10557 10476 - #: src/components/StarterPack/ProfileStarterPacks.tsx:334 10558 + #: src/components/StarterPack/ProfileStarterPacks.tsx:330 10477 10559 msgid "You must be following at least seven other people to generate a starter pack." 10478 10560 msgstr "" 10479 10561 10480 - #: src/components/StarterPack/QrCodeDialog.tsx:61 10562 + #: src/components/StarterPack/QrCodeDialog.tsx:65 10481 10563 msgid "You must grant access to your photo library to save a QR code" 10482 10564 msgstr "" 10483 10565 ··· 10575 10657 msgid "You're in line" 10576 10658 msgstr "" 10577 10659 10578 - #: src/screens/Onboarding/StepFinished.tsx:530 10660 + #: src/screens/Onboarding/StepFinished.tsx:526 10579 10661 msgid "You're ready to go!" 10580 10662 msgstr "" 10581 10663 ··· 10617 10699 msgid "You've reached your daily limit for video uploads (too many videos)" 10618 10700 msgstr "" 10619 10701 10620 - #: src/screens/VideoFeed/index.tsx:1127 10702 + #: src/screens/VideoFeed/index.tsx:1128 10621 10703 msgid "You've run out of videos to watch. Maybe it's a good time to take a break?" 10622 10704 msgstr "" 10623 10705 ··· 10649 10731 msgid "Your birth date" 10650 10732 msgstr "" 10651 10733 10652 - #: src/components/Post/Embed/VideoEmbed/index.web.tsx:224 10734 + #: src/components/Post/Embed/VideoEmbed/index.web.tsx:229 10653 10735 msgid "Your browser does not support the video format. Please try a different browser." 10654 10736 msgstr "" 10655 10737 ··· 10692 10774 msgid "Your full handle will be <0>@{0}</0>" 10693 10775 msgstr "" 10694 10776 10695 - #: src/Navigation.tsx:521 10777 + #: src/Navigation.tsx:508 10696 10778 #: src/screens/Search/modules/ExploreInterestsCard.tsx:67 10697 10779 #: src/screens/Settings/ContentAndMediaSettings.tsx:92 10698 10780 #: src/screens/Settings/ContentAndMediaSettings.tsx:95 ··· 10729 10811 msgid "Your posts were sent" 10730 10812 msgstr "" 10731 10813 10732 - #: src/screens/Onboarding/StepFinished.tsx:545 10814 + #: src/screens/Onboarding/StepFinished.tsx:541 10733 10815 msgid "Your posts, likes, and blocks are public. Mutes are private." 10734 10816 msgstr "" 10735 10817 10736 - #: src/screens/Onboarding/StepFinished.tsx:422 10818 + #: src/screens/Onboarding/StepFinished.tsx:418 10737 10819 msgid "Your profile picture" 10738 10820 msgstr "" 10739 10821 10740 - #: src/screens/Onboarding/StepFinished.tsx:350 10822 + #: src/screens/Onboarding/StepFinished.tsx:346 10741 10823 msgid "Your profile picture surrounded by concentric circles of other users' profile pictures" 10742 10824 msgstr "" 10743 10825
+1 -1
src/logger/__tests__/logDump.test.ts
··· 1 1 import {expect, test} from '@jest/globals' 2 2 3 - import {add, ConsoleTransportEntry, getEntries} from '#/logger/logDump' 3 + import {add, type ConsoleTransportEntry, getEntries} from '#/logger/logDump' 4 4 import {LogContext, LogLevel} from '#/logger/types' 5 5 6 6 test('works', () => {
+1 -1
src/logger/logDump.ts
··· 1 - import type {LogContext, LogLevel, Metadata} from '#/logger/types' 1 + import {type LogContext, type LogLevel, type Metadata} from '#/logger/types' 2 2 3 3 export type ConsoleTransportEntry = { 4 4 id: string
+1 -1
src/logger/transports/bitdrift.ts
··· 1 1 import {debug, error, info, warn} from '#/logger/bitdrift/lib' 2 - import {LogLevel, Transport} from '#/logger/types' 2 + import {LogLevel, type Transport} from '#/logger/types' 3 3 import {prepareMetadata} from '#/logger/util' 4 4 5 5 const logFunctions = {
+1 -1
src/logger/transports/console.ts
··· 1 1 import format from 'date-fns/format' 2 2 3 - import {LogLevel, Transport} from '#/logger/types' 3 + import {LogLevel, type Transport} from '#/logger/types' 4 4 import {prepareMetadata} from '#/logger/util' 5 5 import {isWeb} from '#/platform/detection' 6 6
+1 -1
src/logger/util.ts
··· 1 - import {LogLevel, Metadata, Serializable} from '#/logger/types' 1 + import {LogLevel, type Metadata, type Serializable} from '#/logger/types' 2 2 3 3 export const enabledLogLevels: { 4 4 [key in LogLevel]: LogLevel[]
-49
src/platform/polyfills.ts
··· 1 1 import 'react-native-url-polyfill/auto' 2 2 import 'fast-text-encoding' 3 3 export {} 4 - 5 - /** 6 - https://github.com/MaxArt2501/base64-js 7 - The MIT License (MIT) 8 - Copyright (c) 2014 MaxArt2501 9 - */ 10 - 11 - const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' 12 - // Regular expression to check formal correctness of base64 encoded strings 13 - const b64re = 14 - /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/ 15 - 16 - globalThis.atob = (str: string): string => { 17 - // atob can work with strings with whitespaces, even inside the encoded part, 18 - // but only \t, \n, \f, \r and ' ', which can be stripped. 19 - str = String(str).replace(/[\t\n\f\r ]+/g, '') 20 - if (!b64re.test(str)) { 21 - throw new TypeError( 22 - "Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.", 23 - ) 24 - } 25 - 26 - // Adding the padding if missing, for simplicity 27 - str += '=='.slice(2 - (str.length & 3)) 28 - var bitmap, 29 - result = '', 30 - r1, 31 - r2, 32 - i = 0 33 - for (; i < str.length; ) { 34 - bitmap = 35 - (b64.indexOf(str.charAt(i++)) << 18) | 36 - (b64.indexOf(str.charAt(i++)) << 12) | 37 - ((r1 = b64.indexOf(str.charAt(i++))) << 6) | 38 - (r2 = b64.indexOf(str.charAt(i++))) 39 - 40 - result += 41 - r1 === 64 42 - ? String.fromCharCode((bitmap >> 16) & 255) 43 - : r2 === 64 44 - ? String.fromCharCode((bitmap >> 16) & 255, (bitmap >> 8) & 255) 45 - : String.fromCharCode( 46 - (bitmap >> 16) & 255, 47 - (bitmap >> 8) & 255, 48 - bitmap & 255, 49 - ) 50 - } 51 - return result 52 - }
+16 -18
src/screens/Feeds/NoFollowingFeed.tsx
··· 1 - import React from 'react' 2 - import {View} from 'react-native' 1 + import {type GestureResponderEvent, View} from 'react-native' 3 2 import {msg, Trans} from '@lingui/macro' 4 3 import {useLingui} from '@lingui/react' 5 4 ··· 9 8 import {InlineLinkText} from '#/components/Link' 10 9 import {Text} from '#/components/Typography' 11 10 12 - export function NoFollowingFeed() { 11 + export function NoFollowingFeed({onAddFeed}: {onAddFeed?: () => void}) { 13 12 const t = useTheme() 14 13 const {_} = useLingui() 15 14 const {mutateAsync: addSavedFeeds} = useAddSavedFeedsMutation() 16 15 17 - const addRecommendedFeeds = React.useCallback( 18 - (e: any) => { 19 - e.preventDefault() 16 + const addRecommendedFeeds = (e: GestureResponderEvent) => { 17 + e.preventDefault() 20 18 21 - addSavedFeeds([ 22 - { 23 - ...TIMELINE_SAVED_FEED, 24 - pinned: true, 25 - }, 26 - ]) 19 + addSavedFeeds([ 20 + { 21 + ...TIMELINE_SAVED_FEED, 22 + pinned: true, 23 + }, 24 + ]) 27 25 28 - // prevent navigation 29 - return false 30 - }, 31 - [addSavedFeeds], 32 - ) 26 + onAddFeed?.() 27 + 28 + // prevent navigation 29 + return false as const 30 + } 33 31 34 32 return ( 35 33 <View style={[a.flex_row, a.flex_wrap, a.align_center, a.py_md, a.px_lg]}> ··· 37 35 <Trans> 38 36 Looks like you're missing a following feed.{' '} 39 37 <InlineLinkText 40 - to="/" 38 + to="#" 41 39 label={_(msg`Add the default feed of only people you follow`)} 42 40 onPress={addRecommendedFeeds} 43 41 style={[a.leading_snug]}>
+10 -7
src/screens/Feeds/NoSavedFeedsOfAnyType.tsx
··· 1 - import React from 'react' 2 1 import {View} from 'react-native' 3 2 import {TID} from '@atproto/common-web' 4 3 import {msg, Trans} from '@lingui/macro' ··· 16 15 * feeds if pressed. It should only be presented to the user if they actually 17 16 * have no other feeds saved. 18 17 */ 19 - export function NoSavedFeedsOfAnyType() { 18 + export function NoSavedFeedsOfAnyType({ 19 + onAddRecommendedFeeds, 20 + }: { 21 + onAddRecommendedFeeds?: () => void 22 + }) { 20 23 const t = useTheme() 21 24 const {_} = useLingui() 22 25 const {isPending, mutateAsync: overwriteSavedFeeds} = 23 26 useOverwriteSavedFeedsMutation() 24 27 25 - const addRecommendedFeeds = React.useCallback(async () => { 28 + const addRecommendedFeeds = async () => { 29 + onAddRecommendedFeeds?.() 26 30 await overwriteSavedFeeds( 27 31 RECOMMENDED_SAVED_FEEDS.map(f => ({ 28 32 ...f, 29 33 id: TID.nextStr(), 30 34 })), 31 35 ) 32 - }, [overwriteSavedFeeds]) 36 + } 33 37 34 38 return ( 35 39 <View ··· 46 50 disabled={isPending} 47 51 label={_(msg`Apply default recommended feeds`)} 48 52 size="small" 49 - variant="solid" 50 - color="primary" 53 + color="primary_subtle" 51 54 onPress={addRecommendedFeeds}> 52 - <ButtonIcon icon={Plus} position="left" /> 55 + <ButtonIcon icon={Plus} /> 53 56 <ButtonText>{_(msg`Use recommended`)}</ButtonText> 54 57 </Button> 55 58 </View>
+1 -1
src/screens/Home/NoFeedsPinned.tsx
··· 6 6 7 7 import {DISCOVER_SAVED_FEED, TIMELINE_SAVED_FEED} from '#/lib/constants' 8 8 import {useOverwriteSavedFeedsMutation} from '#/state/queries/preferences' 9 - import {UsePreferencesQueryResponse} from '#/state/queries/preferences' 9 + import {type UsePreferencesQueryResponse} from '#/state/queries/preferences' 10 10 import {CenteredView} from '#/view/com/util/Views' 11 11 import {atoms as a} from '#/alf' 12 12 import {Button, ButtonIcon, ButtonText} from '#/components/Button'
+1 -1
src/screens/List/ListHiddenScreen.tsx
··· 11 11 import {RQKEY_ROOT as listQueryRoot} from '#/state/queries/list' 12 12 import {useListBlockMutation, useListMuteMutation} from '#/state/queries/list' 13 13 import { 14 - UsePreferencesQueryResponse, 14 + type UsePreferencesQueryResponse, 15 15 useRemoveFeedMutation, 16 16 } from '#/state/queries/preferences' 17 17 import {useSession} from '#/state/session'
+1 -1
src/screens/Login/ChooseAccountForm.tsx
··· 5 5 6 6 import {logEvent} from '#/lib/statsig/statsig' 7 7 import {logger} from '#/logger' 8 - import {SessionAccount, useSession, useSessionApi} from '#/state/session' 8 + import {type SessionAccount, useSession, useSessionApi} from '#/state/session' 9 9 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 10 10 import * as Toast from '#/view/com/util/Toast' 11 11 import {atoms as a} from '#/alf'
+1 -1
src/screens/Login/FormContainer.tsx
··· 1 - import React from 'react' 2 1 import {type StyleProp, View, type ViewStyle} from 'react-native' 2 + import type React from 'react' 3 3 4 4 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 5 5 import {Text} from '#/components/Typography'
+2 -2
src/screens/Login/ScreenTransition.tsx
··· 1 - import React from 'react' 2 - import {StyleProp, ViewStyle} from 'react-native' 1 + import {type StyleProp, type ViewStyle} from 'react-native' 3 2 import Animated, {FadeInRight, FadeOutLeft} from 'react-native-reanimated' 3 + import type React from 'react' 4 4 5 5 export function ScreenTransition({ 6 6 style,
+1 -1
src/screens/Messages/components/ChatStatusInfo.tsx
··· 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {ActiveConvoStates} from '#/state/messages/convo' 6 + import {type ActiveConvoStates} from '#/state/messages/convo' 7 7 import {useModerationOpts} from '#/state/preferences/moderation-opts' 8 8 import {useSession} from '#/state/session' 9 9 import {atoms as a, useTheme} from '#/alf'
+5 -2
src/screens/Messages/components/MessageInputEmbed.tsx
··· 9 9 } from '@atproto/api' 10 10 import {msg} from '@lingui/macro' 11 11 import {useLingui} from '@lingui/react' 12 - import {RouteProp, useNavigation, useRoute} from '@react-navigation/native' 12 + import {type RouteProp, useNavigation, useRoute} from '@react-navigation/native' 13 13 14 14 import {makeProfileLink} from '#/lib/routes/links' 15 - import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types' 15 + import { 16 + type CommonNavigatorParams, 17 + type NavigationProp, 18 + } from '#/lib/routes/types' 16 19 import { 17 20 convertBskyAppUrlIfNeeded, 18 21 isBskyPostUrl,
+1 -1
src/screens/Messages/components/MessageListError.tsx
··· 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {ConvoItem, ConvoItemError} from '#/state/messages/convo/types' 6 + import {type ConvoItem, ConvoItemError} from '#/state/messages/convo/types' 7 7 import {atoms as a, useTheme} from '#/alf' 8 8 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 9 9 import {InlineLinkText} from '#/components/Link'
+1 -1
src/screens/ModerationInteractionSettings/index.tsx
··· 9 9 import {createPostgateRecord} from '#/state/queries/postgate/util' 10 10 import { 11 11 usePreferencesQuery, 12 - UsePreferencesQueryResponse, 12 + type UsePreferencesQueryResponse, 13 13 } from '#/state/queries/preferences' 14 14 import { 15 15 threadgateAllowUISettingToAllowRecordValue,
+1 -1
src/screens/Onboarding/StepInterests/InterestButton.tsx
··· 1 1 import React from 'react' 2 - import {TextStyle, View, ViewStyle} from 'react-native' 2 + import {type TextStyle, View, type ViewStyle} from 'react-native' 3 3 4 4 import {capitalize} from '#/lib/strings/capitalize' 5 5 import {useInterestsDisplayNames} from '#/screens/Onboarding/state'
+1 -1
src/screens/Onboarding/StepProfile/AvatarCreatorCircle.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 3 4 - import {Avatar} from '#/screens/Onboarding/StepProfile/index' 4 + import {type Avatar} from '#/screens/Onboarding/StepProfile/index' 5 5 import {atoms as a, useTheme} from '#/alf' 6 6 7 7 export function AvatarCreatorCircle({
+3 -3
src/screens/Onboarding/StepProfile/AvatarCreatorItems.tsx
··· 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {Avatar} from '#/screens/Onboarding/StepProfile/index' 6 + import {type Avatar} from '#/screens/Onboarding/StepProfile/index' 7 7 import { 8 - AvatarColor, 8 + type AvatarColor, 9 9 avatarColors, 10 10 emojiItems, 11 - EmojiName, 11 + type EmojiName, 12 12 emojiNames, 13 13 } from '#/screens/Onboarding/StepProfile/types' 14 14 import {atoms as a, useTheme} from '#/alf'
+4 -1
src/screens/Post/PostLikedBy.tsx
··· 2 2 import {Plural, Trans} from '@lingui/macro' 3 3 import {useFocusEffect} from '@react-navigation/native' 4 4 5 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 5 + import { 6 + type CommonNavigatorParams, 7 + type NativeStackScreenProps, 8 + } from '#/lib/routes/types' 6 9 import {makeRecordUri} from '#/lib/strings/url-helpers' 7 10 import {usePostThreadQuery} from '#/state/queries/post-thread' 8 11 import {useSetMinimalShellMode} from '#/state/shell'
+4 -1
src/screens/Post/PostQuotes.tsx
··· 2 2 import {Plural, Trans} from '@lingui/macro' 3 3 import {useFocusEffect} from '@react-navigation/native' 4 4 5 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 5 + import { 6 + type CommonNavigatorParams, 7 + type NativeStackScreenProps, 8 + } from '#/lib/routes/types' 6 9 import {makeRecordUri} from '#/lib/strings/url-helpers' 7 10 import {usePostThreadQuery} from '#/state/queries/post-thread' 8 11 import {useSetMinimalShellMode} from '#/state/shell'
+4 -1
src/screens/Post/PostRepostedBy.tsx
··· 2 2 import {Plural, Trans} from '@lingui/macro' 3 3 import {useFocusEffect} from '@react-navigation/native' 4 4 5 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 5 + import { 6 + type CommonNavigatorParams, 7 + type NativeStackScreenProps, 8 + } from '#/lib/routes/types' 6 9 import {makeRecordUri} from '#/lib/strings/url-helpers' 7 10 import {usePostThreadQuery} from '#/state/queries/post-thread' 8 11 import {useSetMinimalShellMode} from '#/state/shell'
+1 -1
src/screens/PostThread/components/ThreadItemAnchor.tsx
··· 354 354 )} 355 355 </Text> 356 356 357 - <View style={[{paddingLeft: 3, top: -1}]}> 357 + <View style={[a.pl_xs]}> 358 358 <VerificationCheckButton profile={authorShadow} size="md" /> 359 359 </View> 360 360 </View>
+1 -1
src/screens/Profile/ErrorState.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 import {useNavigation} from '@react-navigation/native' 6 6 7 - import {NavigationProp} from '#/lib/routes/types' 7 + import {type NavigationProp} from '#/lib/routes/types' 8 8 import {atoms as a, useTheme} from '#/alf' 9 9 import {Button, ButtonText} from '#/components/Button' 10 10 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
+1 -1
src/screens/Profile/Header/DisplayName.tsx
··· 4 4 import {sanitizeDisplayName} from '#/lib/strings/display-names' 5 5 import {sanitizeHandle} from '#/lib/strings/handles' 6 6 import {type Shadow} from '#/state/cache/types' 7 - import {atoms as a, platform, useBreakpoints, useTheme} from '#/alf' 7 + import {atoms as a, useBreakpoints, useTheme} from '#/alf' 8 8 import {Text} from '#/components/Typography' 9 9 import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton' 10 10
+3 -3
src/screens/Profile/Header/GrowableAvatar.tsx
··· 1 - import React from 'react' 2 - import {StyleProp, View, ViewStyle} from 'react-native' 1 + import {type StyleProp, View, type ViewStyle} from 'react-native' 3 2 import Animated, { 4 3 Extrapolation, 5 4 interpolate, 6 - SharedValue, 5 + type SharedValue, 7 6 useAnimatedStyle, 8 7 } from 'react-native-reanimated' 8 + import type React from 'react' 9 9 10 10 import {isIOS} from '#/platform/detection' 11 11 import {usePagerHeaderContext} from '#/view/com/pager/PagerHeaderContext'
+3 -2
src/screens/Profile/Header/GrowableBanner.tsx
··· 1 - import React, {useEffect, useState} from 'react' 1 + import {useEffect, useState} from 'react' 2 2 import {View} from 'react-native' 3 3 import {ActivityIndicator} from 'react-native' 4 4 import Animated, { 5 5 Extrapolation, 6 6 interpolate, 7 7 runOnJS, 8 - SharedValue, 8 + type SharedValue, 9 9 useAnimatedProps, 10 10 useAnimatedReaction, 11 11 useAnimatedStyle, ··· 13 13 import {useSafeAreaInsets} from 'react-native-safe-area-context' 14 14 import {BlurView} from 'expo-blur' 15 15 import {useIsFetching} from '@tanstack/react-query' 16 + import type React from 'react' 16 17 17 18 import {isIOS} from '#/platform/detection' 18 19 import {RQKEY_ROOT as STARTERPACK_RQKEY_ROOT} from '#/state/queries/actor-starter-packs'
+4 -1
src/screens/Profile/Header/StatusBarShadow.tsx
··· 1 - import Animated, {SharedValue, useAnimatedStyle} from 'react-native-reanimated' 1 + import Animated, { 2 + type SharedValue, 3 + useAnimatedStyle, 4 + } from 'react-native-reanimated' 2 5 import {useSafeAreaInsets} from 'react-native-safe-area-context' 3 6 import {LinearGradient} from 'expo-linear-gradient' 4 7
+5 -5
src/screens/Profile/Header/index.tsx
··· 1 1 import React, {memo, useState} from 'react' 2 - import {LayoutChangeEvent, StyleSheet, View} from 'react-native' 2 + import {type LayoutChangeEvent, StyleSheet, View} from 'react-native' 3 3 import Animated, { 4 4 runOnJS, 5 5 useAnimatedReaction, ··· 8 8 } from 'react-native-reanimated' 9 9 import {useSafeAreaInsets} from 'react-native-safe-area-context' 10 10 import { 11 - AppBskyActorDefs, 12 - AppBskyLabelerDefs, 13 - ModerationOpts, 14 - RichText as RichTextAPI, 11 + type AppBskyActorDefs, 12 + type AppBskyLabelerDefs, 13 + type ModerationOpts, 14 + type RichText as RichTextAPI, 15 15 } from '@atproto/api' 16 16 import {useIsFocused} from '@react-navigation/native' 17 17
+5 -2
src/screens/Profile/KnownFollowers.tsx
··· 1 1 import React from 'react' 2 - import {AppBskyActorDefs} from '@atproto/api' 2 + import {type AppBskyActorDefs} from '@atproto/api' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 import {useFocusEffect} from '@react-navigation/native' 6 6 7 7 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 8 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 8 + import { 9 + type CommonNavigatorParams, 10 + type NativeStackScreenProps, 11 + } from '#/lib/routes/types' 9 12 import {cleanError} from '#/lib/strings/errors' 10 13 import {logger} from '#/logger' 11 14 import {useProfileKnownFollowersQuery} from '#/state/queries/known-followers'
+4 -1
src/screens/Profile/ProfileFollowers.tsx
··· 2 2 import {Plural} from '@lingui/macro' 3 3 import {useFocusEffect} from '@react-navigation/native' 4 4 5 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 5 + import { 6 + type CommonNavigatorParams, 7 + type NativeStackScreenProps, 8 + } from '#/lib/routes/types' 6 9 import {sanitizeDisplayName} from '#/lib/strings/display-names' 7 10 import {useProfileQuery} from '#/state/queries/profile' 8 11 import {useResolveDidQuery} from '#/state/queries/resolve-uri'
+4 -1
src/screens/Profile/ProfileFollows.tsx
··· 2 2 import {Plural} from '@lingui/macro' 3 3 import {useFocusEffect} from '@react-navigation/native' 4 4 5 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 5 + import { 6 + type CommonNavigatorParams, 7 + type NativeStackScreenProps, 8 + } from '#/lib/routes/types' 6 9 import {sanitizeDisplayName} from '#/lib/strings/display-names' 7 10 import {useProfileQuery} from '#/state/queries/profile' 8 11 import {useResolveDidQuery} from '#/state/queries/resolve-uri'
+4 -1
src/screens/Profile/ProfileLabelerLikedBy.tsx
··· 3 3 import {useLingui} from '@lingui/react' 4 4 import {useFocusEffect} from '@react-navigation/native' 5 5 6 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 6 + import { 7 + type CommonNavigatorParams, 8 + type NativeStackScreenProps, 9 + } from '#/lib/routes/types' 7 10 import {makeRecordUri} from '#/lib/strings/url-helpers' 8 11 import {useSetMinimalShellMode} from '#/state/shell' 9 12 import {ViewHeader} from '#/view/com/util/ViewHeader'
+17 -21
src/screens/Profile/Sections/Feed.tsx
··· 1 - import React from 'react' 1 + import {useCallback, useEffect, useImperativeHandle, useState} from 'react' 2 2 import {findNodeHandle, View} from 'react-native' 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' ··· 18 18 import {type SectionRef} from './types' 19 19 20 20 interface FeedSectionProps { 21 + ref?: React.Ref<SectionRef> 21 22 feed: FeedDescriptor 22 23 headerHeight: number 23 24 isFocused: boolean ··· 25 26 ignoreFilterFor?: string 26 27 setScrollViewTag: (tag: number | null) => void 27 28 } 28 - export const ProfileFeedSection = React.forwardRef< 29 - SectionRef, 30 - FeedSectionProps 31 - >(function FeedSectionImpl( 32 - { 33 - feed, 34 - headerHeight, 35 - isFocused, 36 - scrollElRef, 37 - ignoreFilterFor, 38 - setScrollViewTag, 39 - }, 29 + export function ProfileFeedSection({ 40 30 ref, 41 - ) { 31 + feed, 32 + headerHeight, 33 + isFocused, 34 + scrollElRef, 35 + ignoreFilterFor, 36 + setScrollViewTag, 37 + }: FeedSectionProps) { 42 38 const {_} = useLingui() 43 39 const queryClient = useQueryClient() 44 - const [hasNew, setHasNew] = React.useState(false) 45 - const [isScrolledDown, setIsScrolledDown] = React.useState(false) 40 + const [hasNew, setHasNew] = useState(false) 41 + const [isScrolledDown, setIsScrolledDown] = useState(false) 46 42 const shouldUseAdjustedNumToRender = feed.endsWith('posts_and_author_threads') 47 43 const isVideoFeed = isNative && feed.endsWith('posts_with_video') 48 44 const adjustedInitialNumToRender = useInitialNumToRender({ 49 45 screenHeightOffset: headerHeight, 50 46 }) 51 47 52 - const onScrollToTop = React.useCallback(() => { 48 + const onScrollToTop = useCallback(() => { 53 49 scrollElRef.current?.scrollToOffset({ 54 50 animated: isNative, 55 51 offset: -headerHeight, ··· 58 54 setHasNew(false) 59 55 }, [scrollElRef, headerHeight, queryClient, feed, setHasNew]) 60 56 61 - React.useImperativeHandle(ref, () => ({ 57 + useImperativeHandle(ref, () => ({ 62 58 scrollToTop: onScrollToTop, 63 59 })) 64 60 65 - const renderPostsEmpty = React.useCallback(() => { 61 + const renderPostsEmpty = useCallback(() => { 66 62 return <EmptyState icon="growth" message={_(msg`No posts yet.`)} /> 67 63 }, [_]) 68 64 69 - React.useEffect(() => { 65 + useEffect(() => { 70 66 if (isIOS && isFocused && scrollElRef.current) { 71 67 const nativeTag = findNodeHandle(scrollElRef.current) 72 68 setScrollViewTag(nativeTag) ··· 101 97 )} 102 98 </View> 103 99 ) 104 - }) 100 + } 105 101 106 102 function ProfileEndOfFeed() { 107 103 const t = useTheme()
+1
src/screens/Profile/Sections/Labels.tsx
··· 33 33 isFocused: boolean 34 34 setScrollViewTag: (tag: number | null) => void 35 35 } 36 + 36 37 export function ProfileLabelsSection({ 37 38 ref, 38 39 isLabelerLoading,
+136
src/screens/ProfileList/AboutSection.tsx
··· 1 + import {useCallback, useImperativeHandle, useState} from 'react' 2 + import {View} from 'react-native' 3 + import {type AppBskyGraphDefs} from '@atproto/api' 4 + import {msg, Trans} from '@lingui/macro' 5 + import {useLingui} from '@lingui/react' 6 + 7 + import {isNative} from '#/platform/detection' 8 + import {useSession} from '#/state/session' 9 + import {ListMembers} from '#/view/com/lists/ListMembers' 10 + import {EmptyState} from '#/view/com/util/EmptyState' 11 + import {type ListRef} from '#/view/com/util/List' 12 + import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 13 + import {atoms as a, useBreakpoints} from '#/alf' 14 + import {Button, ButtonIcon, ButtonText} from '#/components/Button' 15 + import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 16 + 17 + interface SectionRef { 18 + scrollToTop: () => void 19 + } 20 + 21 + interface AboutSectionProps { 22 + ref?: React.Ref<SectionRef> 23 + list: AppBskyGraphDefs.ListView 24 + onPressAddUser: () => void 25 + headerHeight: number 26 + scrollElRef: ListRef 27 + } 28 + 29 + export function AboutSection({ 30 + ref, 31 + list, 32 + onPressAddUser, 33 + headerHeight, 34 + scrollElRef, 35 + }: AboutSectionProps) { 36 + const {_} = useLingui() 37 + const {currentAccount} = useSession() 38 + const {gtMobile} = useBreakpoints() 39 + const [isScrolledDown, setIsScrolledDown] = useState(false) 40 + const isOwner = list.creator.did === currentAccount?.did 41 + 42 + const onScrollToTop = useCallback(() => { 43 + scrollElRef.current?.scrollToOffset({ 44 + animated: isNative, 45 + offset: -headerHeight, 46 + }) 47 + }, [scrollElRef, headerHeight]) 48 + 49 + useImperativeHandle(ref, () => ({ 50 + scrollToTop: onScrollToTop, 51 + })) 52 + 53 + const renderHeader = useCallback(() => { 54 + if (!isOwner) { 55 + return <View /> 56 + } 57 + if (!gtMobile) { 58 + return ( 59 + <View style={[a.px_sm, a.py_sm]}> 60 + <Button 61 + testID="addUserBtn" 62 + label={_(msg`Add a user to this list`)} 63 + onPress={onPressAddUser} 64 + color="primary" 65 + size="small" 66 + variant="outline" 67 + style={[a.py_md]}> 68 + <ButtonIcon icon={PersonPlusIcon} /> 69 + <ButtonText> 70 + <Trans>Add people</Trans> 71 + </ButtonText> 72 + </Button> 73 + </View> 74 + ) 75 + } 76 + return ( 77 + <View style={[a.px_lg, a.py_md, a.flex_row_reverse]}> 78 + <Button 79 + testID="addUserBtn" 80 + label={_(msg`Add a user to this list`)} 81 + onPress={onPressAddUser} 82 + color="primary" 83 + size="small" 84 + variant="ghost" 85 + style={[a.py_sm]}> 86 + <ButtonIcon icon={PersonPlusIcon} /> 87 + <ButtonText> 88 + <Trans>Add people</Trans> 89 + </ButtonText> 90 + </Button> 91 + </View> 92 + ) 93 + }, [isOwner, _, onPressAddUser, gtMobile]) 94 + 95 + const renderEmptyState = useCallback(() => { 96 + return ( 97 + <View style={[a.gap_xl, a.align_center]}> 98 + <EmptyState icon="users-slash" message={_(msg`This list is empty.`)} /> 99 + {isOwner && ( 100 + <Button 101 + testID="emptyStateAddUserBtn" 102 + label={_(msg`Start adding people`)} 103 + onPress={onPressAddUser} 104 + color="primary" 105 + size="small"> 106 + <ButtonIcon icon={PersonPlusIcon} /> 107 + <ButtonText> 108 + <Trans>Start adding people!</Trans> 109 + </ButtonText> 110 + </Button> 111 + )} 112 + </View> 113 + ) 114 + }, [_, onPressAddUser, isOwner]) 115 + 116 + return ( 117 + <View> 118 + <ListMembers 119 + testID="listItems" 120 + list={list.uri} 121 + scrollElRef={scrollElRef} 122 + renderHeader={renderHeader} 123 + renderEmptyState={renderEmptyState} 124 + headerOffset={headerHeight} 125 + onScrolledDownChange={setIsScrolledDown} 126 + /> 127 + {isScrolledDown && ( 128 + <LoadLatestBtn 129 + onPress={onScrollToTop} 130 + label={_(msg`Scroll to top`)} 131 + showIndicator={false} 132 + /> 133 + )} 134 + </View> 135 + ) 136 + }
+111
src/screens/ProfileList/FeedSection.tsx
··· 1 + import {useCallback, useEffect, useImperativeHandle, useState} from 'react' 2 + import {View} from 'react-native' 3 + import {msg, Trans} from '@lingui/macro' 4 + import {useLingui} from '@lingui/react' 5 + import {useIsFocused} from '@react-navigation/native' 6 + import {useQueryClient} from '@tanstack/react-query' 7 + 8 + import {isNative} from '#/platform/detection' 9 + import {listenSoftReset} from '#/state/events' 10 + import {type FeedDescriptor} from '#/state/queries/post-feed' 11 + import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' 12 + import {PostFeed} from '#/view/com/posts/PostFeed' 13 + import {EmptyState} from '#/view/com/util/EmptyState' 14 + import {type ListRef} from '#/view/com/util/List' 15 + import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 16 + import {atoms as a} from '#/alf' 17 + import {Button, ButtonIcon, ButtonText} from '#/components/Button' 18 + import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 19 + 20 + interface SectionRef { 21 + scrollToTop: () => void 22 + } 23 + 24 + interface FeedSectionProps { 25 + ref?: React.Ref<SectionRef> 26 + feed: FeedDescriptor 27 + headerHeight: number 28 + scrollElRef: ListRef 29 + isFocused: boolean 30 + isOwner: boolean 31 + onPressAddUser: () => void 32 + } 33 + 34 + export function FeedSection({ 35 + ref, 36 + feed, 37 + scrollElRef, 38 + headerHeight, 39 + isFocused, 40 + isOwner, 41 + onPressAddUser, 42 + }: FeedSectionProps) { 43 + const queryClient = useQueryClient() 44 + const [hasNew, setHasNew] = useState(false) 45 + const [isScrolledDown, setIsScrolledDown] = useState(false) 46 + const isScreenFocused = useIsFocused() 47 + const {_} = useLingui() 48 + 49 + const onScrollToTop = useCallback(() => { 50 + scrollElRef.current?.scrollToOffset({ 51 + animated: isNative, 52 + offset: -headerHeight, 53 + }) 54 + queryClient.resetQueries({queryKey: FEED_RQKEY(feed)}) 55 + setHasNew(false) 56 + }, [scrollElRef, headerHeight, queryClient, feed, setHasNew]) 57 + useImperativeHandle(ref, () => ({ 58 + scrollToTop: onScrollToTop, 59 + })) 60 + 61 + useEffect(() => { 62 + if (!isScreenFocused) { 63 + return 64 + } 65 + return listenSoftReset(onScrollToTop) 66 + }, [onScrollToTop, isScreenFocused]) 67 + 68 + const renderPostsEmpty = useCallback(() => { 69 + return ( 70 + <View style={[a.gap_xl, a.align_center]}> 71 + <EmptyState icon="hashtag" message={_(msg`This feed is empty.`)} /> 72 + {isOwner && ( 73 + <Button 74 + label={_(msg`Start adding people`)} 75 + onPress={onPressAddUser} 76 + color="primary" 77 + size="small"> 78 + <ButtonIcon icon={PersonPlusIcon} /> 79 + <ButtonText> 80 + <Trans>Start adding people!</Trans> 81 + </ButtonText> 82 + </Button> 83 + )} 84 + </View> 85 + ) 86 + }, [_, onPressAddUser, isOwner]) 87 + 88 + return ( 89 + <View> 90 + <PostFeed 91 + testID="listFeed" 92 + enabled={isFocused} 93 + feed={feed} 94 + pollInterval={60e3} 95 + disablePoll={hasNew} 96 + scrollElRef={scrollElRef} 97 + onHasNew={setHasNew} 98 + onScrolledDownChange={setIsScrolledDown} 99 + renderEmptyState={renderPostsEmpty} 100 + headerOffset={headerHeight} 101 + /> 102 + {(isScrolledDown || hasNew) && ( 103 + <LoadLatestBtn 104 + onPress={onScrollToTop} 105 + label={_(msg`Load new posts`)} 106 + showIndicator={hasNew} 107 + /> 108 + )} 109 + </View> 110 + ) 111 + }
+46
src/screens/ProfileList/components/ErrorScreen.tsx
··· 1 + import {View} from 'react-native' 2 + import {msg, Trans} from '@lingui/macro' 3 + import {useLingui} from '@lingui/react' 4 + import {useNavigation} from '@react-navigation/native' 5 + 6 + import {type NavigationProp} from '#/lib/routes/types' 7 + import {atoms as a, useTheme} from '#/alf' 8 + import {Button, ButtonText} from '#/components/Button' 9 + import {Text} from '#/components/Typography' 10 + 11 + export function ErrorScreen({error}: {error: React.ReactNode}) { 12 + const t = useTheme() 13 + const navigation = useNavigation<NavigationProp>() 14 + const {_} = useLingui() 15 + const onPressBack = () => { 16 + if (navigation.canGoBack()) { 17 + navigation.goBack() 18 + } else { 19 + navigation.navigate('Home') 20 + } 21 + } 22 + 23 + return ( 24 + <View style={[a.px_xl, a.py_md, a.gap_md]}> 25 + <Text style={[a.text_4xl, a.font_heavy]}> 26 + <Trans>Could not load list</Trans> 27 + </Text> 28 + <Text style={[a.text_md, t.atoms.text_contrast_high, a.leading_snug]}> 29 + {error} 30 + </Text> 31 + 32 + <View style={[a.flex_row, a.mt_lg]}> 33 + <Button 34 + label={_(msg`Go back`)} 35 + accessibilityHint={_(msg`Returns to previous page`)} 36 + onPress={onPressBack} 37 + size="small" 38 + color="secondary"> 39 + <ButtonText> 40 + <Trans>Go back</Trans> 41 + </ButtonText> 42 + </Button> 43 + </View> 44 + </View> 45 + ) 46 + }
+208
src/screens/ProfileList/components/Header.tsx
··· 1 + import {useMemo} from 'react' 2 + import {View} from 'react-native' 3 + import {AppBskyGraphDefs, RichText as RichTextAPI} from '@atproto/api' 4 + import {msg, Trans} from '@lingui/macro' 5 + import {useLingui} from '@lingui/react' 6 + 7 + import {useHaptics} from '#/lib/haptics' 8 + import {makeListLink} from '#/lib/routes/links' 9 + import {logger} from '#/logger' 10 + import {useListBlockMutation, useListMuteMutation} from '#/state/queries/list' 11 + import { 12 + useAddSavedFeedsMutation, 13 + type UsePreferencesQueryResponse, 14 + useUpdateSavedFeedsMutation, 15 + } from '#/state/queries/preferences' 16 + import {useSession} from '#/state/session' 17 + import {ProfileSubpageHeader} from '#/view/com/profile/ProfileSubpageHeader' 18 + import {atoms as a} from '#/alf' 19 + import {Button, ButtonIcon, ButtonText} from '#/components/Button' 20 + import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin' 21 + import {Loader} from '#/components/Loader' 22 + import {RichText} from '#/components/RichText' 23 + import * as Toast from '#/components/Toast' 24 + import {MoreOptionsMenu} from './MoreOptionsMenu' 25 + import {SubscribeMenu} from './SubscribeMenu' 26 + 27 + export function Header({ 28 + rkey, 29 + list, 30 + preferences, 31 + }: { 32 + rkey: string 33 + list: AppBskyGraphDefs.ListView 34 + preferences: UsePreferencesQueryResponse 35 + }) { 36 + const {_} = useLingui() 37 + const {currentAccount} = useSession() 38 + const isCurateList = list.purpose === AppBskyGraphDefs.CURATELIST 39 + const isModList = list.purpose === AppBskyGraphDefs.MODLIST 40 + const isBlocking = !!list.viewer?.blocked 41 + const isMuting = !!list.viewer?.muted 42 + const playHaptic = useHaptics() 43 + 44 + const {mutateAsync: muteList, isPending: isMutePending} = 45 + useListMuteMutation() 46 + const {mutateAsync: blockList, isPending: isBlockPending} = 47 + useListBlockMutation() 48 + const {mutateAsync: addSavedFeeds, isPending: isAddSavedFeedPending} = 49 + useAddSavedFeedsMutation() 50 + const {mutateAsync: updateSavedFeeds, isPending: isUpdatingSavedFeeds} = 51 + useUpdateSavedFeedsMutation() 52 + 53 + const isPending = isAddSavedFeedPending || isUpdatingSavedFeeds 54 + 55 + const savedFeedConfig = preferences?.savedFeeds?.find( 56 + f => f.value === list.uri, 57 + ) 58 + const isPinned = Boolean(savedFeedConfig?.pinned) 59 + 60 + const onTogglePinned = async () => { 61 + playHaptic() 62 + 63 + try { 64 + if (savedFeedConfig) { 65 + const pinned = !savedFeedConfig.pinned 66 + await updateSavedFeeds([ 67 + { 68 + ...savedFeedConfig, 69 + pinned, 70 + }, 71 + ]) 72 + Toast.show( 73 + pinned 74 + ? _(msg`Pinned to your feeds`) 75 + : _(msg`Unpinned from your feeds`), 76 + ) 77 + } else { 78 + await addSavedFeeds([ 79 + { 80 + type: 'list', 81 + value: list.uri, 82 + pinned: true, 83 + }, 84 + ]) 85 + Toast.show(_(msg`Saved to your feeds`)) 86 + } 87 + } catch (e) { 88 + Toast.show(_(msg`There was an issue contacting the server`), { 89 + type: 'error', 90 + }) 91 + logger.error('Failed to toggle pinned feed', {message: e}) 92 + } 93 + } 94 + 95 + const onUnsubscribeMute = async () => { 96 + try { 97 + await muteList({uri: list.uri, mute: false}) 98 + Toast.show(_(msg({message: 'List unmuted', context: 'toast'}))) 99 + logger.metric( 100 + 'moderation:unsubscribedFromList', 101 + {listType: 'mute'}, 102 + {statsig: true}, 103 + ) 104 + } catch { 105 + Toast.show( 106 + _( 107 + msg`There was an issue. Please check your internet connection and try again.`, 108 + ), 109 + ) 110 + } 111 + } 112 + 113 + const onUnsubscribeBlock = async () => { 114 + try { 115 + await blockList({uri: list.uri, block: false}) 116 + Toast.show(_(msg({message: 'List unblocked', context: 'toast'}))) 117 + logger.metric( 118 + 'moderation:unsubscribedFromList', 119 + {listType: 'block'}, 120 + {statsig: true}, 121 + ) 122 + } catch { 123 + Toast.show( 124 + _( 125 + msg`There was an issue. Please check your internet connection and try again.`, 126 + ), 127 + ) 128 + } 129 + } 130 + 131 + const descriptionRT = useMemo( 132 + () => 133 + list.description 134 + ? new RichTextAPI({ 135 + text: list.description, 136 + facets: list.descriptionFacets, 137 + }) 138 + : undefined, 139 + [list], 140 + ) 141 + 142 + return ( 143 + <> 144 + <ProfileSubpageHeader 145 + href={makeListLink(list.creator.handle || list.creator.did || '', rkey)} 146 + title={list.name} 147 + avatar={list.avatar} 148 + isOwner={list.creator.did === currentAccount?.did} 149 + creator={list.creator} 150 + purpose={list.purpose} 151 + avatarType="list"> 152 + {isCurateList ? ( 153 + <Button 154 + testID={isPinned ? 'unpinBtn' : 'pinBtn'} 155 + color={isPinned ? 'secondary' : 'primary_subtle'} 156 + label={isPinned ? _(msg`Unpin`) : _(msg`Pin to home`)} 157 + onPress={onTogglePinned} 158 + disabled={isPending} 159 + size="small" 160 + style={[a.rounded_full]}> 161 + {!isPinned && <ButtonIcon icon={isPending ? Loader : PinIcon} />} 162 + <ButtonText> 163 + {isPinned ? <Trans>Unpin</Trans> : <Trans>Pin to home</Trans>} 164 + </ButtonText> 165 + </Button> 166 + ) : isModList ? ( 167 + isBlocking ? ( 168 + <Button 169 + testID="unblockBtn" 170 + color="secondary" 171 + label={_(msg`Unblock`)} 172 + onPress={onUnsubscribeBlock} 173 + size="small" 174 + style={[a.rounded_full]} 175 + disabled={isBlockPending}> 176 + {isBlockPending && <ButtonIcon icon={Loader} />} 177 + <ButtonText> 178 + <Trans>Unblock</Trans> 179 + </ButtonText> 180 + </Button> 181 + ) : isMuting ? ( 182 + <Button 183 + testID="unmuteBtn" 184 + color="secondary" 185 + label={_(msg`Unmute`)} 186 + onPress={onUnsubscribeMute} 187 + size="small" 188 + style={[a.rounded_full]} 189 + disabled={isMutePending}> 190 + {isMutePending && <ButtonIcon icon={Loader} />} 191 + <ButtonText> 192 + <Trans>Unmute</Trans> 193 + </ButtonText> 194 + </Button> 195 + ) : ( 196 + <SubscribeMenu list={list} /> 197 + ) 198 + ) : null} 199 + <MoreOptionsMenu list={list} /> 200 + </ProfileSubpageHeader> 201 + {descriptionRT ? ( 202 + <View style={[a.px_lg, a.pt_sm, a.pb_sm, a.gap_md]}> 203 + <RichText value={descriptionRT} style={[a.text_md, a.leading_snug]} /> 204 + </View> 205 + ) : null} 206 + </> 207 + ) 208 + }
+298
src/screens/ProfileList/components/MoreOptionsMenu.tsx
··· 1 + import {type AppBskyActorDefs, AppBskyGraphDefs, AtUri} from '@atproto/api' 2 + import {msg, Trans} from '@lingui/macro' 3 + import {useLingui} from '@lingui/react' 4 + import {useNavigation} from '@react-navigation/native' 5 + 6 + import {type NavigationProp} from '#/lib/routes/types' 7 + import {shareUrl} from '#/lib/sharing' 8 + import {toShareUrl} from '#/lib/strings/url-helpers' 9 + import {logger} from '#/logger' 10 + import {isWeb} from '#/platform/detection' 11 + import {useModalControls} from '#/state/modals' 12 + import { 13 + useListBlockMutation, 14 + useListDeleteMutation, 15 + useListMuteMutation, 16 + } from '#/state/queries/list' 17 + import {useRemoveFeedMutation} from '#/state/queries/preferences' 18 + import {useSession} from '#/state/session' 19 + import {Button, ButtonIcon} from '#/components/Button' 20 + import {useDialogControl} from '#/components/Dialog' 21 + import {ArrowOutOfBoxModified_Stroke2_Corner2_Rounded as ShareIcon} from '#/components/icons/ArrowOutOfBox' 22 + import {ChainLink_Stroke2_Corner0_Rounded as ChainLink} from '#/components/icons/ChainLink' 23 + import {DotGrid_Stroke2_Corner0_Rounded as DotGridIcon} from '#/components/icons/DotGrid' 24 + import {PencilLine_Stroke2_Corner0_Rounded as PencilLineIcon} from '#/components/icons/Pencil' 25 + import {PersonCheck_Stroke2_Corner0_Rounded as PersonCheckIcon} from '#/components/icons/Person' 26 + import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin' 27 + import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker' 28 + import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' 29 + import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' 30 + import * as Menu from '#/components/Menu' 31 + import { 32 + ReportDialog, 33 + useReportDialogControl, 34 + } from '#/components/moderation/ReportDialog' 35 + import * as Prompt from '#/components/Prompt' 36 + import * as Toast from '#/components/Toast' 37 + 38 + export function MoreOptionsMenu({ 39 + list, 40 + savedFeedConfig, 41 + }: { 42 + list: AppBskyGraphDefs.ListView 43 + savedFeedConfig?: AppBskyActorDefs.SavedFeed 44 + }) { 45 + const {_} = useLingui() 46 + const {currentAccount} = useSession() 47 + const {openModal} = useModalControls() 48 + const deleteListPromptControl = useDialogControl() 49 + const reportDialogControl = useReportDialogControl() 50 + const navigation = useNavigation<NavigationProp>() 51 + 52 + const {mutateAsync: removeSavedFeed} = useRemoveFeedMutation() 53 + const {mutateAsync: deleteList} = useListDeleteMutation() 54 + const {mutateAsync: muteList} = useListMuteMutation() 55 + const {mutateAsync: blockList} = useListBlockMutation() 56 + 57 + const isCurateList = list.purpose === AppBskyGraphDefs.CURATELIST 58 + const isModList = list.purpose === AppBskyGraphDefs.MODLIST 59 + const isBlocking = !!list.viewer?.blocked 60 + const isMuting = !!list.viewer?.muted 61 + const isPinned = Boolean(savedFeedConfig?.pinned) 62 + const isOwner = currentAccount?.did === list.creator.did 63 + 64 + const onPressShare = () => { 65 + const {rkey} = new AtUri(list.uri) 66 + const url = toShareUrl(`/profile/${list.creator.did}/lists/${rkey}`) 67 + shareUrl(url) 68 + } 69 + 70 + const onRemoveFromSavedFeeds = async () => { 71 + if (!savedFeedConfig) return 72 + try { 73 + await removeSavedFeed(savedFeedConfig) 74 + Toast.show(_(msg`Removed from your feeds`)) 75 + } catch (e) { 76 + Toast.show(_(msg`There was an issue contacting the server`), { 77 + type: 'error', 78 + }) 79 + logger.error('Failed to remove pinned list', {message: e}) 80 + } 81 + } 82 + 83 + const onPressEdit = () => { 84 + openModal({ 85 + name: 'create-or-edit-list', 86 + list, 87 + }) 88 + } 89 + 90 + const onPressDelete = async () => { 91 + await deleteList({uri: list.uri}) 92 + 93 + if (savedFeedConfig) { 94 + await removeSavedFeed(savedFeedConfig) 95 + } 96 + 97 + Toast.show(_(msg({message: 'List deleted', context: 'toast'}))) 98 + if (navigation.canGoBack()) { 99 + navigation.goBack() 100 + } else { 101 + navigation.navigate('Home') 102 + } 103 + } 104 + 105 + const onUnpinModList = async () => { 106 + try { 107 + if (!savedFeedConfig) return 108 + await removeSavedFeed(savedFeedConfig) 109 + Toast.show(_(msg`Unpinned list`)) 110 + } catch { 111 + Toast.show(_(msg`Failed to unpin list`), { 112 + type: 'error', 113 + }) 114 + } 115 + } 116 + 117 + const onUnsubscribeMute = async () => { 118 + try { 119 + await muteList({uri: list.uri, mute: false}) 120 + Toast.show(_(msg({message: 'List unmuted', context: 'toast'}))) 121 + logger.metric( 122 + 'moderation:unsubscribedFromList', 123 + {listType: 'mute'}, 124 + {statsig: true}, 125 + ) 126 + } catch { 127 + Toast.show( 128 + _( 129 + msg`There was an issue. Please check your internet connection and try again.`, 130 + ), 131 + ) 132 + } 133 + } 134 + 135 + const onUnsubscribeBlock = async () => { 136 + try { 137 + await blockList({uri: list.uri, block: false}) 138 + Toast.show(_(msg({message: 'List unblocked', context: 'toast'}))) 139 + logger.metric( 140 + 'moderation:unsubscribedFromList', 141 + {listType: 'block'}, 142 + {statsig: true}, 143 + ) 144 + } catch { 145 + Toast.show( 146 + _( 147 + msg`There was an issue. Please check your internet connection and try again.`, 148 + ), 149 + ) 150 + } 151 + } 152 + 153 + return ( 154 + <> 155 + <Menu.Root> 156 + <Menu.Trigger label={_(msg`More options`)}> 157 + {({props}) => ( 158 + <Button 159 + label={props.accessibilityLabel} 160 + testID="moreOptionsBtn" 161 + size="small" 162 + color="secondary" 163 + shape="round" 164 + {...props}> 165 + <ButtonIcon icon={DotGridIcon} /> 166 + </Button> 167 + )} 168 + </Menu.Trigger> 169 + <Menu.Outer> 170 + <Menu.Group> 171 + <Menu.Item 172 + label={isWeb ? _(msg`Copy link to list`) : _(msg`Share via...`)} 173 + onPress={onPressShare}> 174 + <Menu.ItemText> 175 + {isWeb ? ( 176 + <Trans>Copy link to list</Trans> 177 + ) : ( 178 + <Trans>Share via...</Trans> 179 + )} 180 + </Menu.ItemText> 181 + <Menu.ItemIcon 182 + position="right" 183 + icon={isWeb ? ChainLink : ShareIcon} 184 + /> 185 + </Menu.Item> 186 + {savedFeedConfig && ( 187 + <Menu.Item 188 + label={_(msg`Remove from my feeds`)} 189 + onPress={onRemoveFromSavedFeeds}> 190 + <Menu.ItemText> 191 + <Trans>Remove from my feeds</Trans> 192 + </Menu.ItemText> 193 + <Menu.ItemIcon position="right" icon={TrashIcon} /> 194 + </Menu.Item> 195 + )} 196 + </Menu.Group> 197 + 198 + <Menu.Divider /> 199 + 200 + {isOwner ? ( 201 + <Menu.Group> 202 + <Menu.Item 203 + label={_(msg`Edit list details`)} 204 + onPress={onPressEdit}> 205 + <Menu.ItemText> 206 + <Trans>Edit list details</Trans> 207 + </Menu.ItemText> 208 + <Menu.ItemIcon position="right" icon={PencilLineIcon} /> 209 + </Menu.Item> 210 + <Menu.Item 211 + label={_(msg`Delete list`)} 212 + onPress={deleteListPromptControl.open}> 213 + <Menu.ItemText> 214 + <Trans>Delete list</Trans> 215 + </Menu.ItemText> 216 + <Menu.ItemIcon position="right" icon={TrashIcon} /> 217 + </Menu.Item> 218 + </Menu.Group> 219 + ) : ( 220 + <Menu.Group> 221 + <Menu.Item 222 + label={_(msg`Report list`)} 223 + onPress={reportDialogControl.open}> 224 + <Menu.ItemText> 225 + <Trans>Report list</Trans> 226 + </Menu.ItemText> 227 + <Menu.ItemIcon position="right" icon={WarningIcon} /> 228 + </Menu.Item> 229 + </Menu.Group> 230 + )} 231 + 232 + {isModList && isPinned && ( 233 + <> 234 + <Menu.Divider /> 235 + <Menu.Group> 236 + <Menu.Item 237 + label={_(msg`Unpin moderation list`)} 238 + onPress={onUnpinModList}> 239 + <Menu.ItemText> 240 + <Trans>Unpin moderation list</Trans> 241 + </Menu.ItemText> 242 + <Menu.ItemIcon icon={PinIcon} /> 243 + </Menu.Item> 244 + </Menu.Group> 245 + </> 246 + )} 247 + 248 + {isCurateList && (isBlocking || isMuting) && ( 249 + <> 250 + <Menu.Divider /> 251 + <Menu.Group> 252 + {isBlocking && ( 253 + <Menu.Item 254 + label={_(msg`Unblock list`)} 255 + onPress={onUnsubscribeBlock}> 256 + <Menu.ItemText> 257 + <Trans>Unblock list</Trans> 258 + </Menu.ItemText> 259 + <Menu.ItemIcon icon={PersonCheckIcon} /> 260 + </Menu.Item> 261 + )} 262 + {isMuting && ( 263 + <Menu.Item 264 + label={_(msg`Unmute list`)} 265 + onPress={onUnsubscribeMute}> 266 + <Menu.ItemText> 267 + <Trans>Unmute list</Trans> 268 + </Menu.ItemText> 269 + <Menu.ItemIcon icon={UnmuteIcon} /> 270 + </Menu.Item> 271 + )} 272 + </Menu.Group> 273 + </> 274 + )} 275 + </Menu.Outer> 276 + </Menu.Root> 277 + 278 + <Prompt.Basic 279 + control={deleteListPromptControl} 280 + title={_(msg`Delete this list?`)} 281 + description={_( 282 + msg`If you delete this list, you won't be able to recover it.`, 283 + )} 284 + onConfirm={onPressDelete} 285 + confirmButtonCta={_(msg`Delete`)} 286 + confirmButtonColor="negative" 287 + /> 288 + 289 + <ReportDialog 290 + control={reportDialogControl} 291 + subject={{ 292 + ...list, 293 + $type: 'app.bsky.graph.defs#listView', 294 + }} 295 + /> 296 + </> 297 + ) 298 + }
+130
src/screens/ProfileList/components/SubscribeMenu.tsx
··· 1 + import {type AppBskyGraphDefs} from '@atproto/api' 2 + import {msg, Trans} from '@lingui/macro' 3 + import {useLingui} from '@lingui/react' 4 + 5 + import {logger} from '#/logger' 6 + import {useListBlockMutation, useListMuteMutation} from '#/state/queries/list' 7 + import {atoms as a} from '#/alf' 8 + import {Button, ButtonIcon, ButtonText} from '#/components/Button' 9 + import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' 10 + import {PersonX_Stroke2_Corner0_Rounded as PersonXIcon} from '#/components/icons/Person' 11 + import {Loader} from '#/components/Loader' 12 + import * as Menu from '#/components/Menu' 13 + import * as Prompt from '#/components/Prompt' 14 + import * as Toast from '#/components/Toast' 15 + 16 + export function SubscribeMenu({list}: {list: AppBskyGraphDefs.ListView}) { 17 + const {_} = useLingui() 18 + const subscribeMutePromptControl = Prompt.usePromptControl() 19 + const subscribeBlockPromptControl = Prompt.usePromptControl() 20 + 21 + const {mutateAsync: muteList, isPending: isMutePending} = 22 + useListMuteMutation() 23 + const {mutateAsync: blockList, isPending: isBlockPending} = 24 + useListBlockMutation() 25 + 26 + const isPending = isMutePending || isBlockPending 27 + 28 + const onSubscribeMute = async () => { 29 + try { 30 + await muteList({uri: list.uri, mute: true}) 31 + Toast.show(_(msg({message: 'List muted', context: 'toast'}))) 32 + logger.metric( 33 + 'moderation:subscribedToList', 34 + {listType: 'mute'}, 35 + {statsig: true}, 36 + ) 37 + } catch { 38 + Toast.show( 39 + _( 40 + msg`There was an issue. Please check your internet connection and try again.`, 41 + ), 42 + {type: 'error'}, 43 + ) 44 + } 45 + } 46 + 47 + const onSubscribeBlock = async () => { 48 + try { 49 + await blockList({uri: list.uri, block: true}) 50 + Toast.show(_(msg({message: 'List blocked', context: 'toast'}))) 51 + logger.metric( 52 + 'moderation:subscribedToList', 53 + {listType: 'block'}, 54 + {statsig: true}, 55 + ) 56 + } catch { 57 + Toast.show( 58 + _( 59 + msg`There was an issue. Please check your internet connection and try again.`, 60 + ), 61 + {type: 'error'}, 62 + ) 63 + } 64 + } 65 + 66 + return ( 67 + <> 68 + <Menu.Root> 69 + <Menu.Trigger label={_(msg`Subscribe to this list`)}> 70 + {({props}) => ( 71 + <Button 72 + label={props.accessibilityLabel} 73 + testID="subscribeBtn" 74 + size="small" 75 + color="primary_subtle" 76 + style={[a.rounded_full]} 77 + disabled={isPending} 78 + {...props}> 79 + {isPending && <ButtonIcon icon={Loader} />} 80 + <ButtonText> 81 + <Trans>Subscribe</Trans> 82 + </ButtonText> 83 + </Button> 84 + )} 85 + </Menu.Trigger> 86 + <Menu.Outer showCancel> 87 + <Menu.Group> 88 + <Menu.Item 89 + label={_(msg`Mute accounts`)} 90 + onPress={subscribeMutePromptControl.open}> 91 + <Menu.ItemText> 92 + <Trans>Mute accounts</Trans> 93 + </Menu.ItemText> 94 + <Menu.ItemIcon position="right" icon={MuteIcon} /> 95 + </Menu.Item> 96 + <Menu.Item 97 + label={_(msg`Block accounts`)} 98 + onPress={subscribeBlockPromptControl.open}> 99 + <Menu.ItemText> 100 + <Trans>Block accounts</Trans> 101 + </Menu.ItemText> 102 + <Menu.ItemIcon position="right" icon={PersonXIcon} /> 103 + </Menu.Item> 104 + </Menu.Group> 105 + </Menu.Outer> 106 + </Menu.Root> 107 + 108 + <Prompt.Basic 109 + control={subscribeMutePromptControl} 110 + title={_(msg`Mute these accounts?`)} 111 + description={_( 112 + msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`, 113 + )} 114 + onConfirm={onSubscribeMute} 115 + confirmButtonCta={_(msg`Mute list`)} 116 + /> 117 + 118 + <Prompt.Basic 119 + control={subscribeBlockPromptControl} 120 + title={_(msg`Block these accounts?`)} 121 + description={_( 122 + msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`, 123 + )} 124 + onConfirm={onSubscribeBlock} 125 + confirmButtonCta={_(msg`Block list`)} 126 + confirmButtonColor="negative" 127 + /> 128 + </> 129 + ) 130 + }
+296
src/screens/ProfileList/index.tsx
··· 1 + import {useCallback, useMemo, useRef} from 'react' 2 + import {View} from 'react-native' 3 + import {useAnimatedRef} from 'react-native-reanimated' 4 + import { 5 + AppBskyGraphDefs, 6 + AtUri, 7 + moderateUserList, 8 + type ModerationOpts, 9 + } from '@atproto/api' 10 + import {msg, Trans} from '@lingui/macro' 11 + import {useLingui} from '@lingui/react' 12 + import {useFocusEffect, useIsFocused} from '@react-navigation/native' 13 + import {useQueryClient} from '@tanstack/react-query' 14 + 15 + import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 16 + import {useSetTitle} from '#/lib/hooks/useSetTitle' 17 + import {ComposeIcon2} from '#/lib/icons' 18 + import { 19 + type CommonNavigatorParams, 20 + type NativeStackScreenProps, 21 + } from '#/lib/routes/types' 22 + import {cleanError} from '#/lib/strings/errors' 23 + import {useModerationOpts} from '#/state/preferences/moderation-opts' 24 + import {useListQuery} from '#/state/queries/list' 25 + import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' 26 + import { 27 + usePreferencesQuery, 28 + type UsePreferencesQueryResponse, 29 + } from '#/state/queries/preferences' 30 + import {useResolveUriQuery} from '#/state/queries/resolve-uri' 31 + import {truncateAndInvalidate} from '#/state/queries/util' 32 + import {useSession} from '#/state/session' 33 + import {useSetMinimalShellMode} from '#/state/shell' 34 + import {PagerWithHeader} from '#/view/com/pager/PagerWithHeader' 35 + import {FAB} from '#/view/com/util/fab/FAB' 36 + import {type ListRef} from '#/view/com/util/List' 37 + import {ListHiddenScreen} from '#/screens/List/ListHiddenScreen' 38 + import {atoms as a, platform} from '#/alf' 39 + import {useDialogControl} from '#/components/Dialog' 40 + import {ListAddRemoveUsersDialog} from '#/components/dialogs/lists/ListAddRemoveUsersDialog' 41 + import * as Layout from '#/components/Layout' 42 + import {Loader} from '#/components/Loader' 43 + import * as Hider from '#/components/moderation/Hider' 44 + import {AboutSection} from './AboutSection' 45 + import {ErrorScreen} from './components/ErrorScreen' 46 + import {Header} from './components/Header' 47 + import {FeedSection} from './FeedSection' 48 + 49 + interface SectionRef { 50 + scrollToTop: () => void 51 + } 52 + 53 + type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileList'> 54 + export function ProfileListScreen(props: Props) { 55 + return ( 56 + <Layout.Screen testID="profileListScreen"> 57 + <ProfileListScreenInner {...props} /> 58 + </Layout.Screen> 59 + ) 60 + } 61 + 62 + function ProfileListScreenInner(props: Props) { 63 + const {_} = useLingui() 64 + const {name: handleOrDid, rkey} = props.route.params 65 + const {data: resolvedUri, error: resolveError} = useResolveUriQuery( 66 + AtUri.make(handleOrDid, 'app.bsky.graph.list', rkey).toString(), 67 + ) 68 + const {data: preferences} = usePreferencesQuery() 69 + const {data: list, error: listError} = useListQuery(resolvedUri?.uri) 70 + const moderationOpts = useModerationOpts() 71 + 72 + if (resolveError) { 73 + return ( 74 + <> 75 + <Layout.Header.Outer> 76 + <Layout.Header.BackButton /> 77 + <Layout.Header.Content> 78 + <Layout.Header.TitleText> 79 + <Trans>Could not load list</Trans> 80 + </Layout.Header.TitleText> 81 + </Layout.Header.Content> 82 + <Layout.Header.Slot /> 83 + </Layout.Header.Outer> 84 + <Layout.Content centerContent> 85 + <ErrorScreen 86 + error={_( 87 + msg`We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @${handleOrDid}.`, 88 + )} 89 + /> 90 + </Layout.Content> 91 + </> 92 + ) 93 + } 94 + if (listError) { 95 + return ( 96 + <> 97 + <Layout.Header.Outer> 98 + <Layout.Header.BackButton /> 99 + <Layout.Header.Content> 100 + <Layout.Header.TitleText> 101 + <Trans>Could not load list</Trans> 102 + </Layout.Header.TitleText> 103 + </Layout.Header.Content> 104 + <Layout.Header.Slot /> 105 + </Layout.Header.Outer> 106 + <Layout.Content centerContent> 107 + <ErrorScreen error={cleanError(listError)} /> 108 + </Layout.Content> 109 + </> 110 + ) 111 + } 112 + 113 + return resolvedUri && list && moderationOpts && preferences ? ( 114 + <ProfileListScreenLoaded 115 + {...props} 116 + uri={resolvedUri.uri} 117 + list={list} 118 + moderationOpts={moderationOpts} 119 + preferences={preferences} 120 + /> 121 + ) : ( 122 + <> 123 + <Layout.Header.Outer> 124 + <Layout.Header.BackButton /> 125 + <Layout.Header.Content /> 126 + <Layout.Header.Slot /> 127 + </Layout.Header.Outer> 128 + <Layout.Content 129 + centerContent 130 + contentContainerStyle={platform({ 131 + web: [a.mx_auto], 132 + native: [a.align_center], 133 + })}> 134 + <Loader size="2xl" /> 135 + </Layout.Content> 136 + </> 137 + ) 138 + } 139 + 140 + function ProfileListScreenLoaded({ 141 + route, 142 + uri, 143 + list, 144 + moderationOpts, 145 + preferences, 146 + }: Props & { 147 + uri: string 148 + list: AppBskyGraphDefs.ListView 149 + moderationOpts: ModerationOpts 150 + preferences: UsePreferencesQueryResponse 151 + }) { 152 + const {_} = useLingui() 153 + const queryClient = useQueryClient() 154 + const {openComposer} = useOpenComposer() 155 + const setMinimalShellMode = useSetMinimalShellMode() 156 + const {currentAccount} = useSession() 157 + const {rkey} = route.params 158 + const feedSectionRef = useRef<SectionRef>(null) 159 + const aboutSectionRef = useRef<SectionRef>(null) 160 + const isCurateList = list.purpose === AppBskyGraphDefs.CURATELIST 161 + const isScreenFocused = useIsFocused() 162 + const isHidden = list.labels?.findIndex(l => l.val === '!hide') !== -1 163 + const isOwner = currentAccount?.did === list.creator.did 164 + const scrollElRef = useAnimatedRef() 165 + const addUserDialogControl = useDialogControl() 166 + const sectionTitlesCurate = [_(msg`Posts`), _(msg`People`)] 167 + 168 + const moderation = useMemo(() => { 169 + return moderateUserList(list, moderationOpts) 170 + }, [list, moderationOpts]) 171 + 172 + useSetTitle(isHidden ? _(msg`List Hidden`) : list.name) 173 + 174 + useFocusEffect( 175 + useCallback(() => { 176 + setMinimalShellMode(false) 177 + }, [setMinimalShellMode]), 178 + ) 179 + 180 + const onChangeMembers = () => { 181 + if (isCurateList) { 182 + truncateAndInvalidate(queryClient, FEED_RQKEY(`list|${list.uri}`)) 183 + } 184 + } 185 + 186 + const onCurrentPageSelected = useCallback( 187 + (index: number) => { 188 + if (index === 0) { 189 + feedSectionRef.current?.scrollToTop() 190 + } else if (index === 1) { 191 + aboutSectionRef.current?.scrollToTop() 192 + } 193 + }, 194 + [feedSectionRef], 195 + ) 196 + 197 + const renderHeader = useCallback(() => { 198 + return <Header rkey={rkey} list={list} preferences={preferences} /> 199 + }, [rkey, list, preferences]) 200 + 201 + if (isCurateList) { 202 + return ( 203 + <Hider.Outer modui={moderation.ui('contentView')} allowOverride={isOwner}> 204 + <Hider.Mask> 205 + <ListHiddenScreen list={list} preferences={preferences} /> 206 + </Hider.Mask> 207 + <Hider.Content> 208 + <View style={[a.util_screen_outer]}> 209 + <PagerWithHeader 210 + items={sectionTitlesCurate} 211 + isHeaderReady={true} 212 + renderHeader={renderHeader} 213 + onCurrentPageSelected={onCurrentPageSelected}> 214 + {({headerHeight, scrollElRef, isFocused}) => ( 215 + <FeedSection 216 + ref={feedSectionRef} 217 + feed={`list|${uri}`} 218 + scrollElRef={scrollElRef as ListRef} 219 + headerHeight={headerHeight} 220 + isFocused={isScreenFocused && isFocused} 221 + isOwner={isOwner} 222 + onPressAddUser={addUserDialogControl.open} 223 + /> 224 + )} 225 + {({headerHeight, scrollElRef}) => ( 226 + <AboutSection 227 + ref={aboutSectionRef} 228 + scrollElRef={scrollElRef as ListRef} 229 + list={list} 230 + onPressAddUser={addUserDialogControl.open} 231 + headerHeight={headerHeight} 232 + /> 233 + )} 234 + </PagerWithHeader> 235 + <FAB 236 + testID="composeFAB" 237 + onPress={() => openComposer({})} 238 + icon={ 239 + <ComposeIcon2 240 + strokeWidth={1.5} 241 + size={29} 242 + style={{color: 'white'}} 243 + /> 244 + } 245 + accessibilityRole="button" 246 + accessibilityLabel={_(msg`New post`)} 247 + accessibilityHint="" 248 + /> 249 + </View> 250 + <ListAddRemoveUsersDialog 251 + control={addUserDialogControl} 252 + list={list} 253 + onChange={onChangeMembers} 254 + /> 255 + </Hider.Content> 256 + </Hider.Outer> 257 + ) 258 + } 259 + return ( 260 + <Hider.Outer modui={moderation.ui('contentView')} allowOverride={isOwner}> 261 + <Hider.Mask> 262 + <ListHiddenScreen list={list} preferences={preferences} /> 263 + </Hider.Mask> 264 + <Hider.Content> 265 + <View style={[a.util_screen_outer]}> 266 + <Layout.Center>{renderHeader()}</Layout.Center> 267 + <AboutSection 268 + list={list} 269 + scrollElRef={scrollElRef as ListRef} 270 + onPressAddUser={addUserDialogControl.open} 271 + headerHeight={0} 272 + /> 273 + <FAB 274 + testID="composeFAB" 275 + onPress={() => openComposer({})} 276 + icon={ 277 + <ComposeIcon2 278 + strokeWidth={1.5} 279 + size={29} 280 + style={{color: 'white'}} 281 + /> 282 + } 283 + accessibilityRole="button" 284 + accessibilityLabel={_(msg`New post`)} 285 + accessibilityHint="" 286 + /> 287 + </View> 288 + <ListAddRemoveUsersDialog 289 + control={addUserDialogControl} 290 + list={list} 291 + onChange={onChangeMembers} 292 + /> 293 + </Hider.Content> 294 + </Hider.Outer> 295 + ) 296 + }
+415
src/screens/SavedFeeds.tsx
··· 1 + import {useCallback, useState} from 'react' 2 + import {View} from 'react-native' 3 + import Animated, {LinearTransition} from 'react-native-reanimated' 4 + import {type AppBskyActorDefs} from '@atproto/api' 5 + import {TID} from '@atproto/common-web' 6 + import {msg, Trans} from '@lingui/macro' 7 + import {useLingui} from '@lingui/react' 8 + import {useFocusEffect} from '@react-navigation/native' 9 + import {useNavigation} from '@react-navigation/native' 10 + import {type NativeStackScreenProps} from '@react-navigation/native-stack' 11 + 12 + import {RECOMMENDED_SAVED_FEEDS, TIMELINE_SAVED_FEED} from '#/lib/constants' 13 + import {useHaptics} from '#/lib/haptics' 14 + import { 15 + type CommonNavigatorParams, 16 + type NavigationProp, 17 + } from '#/lib/routes/types' 18 + import {logger} from '#/logger' 19 + import { 20 + useOverwriteSavedFeedsMutation, 21 + usePreferencesQuery, 22 + } from '#/state/queries/preferences' 23 + import {type UsePreferencesQueryResponse} from '#/state/queries/preferences/types' 24 + import {useSetMinimalShellMode} from '#/state/shell' 25 + import {FeedSourceCard} from '#/view/com/feeds/FeedSourceCard' 26 + import * as Toast from '#/view/com/util/Toast' 27 + import {NoFollowingFeed} from '#/screens/Feeds/NoFollowingFeed' 28 + import {NoSavedFeedsOfAnyType} from '#/screens/Feeds/NoSavedFeedsOfAnyType' 29 + import {atoms as a, useBreakpoints, useTheme} from '#/alf' 30 + import {Admonition} from '#/components/Admonition' 31 + import {Button, ButtonIcon, ButtonText} from '#/components/Button' 32 + import { 33 + ArrowBottom_Stroke2_Corner0_Rounded as ArrowDownIcon, 34 + ArrowTop_Stroke2_Corner0_Rounded as ArrowUpIcon, 35 + } from '#/components/icons/Arrow' 36 + import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline' 37 + import {FloppyDisk_Stroke2_Corner0_Rounded as SaveIcon} from '#/components/icons/FloppyDisk' 38 + import {Pin_Filled_Corner0_Rounded as PinIcon} from '#/components/icons/Pin' 39 + import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' 40 + import * as Layout from '#/components/Layout' 41 + import {InlineLinkText} from '#/components/Link' 42 + import {Loader} from '#/components/Loader' 43 + import {Text} from '#/components/Typography' 44 + 45 + type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'> 46 + export function SavedFeeds({}: Props) { 47 + const {data: preferences} = usePreferencesQuery() 48 + if (!preferences) { 49 + return <View /> 50 + } 51 + return <SavedFeedsInner preferences={preferences} /> 52 + } 53 + 54 + function SavedFeedsInner({ 55 + preferences, 56 + }: { 57 + preferences: UsePreferencesQueryResponse 58 + }) { 59 + const t = useTheme() 60 + const {_} = useLingui() 61 + const {gtMobile} = useBreakpoints() 62 + const setMinimalShellMode = useSetMinimalShellMode() 63 + const {mutateAsync: overwriteSavedFeeds, isPending: isOverwritePending} = 64 + useOverwriteSavedFeedsMutation() 65 + const navigation = useNavigation<NavigationProp>() 66 + 67 + /* 68 + * Use optimistic data if exists and no error, otherwise fallback to remote 69 + * data 70 + */ 71 + const [currentFeeds, setCurrentFeeds] = useState( 72 + () => preferences.savedFeeds || [], 73 + ) 74 + const hasUnsavedChanges = currentFeeds !== preferences.savedFeeds 75 + const pinnedFeeds = currentFeeds.filter(f => f.pinned) 76 + const unpinnedFeeds = currentFeeds.filter(f => !f.pinned) 77 + const noSavedFeedsOfAnyType = pinnedFeeds.length + unpinnedFeeds.length === 0 78 + const noFollowingFeed = 79 + currentFeeds.every(f => f.type !== 'timeline') && !noSavedFeedsOfAnyType 80 + 81 + useFocusEffect( 82 + useCallback(() => { 83 + setMinimalShellMode(false) 84 + }, [setMinimalShellMode]), 85 + ) 86 + 87 + const onSaveChanges = async () => { 88 + try { 89 + await overwriteSavedFeeds(currentFeeds) 90 + Toast.show(_(msg({message: 'Feeds updated!', context: 'toast'}))) 91 + if (navigation.canGoBack()) { 92 + navigation.goBack() 93 + } else { 94 + navigation.navigate('Feeds') 95 + } 96 + } catch (e) { 97 + Toast.show(_(msg`There was an issue contacting the server`), 'xmark') 98 + logger.error('Failed to toggle pinned feed', {message: e}) 99 + } 100 + } 101 + 102 + return ( 103 + <Layout.Screen> 104 + <Layout.Header.Outer> 105 + <Layout.Header.BackButton /> 106 + <Layout.Header.Content align="left"> 107 + <Layout.Header.TitleText> 108 + <Trans>Feeds</Trans> 109 + </Layout.Header.TitleText> 110 + </Layout.Header.Content> 111 + <Button 112 + testID="saveChangesBtn" 113 + size="small" 114 + color={hasUnsavedChanges ? 'primary' : 'secondary'} 115 + onPress={onSaveChanges} 116 + label={_(msg`Save changes`)} 117 + disabled={isOverwritePending || !hasUnsavedChanges}> 118 + <ButtonIcon icon={isOverwritePending ? Loader : SaveIcon} /> 119 + <ButtonText> 120 + {gtMobile ? <Trans>Save changes</Trans> : <Trans>Save</Trans>} 121 + </ButtonText> 122 + </Button> 123 + </Layout.Header.Outer> 124 + 125 + <Layout.Content> 126 + {noSavedFeedsOfAnyType && ( 127 + <View style={[t.atoms.border_contrast_low, a.border_b]}> 128 + <NoSavedFeedsOfAnyType 129 + onAddRecommendedFeeds={() => 130 + setCurrentFeeds( 131 + RECOMMENDED_SAVED_FEEDS.map(f => ({ 132 + ...f, 133 + id: TID.nextStr(), 134 + })), 135 + ) 136 + } 137 + /> 138 + </View> 139 + )} 140 + 141 + <SectionHeaderText> 142 + <Trans>Pinned Feeds</Trans> 143 + </SectionHeaderText> 144 + 145 + {preferences ? ( 146 + !pinnedFeeds.length ? ( 147 + <View style={[a.flex_1, a.p_lg]}> 148 + <Admonition type="info"> 149 + <Trans>You don't have any pinned feeds.</Trans> 150 + </Admonition> 151 + </View> 152 + ) : ( 153 + pinnedFeeds.map(f => ( 154 + <ListItem 155 + key={f.id} 156 + feed={f} 157 + isPinned 158 + currentFeeds={currentFeeds} 159 + setCurrentFeeds={setCurrentFeeds} 160 + preferences={preferences} 161 + /> 162 + )) 163 + ) 164 + ) : ( 165 + <View style={[a.w_full, a.py_2xl, a.align_center]}> 166 + <Loader size="xl" /> 167 + </View> 168 + )} 169 + 170 + {noFollowingFeed && ( 171 + <View style={[t.atoms.border_contrast_low, a.border_b]}> 172 + <NoFollowingFeed 173 + onAddFeed={() => 174 + setCurrentFeeds(feeds => [ 175 + ...feeds, 176 + {...TIMELINE_SAVED_FEED, id: TID.next().toString()}, 177 + ]) 178 + } 179 + /> 180 + </View> 181 + )} 182 + 183 + <SectionHeaderText> 184 + <Trans>Saved Feeds</Trans> 185 + </SectionHeaderText> 186 + 187 + {preferences ? ( 188 + !unpinnedFeeds.length ? ( 189 + <View style={[a.flex_1, a.p_lg]}> 190 + <Admonition type="info"> 191 + <Trans>You don't have any saved feeds.</Trans> 192 + </Admonition> 193 + </View> 194 + ) : ( 195 + unpinnedFeeds.map(f => ( 196 + <ListItem 197 + key={f.id} 198 + feed={f} 199 + isPinned={false} 200 + currentFeeds={currentFeeds} 201 + setCurrentFeeds={setCurrentFeeds} 202 + preferences={preferences} 203 + /> 204 + )) 205 + ) 206 + ) : ( 207 + <View style={[a.w_full, a.py_2xl, a.align_center]}> 208 + <Loader size="xl" /> 209 + </View> 210 + )} 211 + 212 + <View style={[a.px_lg, a.py_xl]}> 213 + <Text 214 + style={[a.text_sm, t.atoms.text_contrast_medium, a.leading_snug]}> 215 + <Trans> 216 + Feeds are custom algorithms that users build with a little coding 217 + expertise.{' '} 218 + <InlineLinkText 219 + to="https://github.com/bluesky-social/feed-generator" 220 + label={_(msg`See this guide`)} 221 + disableMismatchWarning 222 + style={[a.leading_snug]}> 223 + See this guide 224 + </InlineLinkText>{' '} 225 + for more information. 226 + </Trans> 227 + </Text> 228 + </View> 229 + </Layout.Content> 230 + </Layout.Screen> 231 + ) 232 + } 233 + 234 + function ListItem({ 235 + feed, 236 + isPinned, 237 + currentFeeds, 238 + setCurrentFeeds, 239 + }: { 240 + feed: AppBskyActorDefs.SavedFeed 241 + isPinned: boolean 242 + currentFeeds: AppBskyActorDefs.SavedFeed[] 243 + setCurrentFeeds: React.Dispatch<AppBskyActorDefs.SavedFeed[]> 244 + preferences: UsePreferencesQueryResponse 245 + }) { 246 + const {_} = useLingui() 247 + const t = useTheme() 248 + const playHaptic = useHaptics() 249 + const feedUri = feed.value 250 + 251 + const onTogglePinned = async () => { 252 + playHaptic() 253 + setCurrentFeeds( 254 + currentFeeds.map(f => 255 + f.id === feed.id ? {...feed, pinned: !feed.pinned} : f, 256 + ), 257 + ) 258 + } 259 + 260 + const onPressUp = async () => { 261 + if (!isPinned) return 262 + 263 + const nextFeeds = currentFeeds.slice() 264 + const ids = currentFeeds.map(f => f.id) 265 + const index = ids.indexOf(feed.id) 266 + const nextIndex = index - 1 267 + 268 + if (index === -1 || index === 0) return 269 + ;[nextFeeds[index], nextFeeds[nextIndex]] = [ 270 + nextFeeds[nextIndex], 271 + nextFeeds[index], 272 + ] 273 + 274 + setCurrentFeeds(nextFeeds) 275 + } 276 + 277 + const onPressDown = async () => { 278 + if (!isPinned) return 279 + 280 + const nextFeeds = currentFeeds.slice() 281 + const ids = currentFeeds.map(f => f.id) 282 + const index = ids.indexOf(feed.id) 283 + const nextIndex = index + 1 284 + 285 + if (index === -1 || index >= nextFeeds.filter(f => f.pinned).length - 1) 286 + return 287 + ;[nextFeeds[index], nextFeeds[nextIndex]] = [ 288 + nextFeeds[nextIndex], 289 + nextFeeds[index], 290 + ] 291 + 292 + setCurrentFeeds(nextFeeds) 293 + } 294 + 295 + const onPressRemove = async () => { 296 + playHaptic() 297 + setCurrentFeeds(currentFeeds.filter(f => f.id !== feed.id)) 298 + } 299 + 300 + return ( 301 + <Animated.View 302 + style={[a.flex_row, a.border_b, t.atoms.border_contrast_low]} 303 + layout={LinearTransition.duration(100)}> 304 + {feed.type === 'timeline' ? ( 305 + <FollowingFeedCard /> 306 + ) : ( 307 + <FeedSourceCard 308 + key={feedUri} 309 + feedUri={feedUri} 310 + style={[isPinned && a.pr_sm]} 311 + showMinimalPlaceholder 312 + hideTopBorder={true} 313 + /> 314 + )} 315 + <View style={[a.pr_lg, a.flex_row, a.align_center, a.gap_sm]}> 316 + {isPinned ? ( 317 + <> 318 + <Button 319 + testID={`feed-${feed.type}-moveUp`} 320 + label={_(msg`Move feed up`)} 321 + onPress={onPressUp} 322 + size="small" 323 + color="secondary" 324 + shape="square"> 325 + <ButtonIcon icon={ArrowUpIcon} /> 326 + </Button> 327 + <Button 328 + testID={`feed-${feed.type}-moveDown`} 329 + label={_(msg`Move feed down`)} 330 + onPress={onPressDown} 331 + size="small" 332 + color="secondary" 333 + shape="square"> 334 + <ButtonIcon icon={ArrowDownIcon} /> 335 + </Button> 336 + </> 337 + ) : ( 338 + <Button 339 + testID={`feed-${feedUri}-toggleSave`} 340 + label={_(msg`Remove from my feeds`)} 341 + onPress={onPressRemove} 342 + size="small" 343 + color="secondary" 344 + variant="ghost" 345 + shape="square"> 346 + <ButtonIcon icon={TrashIcon} /> 347 + </Button> 348 + )} 349 + <Button 350 + testID={`feed-${feed.type}-togglePin`} 351 + label={isPinned ? _(msg`Unpin feed`) : _(msg`Pin feed`)} 352 + onPress={onTogglePinned} 353 + size="small" 354 + color={isPinned ? 'primary_subtle' : 'secondary'} 355 + shape="square"> 356 + <ButtonIcon icon={PinIcon} /> 357 + </Button> 358 + </View> 359 + </Animated.View> 360 + ) 361 + } 362 + 363 + function SectionHeaderText({children}: {children: React.ReactNode}) { 364 + const t = useTheme() 365 + // eslint-disable-next-line bsky-internal/avoid-unwrapped-text 366 + return ( 367 + <View 368 + style={[ 369 + a.flex_row, 370 + a.flex_1, 371 + a.px_lg, 372 + a.pt_2xl, 373 + a.pb_md, 374 + a.border_b, 375 + t.atoms.border_contrast_low, 376 + ]}> 377 + <Text style={[a.text_xl, a.font_heavy, a.leading_snug]}>{children}</Text> 378 + </View> 379 + ) 380 + } 381 + 382 + function FollowingFeedCard() { 383 + const t = useTheme() 384 + return ( 385 + <View style={[a.flex_row, a.align_center, a.flex_1, a.p_lg]}> 386 + <View 387 + style={[ 388 + a.align_center, 389 + a.justify_center, 390 + a.rounded_sm, 391 + a.mr_md, 392 + { 393 + width: 36, 394 + height: 36, 395 + backgroundColor: t.palette.primary_500, 396 + }, 397 + ]}> 398 + <FilterTimeline 399 + style={[ 400 + { 401 + width: 22, 402 + height: 22, 403 + }, 404 + ]} 405 + fill={t.palette.white} 406 + /> 407 + </View> 408 + <View style={[a.flex_1, a.flex_row, a.gap_sm, a.align_center]}> 409 + <Text style={[a.text_sm, a.font_bold, a.leading_snug]}> 410 + <Trans context="feed-name">Following</Trans> 411 + </Text> 412 + </View> 413 + </View> 414 + ) 415 + }
+1 -1
src/screens/Settings/AppIconSettings/AppIconImage.tsx
··· 1 1 import {Image} from 'expo-image' 2 2 3 - import {AppIconSet} from '#/screens/Settings/AppIconSettings/types' 3 + import {type AppIconSet} from '#/screens/Settings/AppIconSettings/types' 4 4 import {atoms as a, platform, useTheme} from '#/alf' 5 5 6 6 export function AppIconImage({
+1 -1
src/screens/Settings/components/AddAppPasswordDialog.tsx
··· 8 8 SlideInRight, 9 9 SlideOutLeft, 10 10 } from 'react-native-reanimated' 11 - import {ComAtprotoServerCreateAppPassword} from '@atproto/api' 11 + import {type ComAtprotoServerCreateAppPassword} from '@atproto/api' 12 12 import {msg, Trans} from '@lingui/macro' 13 13 import {useLingui} from '@lingui/react' 14 14 import {useMutation} from '@tanstack/react-query'
+2 -2
src/screens/Settings/components/CopyButton.tsx
··· 1 1 import {useCallback, useEffect, useState} from 'react' 2 - import {GestureResponderEvent, View} from 'react-native' 2 + import {type GestureResponderEvent, View} from 'react-native' 3 3 import Animated, { 4 4 FadeOutUp, 5 5 useReducedMotion, ··· 9 9 import {Trans} from '@lingui/macro' 10 10 11 11 import {atoms as a, useTheme} from '#/alf' 12 - import {Button, ButtonProps} from '#/components/Button' 12 + import {Button, type ButtonProps} from '#/components/Button' 13 13 import {Text} from '#/components/Typography' 14 14 15 15 export function CopyButton({
+1 -1
src/screens/Settings/components/DeactivateAccountDialog.tsx
··· 7 7 import {useAgent, useSessionApi} from '#/state/session' 8 8 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 9 9 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 10 - import {DialogOuterProps} from '#/components/Dialog' 10 + import {type DialogOuterProps} from '#/components/Dialog' 11 11 import {Divider} from '#/components/Divider' 12 12 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 13 13 import {Loader} from '#/components/Loader'
+6 -7
src/screens/Settings/components/ExportCarDialog.tsx
··· 1 - import React from 'react' 1 + import {useCallback, useState} from 'react' 2 2 import {View} from 'react-native' 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' ··· 18 18 export function ExportCarDialog({ 19 19 control, 20 20 }: { 21 - control: Dialog.DialogOuterProps['control'] 21 + control: Dialog.DialogControlProps 22 22 }) { 23 23 const {_} = useLingui() 24 24 const t = useTheme() 25 25 const agent = useAgent() 26 - const [loading, setLoading] = React.useState(false) 26 + const [loading, setLoading] = useState(false) 27 27 28 - const download = React.useCallback(async () => { 28 + const download = useCallback(async () => { 29 29 if (!agent.session) { 30 30 return // shouldnt ever happen 31 31 } ··· 52 52 }, [_, control, agent]) 53 53 54 54 return ( 55 - <Dialog.Outer control={control}> 55 + <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> 56 56 <Dialog.Handle /> 57 57 <Dialog.ScrollableInner 58 58 accessibilityDescribedBy="dialog-description" ··· 63 63 </Text> 64 64 <Text 65 65 nativeID="dialog-description" 66 - style={[a.text_sm, a.leading_normal, t.atoms.text_contrast_high]}> 66 + style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_high]}> 67 67 <Trans> 68 68 Your account repository, containing all public data records, can 69 69 be downloaded as a "CAR" file. This file does not include media ··· 73 73 </Text> 74 74 75 75 <Button 76 - variant="solid" 77 76 color="primary" 78 77 size="large" 79 78 label={_(msg`Download CAR file`)}
+1 -1
src/screens/Settings/components/PwiOptOut.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 - import {$Typed, ComAtprotoLabelDefs} from '@atproto/api' 3 + import {type $Typed, ComAtprotoLabelDefs} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6
+1 -1
src/screens/Signup/StepCaptcha/CaptchaWebView.tsx
··· 31 31 onError: (error: unknown) => void 32 32 }) { 33 33 const startedAt = useRef(Date.now()) 34 - const successTo = useRef<NodeJS.Timeout>() 34 + const successTo = useRef<NodeJS.Timeout>(undefined) 35 35 36 36 useEffect(() => { 37 37 return () => {
+1 -1
src/screens/Signup/StepInfo/Policies.tsx
··· 72 72 ) 73 73 } 74 74 75 - let els: ReactElement 75 + let els: ReactElement<any> 76 76 if (tos && pp) { 77 77 els = ( 78 78 <Trans>
+1 -1
src/screens/Signup/StepInfo/index.tsx
··· 68 68 69 69 const [hasWarnedEmail, setHasWarnedEmail] = React.useState<boolean>(false) 70 70 71 - const tldtsRef = React.useRef<typeof tldts>() 71 + const tldtsRef = React.useRef<typeof tldts>(undefined) 72 72 React.useEffect(() => { 73 73 // @ts-expect-error - valid path 74 74 import('tldts/dist/index.cjs.min.js').then(tldts => {
+2 -2
src/screens/StarterPack/Wizard/StepFeeds.tsx
··· 1 1 import {useState} from 'react' 2 - import {ListRenderItemInfo, View} from 'react-native' 2 + import {type ListRenderItemInfo, View} from 'react-native' 3 3 import {KeyboardAwareScrollView} from 'react-native-keyboard-controller' 4 - import {AppBskyFeedDefs, ModerationOpts} from '@atproto/api' 4 + import {type AppBskyFeedDefs, type ModerationOpts} from '@atproto/api' 5 5 import {Trans} from '@lingui/macro' 6 6 7 7 import {DISCOVER_FEED_URI} from '#/lib/constants'
+3 -3
src/screens/StarterPack/Wizard/StepProfiles.tsx
··· 1 1 import {useState} from 'react' 2 - import {ListRenderItemInfo, View} from 'react-native' 2 + import {type ListRenderItemInfo, View} from 'react-native' 3 3 import {KeyboardAwareScrollView} from 'react-native-keyboard-controller' 4 - import {AppBskyActorDefs, ModerationOpts} from '@atproto/api' 4 + import {type AppBskyActorDefs, type ModerationOpts} from '@atproto/api' 5 5 import {Trans} from '@lingui/macro' 6 6 7 7 import {isNative} from '#/platform/detection' ··· 16 16 import {ScreenTransition} from '#/components/StarterPack/Wizard/ScreenTransition' 17 17 import {WizardProfileCard} from '#/components/StarterPack/Wizard/WizardListCard' 18 18 import {Text} from '#/components/Typography' 19 - import * as bsky from '#/types/bsky' 19 + import type * as bsky from '#/types/bsky' 20 20 21 21 function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic) { 22 22 return item?.did ?? ''
+4 -4
src/screens/VideoFeed/components/Header.tsx
··· 1 1 import {useCallback} from 'react' 2 - import {GestureResponderEvent, View} from 'react-native' 2 + import {type GestureResponderEvent, View} from 'react-native' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 import {useNavigation} from '@react-navigation/native' 6 6 7 7 import {HITSLOP_30} from '#/lib/constants' 8 - import {NavigationProp} from '#/lib/routes/types' 8 + import {type NavigationProp} from '#/lib/routes/types' 9 9 import {sanitizeHandle} from '#/lib/strings/handles' 10 10 import {useFeedSourceInfoQuery} from '#/state/queries/feed' 11 11 import {UserAvatar} from '#/view/com/util/UserAvatar' 12 - import {VideoFeedSourceContext} from '#/screens/VideoFeed/types' 12 + import {type VideoFeedSourceContext} from '#/screens/VideoFeed/types' 13 13 import {atoms as a, useBreakpoints} from '#/alf' 14 - import {Button, ButtonProps} from '#/components/Button' 14 + import {Button, type ButtonProps} from '#/components/Button' 15 15 import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft} from '#/components/icons/Arrow' 16 16 import * as Layout from '#/components/Layout' 17 17 import {BUTTON_VISUAL_ALIGNMENT_OFFSET} from '#/components/Layout/const'
+1 -1
src/screens/VideoFeed/types.ts
··· 1 - import {AuthorFilter} from '#/state/queries/post-feed' 1 + import {type AuthorFilter} from '#/state/queries/post-feed' 2 2 3 3 /** 4 4 * Kind of like `FeedDescriptor` but not
+5 -5
src/state/messages/convo/util.ts
··· 1 1 import { 2 - ConvoState, 3 - ConvoStateBackgrounded, 4 - ConvoStateDisabled, 5 - ConvoStateReady, 6 - ConvoStateSuspended, 2 + type ConvoState, 3 + type ConvoStateBackgrounded, 4 + type ConvoStateDisabled, 5 + type ConvoStateReady, 6 + type ConvoStateSuspended, 7 7 ConvoStatus, 8 8 } from './types' 9 9
+1 -1
src/state/messages/events/types.ts
··· 1 - import {BskyAgent, ChatBskyConvoGetLog} from '@atproto/api' 1 + import {type BskyAgent, type ChatBskyConvoGetLog} from '@atproto/api' 2 2 3 3 export type MessagesEventBusParams = { 4 4 agent: BskyAgent
+1 -1
src/state/messages/index.tsx
··· 1 - import React from 'react' 1 + import type React from 'react' 2 2 3 3 import {CurrentConvoIdProvider} from '#/state/messages/current-convo-id' 4 4 import {MessagesEventBusProvider} from '#/state/messages/events'
+2 -2
src/state/persisted/index.web.ts
··· 4 4 import {logger} from '#/logger' 5 5 import { 6 6 defaults, 7 - Schema, 7 + type Schema, 8 8 tryParse, 9 9 tryStringify, 10 10 } from '#/state/persisted/schema' 11 - import {PersistedApi} from './types' 11 + import {type PersistedApi} from './types' 12 12 import {normalizeData} from './util' 13 13 14 14 export type {PersistedAccount, Schema} from '#/state/persisted/schema'
+1 -1
src/state/persisted/types.ts
··· 1 - import type {Schema} from './schema' 1 + import {type Schema} from './schema' 2 2 3 3 export type PersistedApi = { 4 4 init(): Promise<void>
+1 -1
src/state/persisted/util.ts
··· 2 2 3 3 import {dedupArray} from '#/lib/functions' 4 4 import {logger} from '#/logger' 5 - import {Schema} from '#/state/persisted/schema' 5 + import {type Schema} from '#/state/persisted/schema' 6 6 7 7 export function normalizeData(data: Schema) { 8 8 const next = {...data}
+5 -1
src/state/queries/actor-autocomplete.ts
··· 1 1 import React from 'react' 2 - import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' 2 + import { 3 + type AppBskyActorDefs, 4 + moderateProfile, 5 + type ModerationOpts, 6 + } from '@atproto/api' 3 7 import {keepPreviousData, useQuery, useQueryClient} from '@tanstack/react-query' 4 8 5 9 import {isJustAMute, moduiContainsHideableOffense} from '#/lib/moderation'
+1 -1
src/state/queries/app-passwords.ts
··· 1 - import {ComAtprotoServerCreateAppPassword} from '@atproto/api' 1 + import {type ComAtprotoServerCreateAppPassword} from '@atproto/api' 2 2 import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' 3 3 4 4 import {STALE} from '#/state/queries'
+1 -1
src/state/queries/invites.ts
··· 1 - import {ComAtprotoServerDefs} from '@atproto/api' 1 + import {type ComAtprotoServerDefs} from '@atproto/api' 2 2 import {useQuery} from '@tanstack/react-query' 3 3 4 4 import {cleanError} from '#/lib/strings/errors'
+7 -4
src/state/queries/known-followers.ts
··· 1 - import {AppBskyActorDefs, AppBskyGraphGetKnownFollowers} from '@atproto/api' 2 1 import { 3 - InfiniteData, 4 - QueryClient, 5 - QueryKey, 2 + type AppBskyActorDefs, 3 + type AppBskyGraphGetKnownFollowers, 4 + } from '@atproto/api' 5 + import { 6 + type InfiniteData, 7 + type QueryClient, 8 + type QueryKey, 6 9 useInfiniteQuery, 7 10 } from '@tanstack/react-query' 8 11
+4 -4
src/state/queries/my-blocked-accounts.ts
··· 1 - import {AppBskyActorDefs, AppBskyGraphGetBlocks} from '@atproto/api' 1 + import {type AppBskyActorDefs, type AppBskyGraphGetBlocks} from '@atproto/api' 2 2 import { 3 - InfiniteData, 4 - QueryClient, 5 - QueryKey, 3 + type InfiniteData, 4 + type QueryClient, 5 + type QueryKey, 6 6 useInfiniteQuery, 7 7 } from '@tanstack/react-query' 8 8
+2 -2
src/state/queries/my-lists.ts
··· 1 - import {AppBskyGraphDefs} from '@atproto/api' 2 - import {QueryClient, useQuery} from '@tanstack/react-query' 1 + import {type AppBskyGraphDefs} from '@atproto/api' 2 + import {type QueryClient, useQuery} from '@tanstack/react-query' 3 3 4 4 import {accumulate} from '#/lib/async/accumulate' 5 5 import {STALE} from '#/state/queries'
+4 -4
src/state/queries/my-muted-accounts.ts
··· 1 - import {AppBskyActorDefs, AppBskyGraphGetMutes} from '@atproto/api' 1 + import {type AppBskyActorDefs, type AppBskyGraphGetMutes} from '@atproto/api' 2 2 import { 3 - InfiniteData, 4 - QueryClient, 5 - QueryKey, 3 + type InfiniteData, 4 + type QueryClient, 5 + type QueryKey, 6 6 useInfiniteQuery, 7 7 } from '@tanstack/react-query' 8 8
+1 -1
src/state/queries/nuxs/types.ts
··· 1 - import {AppBskyActorDefs} from '@atproto/api' 1 + import {type AppBskyActorDefs} from '@atproto/api' 2 2 3 3 export type Data = Record<string, unknown> | undefined 4 4
+3 -3
src/state/queries/nuxs/util.ts
··· 1 - import {AppBskyActorDefs, nuxSchema} from '@atproto/api' 1 + import {type AppBskyActorDefs, nuxSchema} from '@atproto/api' 2 2 3 3 import { 4 - AppNux, 5 - Nux, 4 + type AppNux, 5 + type Nux, 6 6 nuxNames, 7 7 NuxSchemas, 8 8 } from '#/state/queries/nuxs/definitions'
+1 -1
src/state/queries/post-interaction-settings.ts
··· 1 - import {AppBskyActorDefs} from '@atproto/api' 1 + import {type AppBskyActorDefs} from '@atproto/api' 2 2 import {useMutation, useQueryClient} from '@tanstack/react-query' 3 3 4 4 import {preferencesQueryKey} from '#/state/queries/preferences'
+4 -4
src/state/queries/post-liked-by.ts
··· 1 - import {AppBskyActorDefs, AppBskyFeedGetLikes} from '@atproto/api' 1 + import {type AppBskyActorDefs, type AppBskyFeedGetLikes} from '@atproto/api' 2 2 import { 3 - InfiniteData, 4 - QueryClient, 5 - QueryKey, 3 + type InfiniteData, 4 + type QueryClient, 5 + type QueryKey, 6 6 useInfiniteQuery, 7 7 } from '@tanstack/react-query' 8 8
+6 -6
src/state/queries/post-quotes.ts
··· 1 1 import { 2 - AppBskyActorDefs, 2 + type AppBskyActorDefs, 3 3 AppBskyEmbedRecord, 4 - AppBskyFeedDefs, 5 - AppBskyFeedGetQuotes, 4 + type AppBskyFeedDefs, 5 + type AppBskyFeedGetQuotes, 6 6 AtUri, 7 7 } from '@atproto/api' 8 8 import { 9 - InfiniteData, 10 - QueryClient, 11 - QueryKey, 9 + type InfiniteData, 10 + type QueryClient, 11 + type QueryKey, 12 12 useInfiniteQuery, 13 13 } from '@tanstack/react-query' 14 14
+7 -4
src/state/queries/post-reposted-by.ts
··· 1 - import {AppBskyActorDefs, AppBskyFeedGetRepostedBy} from '@atproto/api' 2 1 import { 3 - InfiniteData, 4 - QueryClient, 5 - QueryKey, 2 + type AppBskyActorDefs, 3 + type AppBskyFeedGetRepostedBy, 4 + } from '@atproto/api' 5 + import { 6 + type InfiniteData, 7 + type QueryClient, 8 + type QueryKey, 6 9 useInfiniteQuery, 7 10 } from '@tanstack/react-query' 8 11
+1 -1
src/state/queries/postgate/index.ts
··· 173 173 const agent = useAgent() 174 174 const queryClient = useQueryClient() 175 175 const getPosts = useGetPosts() 176 - const prevEmbed = React.useRef<AppBskyFeedDefs.PostView['embed']>() 176 + const prevEmbed = React.useRef<AppBskyFeedDefs.PostView['embed']>(undefined) 177 177 178 178 return useMutation({ 179 179 mutationFn: async ({
+3 -3
src/state/queries/preferences/types.ts
··· 1 1 import { 2 - BskyFeedViewPreference, 3 - BskyPreferences, 4 - BskyThreadViewPreference, 2 + type BskyFeedViewPreference, 3 + type BskyPreferences, 4 + type BskyThreadViewPreference, 5 5 } from '@atproto/api' 6 6 7 7 export type UsePreferencesQueryResponse = Omit<
+9 -2
src/state/queries/profile-feedgens.ts
··· 1 - import {AppBskyFeedGetActorFeeds, moderateFeedGenerator} from '@atproto/api' 2 - import {InfiniteData, QueryKey, useInfiniteQuery} from '@tanstack/react-query' 1 + import { 2 + type AppBskyFeedGetActorFeeds, 3 + moderateFeedGenerator, 4 + } from '@atproto/api' 5 + import { 6 + type InfiniteData, 7 + type QueryKey, 8 + useInfiniteQuery, 9 + } from '@tanstack/react-query' 3 10 4 11 import {useAgent} from '#/state/session' 5 12 import {useModerationOpts} from '../preferences/moderation-opts'
+7 -4
src/state/queries/profile-followers.ts
··· 1 - import {AppBskyActorDefs, AppBskyGraphGetFollowers} from '@atproto/api' 2 1 import { 3 - InfiniteData, 4 - QueryClient, 5 - QueryKey, 2 + type AppBskyActorDefs, 3 + type AppBskyGraphGetFollowers, 4 + } from '@atproto/api' 5 + import { 6 + type InfiniteData, 7 + type QueryClient, 8 + type QueryKey, 6 9 useInfiniteQuery, 7 10 } from '@tanstack/react-query' 8 11
+4 -4
src/state/queries/profile-follows.ts
··· 1 - import {AppBskyActorDefs, AppBskyGraphGetFollows} from '@atproto/api' 1 + import {type AppBskyActorDefs, type AppBskyGraphGetFollows} from '@atproto/api' 2 2 import { 3 - InfiniteData, 4 - QueryClient, 5 - QueryKey, 3 + type InfiniteData, 4 + type QueryClient, 5 + type QueryKey, 6 6 useInfiniteQuery, 7 7 } from '@tanstack/react-query' 8 8
+6 -2
src/state/queries/profile-lists.ts
··· 1 - import {AppBskyGraphGetLists, moderateUserList} from '@atproto/api' 2 - import {InfiniteData, QueryKey, useInfiniteQuery} from '@tanstack/react-query' 1 + import {type AppBskyGraphGetLists, moderateUserList} from '@atproto/api' 2 + import { 3 + type InfiniteData, 4 + type QueryKey, 5 + useInfiniteQuery, 6 + } from '@tanstack/react-query' 3 7 4 8 import {useAgent} from '#/state/session' 5 9 import {useModerationOpts} from '../preferences/moderation-opts'
+4 -4
src/state/queries/resolve-link.ts
··· 1 - import {QueryClient, useQuery} from '@tanstack/react-query' 1 + import {type QueryClient, useQuery} from '@tanstack/react-query' 2 2 3 3 import {STALE} from '#/state/queries/index' 4 4 import {useAgent} from '../session' ··· 9 9 const RQKEY_GIF_ROOT = 'resolve-gif' 10 10 export const RQKEY_GIF = (url: string) => [RQKEY_GIF_ROOT, url] 11 11 12 - import {BskyAgent} from '@atproto/api' 12 + import {type BskyAgent} from '@atproto/api' 13 13 14 - import {ResolvedLink, resolveGif, resolveLink} from '#/lib/api/resolve' 15 - import {Gif} from './tenor' 14 + import {type ResolvedLink, resolveGif, resolveLink} from '#/lib/api/resolve' 15 + import {type Gif} from './tenor' 16 16 17 17 export function useResolveLinkQuery(url: string) { 18 18 const agent = useAgent()
+5 -1
src/state/queries/resolve-uri.ts
··· 1 1 import {AtUri} from '@atproto/api' 2 - import {QueryClient, useQuery, UseQueryResult} from '@tanstack/react-query' 2 + import { 3 + type QueryClient, 4 + useQuery, 5 + type UseQueryResult, 6 + } from '@tanstack/react-query' 3 7 4 8 import {STALE} from '#/state/queries' 5 9 import {useAgent} from '#/state/session'
+6 -6
src/state/queries/search-posts.ts
··· 1 1 import React from 'react' 2 2 import { 3 - AppBskyActorDefs, 4 - AppBskyFeedDefs, 5 - AppBskyFeedSearchPosts, 3 + type AppBskyActorDefs, 4 + type AppBskyFeedDefs, 5 + type AppBskyFeedSearchPosts, 6 6 AtUri, 7 7 moderatePost, 8 8 } from '@atproto/api' 9 9 import { 10 - InfiniteData, 11 - QueryClient, 12 - QueryKey, 10 + type InfiniteData, 11 + type QueryClient, 12 + type QueryKey, 13 13 useInfiniteQuery, 14 14 } from '@tanstack/react-query' 15 15
+6 -2
src/state/queries/suggested-feeds.ts
··· 1 - import {AppBskyFeedGetSuggestedFeeds} from '@atproto/api' 2 - import {InfiniteData, QueryKey, useInfiniteQuery} from '@tanstack/react-query' 1 + import {type AppBskyFeedGetSuggestedFeeds} from '@atproto/api' 2 + import { 3 + type InfiniteData, 4 + type QueryKey, 5 + useInfiniteQuery, 6 + } from '@tanstack/react-query' 3 7 4 8 import {STALE} from '#/state/queries' 5 9 import {useAgent} from '#/state/session'
+3 -3
src/state/queries/threadgate/index.ts
··· 1 1 import { 2 2 AppBskyFeedDefs, 3 - AppBskyFeedGetPostThread, 3 + type AppBskyFeedGetPostThread, 4 4 AppBskyFeedThreadgate, 5 5 AtUri, 6 - BskyAgent, 6 + type BskyAgent, 7 7 } from '@atproto/api' 8 8 import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' 9 9 ··· 11 11 import {until} from '#/lib/async/until' 12 12 import {STALE} from '#/state/queries' 13 13 import {RQKEY_ROOT as postThreadQueryKeyRoot} from '#/state/queries/post-thread' 14 - import {ThreadgateAllowUISetting} from '#/state/queries/threadgate/types' 14 + import {type ThreadgateAllowUISetting} from '#/state/queries/threadgate/types' 15 15 import { 16 16 createThreadgateRecord, 17 17 mergeThreadgateRecords,
+2 -2
src/state/queries/threadgate/util.ts
··· 1 - import {AppBskyFeedDefs, AppBskyFeedThreadgate} from '@atproto/api' 1 + import {type AppBskyFeedDefs, AppBskyFeedThreadgate} from '@atproto/api' 2 2 3 - import {ThreadgateAllowUISetting} from '#/state/queries/threadgate/types' 3 + import {type ThreadgateAllowUISetting} from '#/state/queries/threadgate/types' 4 4 import * as bsky from '#/types/bsky' 5 5 6 6 export function threadgateViewToAllowUISetting(
+2 -2
src/state/queries/unstable-profile-cache.ts
··· 1 1 import {useCallback} from 'react' 2 - import {QueryClient, useQueryClient} from '@tanstack/react-query' 2 + import {type QueryClient, useQueryClient} from '@tanstack/react-query' 3 3 4 - import * as bsky from '#/types/bsky' 4 + import type * as bsky from '#/types/bsky' 5 5 6 6 const unstableProfileViewCacheQueryKeyRoot = 'unstableProfileViewCache' 7 7 export const unstableProfileViewCacheQueryKey = (didOrHandle: string) => [
+8 -4
src/state/queries/util.ts
··· 1 1 import { 2 - AppBskyActorDefs, 2 + type AppBskyActorDefs, 3 3 AppBskyEmbedRecord, 4 4 AppBskyEmbedRecordWithMedia, 5 - AppBskyFeedDefs, 5 + type AppBskyFeedDefs, 6 6 AppBskyFeedPost, 7 - AtUri, 7 + type AtUri, 8 8 } from '@atproto/api' 9 - import {InfiniteData, QueryClient, QueryKey} from '@tanstack/react-query' 9 + import { 10 + type InfiniteData, 11 + type QueryClient, 12 + type QueryKey, 13 + } from '@tanstack/react-query' 10 14 11 15 import * as bsky from '#/types/bsky' 12 16
+1 -1
src/state/session/__tests__/session-test.ts
··· 2 2 import {describe, expect, it, jest} from '@jest/globals' 3 3 4 4 import {agentToSessionAccountOrThrow} from '../agent' 5 - import {Action, getInitialState, reducer, State} from '../reducer' 5 + import {type Action, getInitialState, reducer, type State} from '../reducer' 6 6 7 7 jest.mock('jwt-decode', () => ({ 8 8 jwtDecode(_token: string) {
+1 -1
src/state/session/util.ts
··· 3 3 import {hasProp} from '#/lib/type-guards' 4 4 import {logger} from '#/logger' 5 5 import * as persisted from '#/state/persisted' 6 - import {SessionAccount} from './types' 6 + import {type SessionAccount} from './types' 7 7 8 8 export function readLastActiveAccount() { 9 9 const {currentAccount, accounts} = persisted.get('session')
-2
src/state/shell/index.tsx
··· 1 - import type React from 'react' 2 - 3 1 import {Provider as ColorModeProvider} from './color-mode' 4 2 import {Provider as DrawerOpenProvider} from './drawer-open' 5 3 import {Provider as DrawerSwipableProvider} from './drawer-swipe-disabled'
+1 -1
src/state/shell/reminders.ts
··· 1 1 import {simpleAreDatesEqual} from '#/lib/strings/time' 2 2 import {logger} from '#/logger' 3 3 import * as persisted from '#/state/persisted' 4 - import {SessionAccount} from '../session' 4 + import {type SessionAccount} from '../session' 5 5 import {isOnboardingActive} from './onboarding' 6 6 7 7 export function shouldRequestEmailConfirmation(account: SessionAccount) {
+1 -1
src/types/bsky/index.ts
··· 1 - import {ValidationResult} from '@atproto/lexicon' 1 + import {type ValidationResult} from '@atproto/lexicon' 2 2 3 3 export * as post from '#/types/bsky/post' 4 4 export * as profile from '#/types/bsky/profile'
+1 -1
src/types/bsky/post.ts
··· 1 1 import { 2 - $Typed, 2 + type $Typed, 3 3 AppBskyEmbedExternal, 4 4 AppBskyEmbedImages, 5 5 AppBskyEmbedRecord,
+1 -1
src/view/com/composer/AltTextCounterWrapper.tsx
··· 1 - import React from 'react' 2 1 import {View} from 'react-native' 2 + import type React from 'react' 3 3 4 4 import {MAX_ALT_TEXT} from '#/lib/constants' 5 5 import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
+1 -1
src/view/com/composer/Composer.tsx
··· 174 174 videoUri: initVideoUri, 175 175 cancelRef, 176 176 }: Props & { 177 - cancelRef?: React.RefObject<CancelRef> 177 + cancelRef?: React.RefObject<CancelRef | null> 178 178 }) => { 179 179 const {currentAccount} = useSession() 180 180 const agent = useAgent()
+1 -1
src/view/com/composer/KeyboardAccessory.tsx
··· 1 - import React from 'react' 2 1 import {View} from 'react-native' 3 2 import {KeyboardStickyView} from 'react-native-keyboard-controller' 4 3 import {useSafeAreaInsets} from 'react-native-safe-area-context' 4 + import type React from 'react' 5 5 6 6 import {isWeb} from '#/platform/detection' 7 7 import {atoms as a, useTheme} from '#/alf'
+6 -1
src/view/com/composer/char-progress/CharProgress.tsx
··· 1 - import {StyleProp, TextStyle, View, ViewStyle} from 'react-native' 1 + import { 2 + type StyleProp, 3 + type TextStyle, 4 + View, 5 + type ViewStyle, 6 + } from 'react-native' 2 7 // @ts-ignore no type definition -prf 3 8 import ProgressCircle from 'react-native-progress/Circle' 4 9 // @ts-ignore no type definition -prf
-2
src/view/com/composer/photos/EditImageDialog.tsx
··· 1 - import type React from 'react' 2 - 3 1 import {type ComposerImage} from '#/state/gallery' 4 2 import type * as Dialog from '#/components/Dialog' 5 3
+1 -1
src/view/com/composer/photos/EditImageDialog.web.tsx
··· 112 112 aspectRatio, 113 113 }: Required<Pick<EditImageDialogProps, 'image'>> & 114 114 Omit<EditImageDialogProps, 'control' | 'image'> & { 115 - saveRef: React.RefObject<{save: () => Promise<void>}> 115 + saveRef: React.RefObject<{save: () => Promise<void>} | null> 116 116 }) { 117 117 const t = useTheme() 118 118 const [isDragging, setIsDragging] = useState(false)
+1 -1
src/view/com/composer/photos/SelectGifBtn.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 6 6 import {logEvent} from '#/lib/statsig/statsig' 7 - import {Gif} from '#/state/queries/tenor' 7 + import {type Gif} from '#/state/queries/tenor' 8 8 import {atoms as a, useTheme} from '#/alf' 9 9 import {Button} from '#/components/Button' 10 10 import {GifSelectDialog} from '#/components/dialogs/GifSelect'
+11 -1
src/view/com/composer/select-language/SuggestedLanguage.tsx
··· 1 1 import {useEffect, useState} from 'react' 2 2 import {View} from 'react-native' 3 + import {parseLanguage} from '@atproto/api' 3 4 import {msg, Trans} from '@lingui/macro' 4 5 import {useLingui} from '@lingui/react' 5 6 import lande from 'lande' ··· 21 22 22 23 export function SuggestedLanguage({ 23 24 text, 24 - replyToLanguage, 25 + replyToLanguage: replyToLanguageProp, 25 26 }: { 26 27 text: string 27 28 replyToLanguage?: string 28 29 }) { 30 + const replyToLanguage = cleanUpLanguage(replyToLanguageProp) 29 31 const [suggestedLanguage, setSuggestedLanguage] = useState< 30 32 string | undefined 31 33 >(text.length === 0 ? replyToLanguage : undefined) ··· 125 127 } 126 128 return code3ToCode2Strict(lang) 127 129 } 130 + 131 + function cleanUpLanguage(text: string | undefined): string | undefined { 132 + if (!text) { 133 + return undefined 134 + } 135 + 136 + return parseLanguage(text)?.language 137 + }
+1 -1
src/view/com/composer/text-input/text-input-util.ts
··· 1 - import {AppBskyRichtextFacet, RichText} from '@atproto/api' 1 + import {type AppBskyRichtextFacet, type RichText} from '@atproto/api' 2 2 3 3 export type LinkFacetMatch = { 4 4 rt: RichText
+1 -1
src/view/com/composer/text-input/web/LinkDecorator.ts
··· 16 16 17 17 import {URL_REGEX} from '@atproto/api' 18 18 import {Mark} from '@tiptap/core' 19 - import {Node as ProsemirrorNode} from '@tiptap/pm/model' 19 + import {type Node as ProsemirrorNode} from '@tiptap/pm/model' 20 20 import {Plugin, PluginKey} from '@tiptap/pm/state' 21 21 import {Decoration, DecorationSet} from '@tiptap/pm/view' 22 22
+1 -1
src/view/com/composer/text-input/web/TagDecorator.ts
··· 16 16 17 17 import {TAG_REGEX, TRAILING_PUNCTUATION_REGEX} from '@atproto/api' 18 18 import {Mark} from '@tiptap/core' 19 - import {Node as ProsemirrorNode} from '@tiptap/pm/model' 19 + import {type Node as ProsemirrorNode} from '@tiptap/pm/model' 20 20 import {Plugin, PluginKey} from '@tiptap/pm/state' 21 21 import {Decoration, DecorationSet} from '@tiptap/pm/view' 22 22
+4 -4
src/view/com/composer/threadgate/ThreadgateBtn.tsx
··· 1 - import {Keyboard, StyleProp, ViewStyle} from 'react-native' 2 - import {AnimatedStyle} from 'react-native-reanimated' 3 - import {AppBskyFeedPostgate} from '@atproto/api' 1 + import {Keyboard, type StyleProp, type ViewStyle} from 'react-native' 2 + import {type AnimatedStyle} from 'react-native-reanimated' 3 + import {type AppBskyFeedPostgate} from '@atproto/api' 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 7 import {isNative} from '#/platform/detection' 8 - import {ThreadgateAllowUISetting} from '#/state/queries/threadgate' 8 + import {type ThreadgateAllowUISetting} from '#/state/queries/threadgate' 9 9 import {native} from '#/alf' 10 10 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 11 11 import * as Dialog from '#/components/Dialog'
+2 -1
src/view/com/composer/videos/SubtitleFilePicker.tsx
··· 1 - import React, {useRef} from 'react' 1 + import {useRef} from 'react' 2 2 import {View} from 'react-native' 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 + import type React from 'react' 5 6 6 7 import {logger} from '#/logger' 7 8 import * as Toast from '#/view/com/util/Toast'
+2 -2
src/view/com/composer/videos/VideoPreview.web.tsx
··· 1 1 import {View} from 'react-native' 2 - import {ImagePickerAsset} from 'expo-image-picker' 2 + import {type ImagePickerAsset} from 'expo-image-picker' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {CompressedVideo} from '#/lib/media/video/types' 6 + import {type CompressedVideo} from '#/lib/media/video/types' 7 7 import {clamp} from '#/lib/numbers' 8 8 import {useAutoplayDisabled} from '#/state/preferences' 9 9 import {ExternalEmbedRemoveBtn} from '#/view/com/composer/ExternalEmbedRemoveBtn'
+1 -1
src/view/com/composer/videos/VideoTranscodeProgress.tsx
··· 1 1 import {View} from 'react-native' 2 2 // @ts-expect-error no type definition 3 3 import ProgressPie from 'react-native-progress/Pie' 4 - import {ImagePickerAsset} from 'expo-image-picker' 4 + import {type ImagePickerAsset} from 'expo-image-picker' 5 5 6 6 import {clamp} from '#/lib/numbers' 7 7 import {isWeb} from '#/platform/detection'
+1 -1
src/view/com/composer/videos/pickVideo.web.ts
··· 1 - import {ImagePickerAsset, ImagePickerResult} from 'expo-image-picker' 1 + import {type ImagePickerAsset, type ImagePickerResult} from 'expo-image-picker' 2 2 3 3 import {SUPPORTED_MIME_TYPES} from '#/lib/constants' 4 4
+8 -1
src/view/com/feeds/FeedPage.tsx
··· 1 - import {useCallback, useEffect, useMemo, useRef, useState} from 'react' 1 + import { 2 + type JSX, 3 + useCallback, 4 + useEffect, 5 + useMemo, 6 + useRef, 7 + useState, 8 + } from 'react' 2 9 import {View} from 'react-native' 3 10 import {type AppBskyActorDefs, AppBskyFeedDefs} from '@atproto/api' 4 11 import {msg} from '@lingui/macro'
+32 -19
src/view/com/feeds/ProfileFeedgens.tsx
··· 1 - import React from 'react' 1 + import { 2 + useCallback, 3 + useEffect, 4 + useImperativeHandle, 5 + useMemo, 6 + useState, 7 + } from 'react' 2 8 import { 3 9 findNodeHandle, 4 10 type ListRenderItemInfo, 5 11 type StyleProp, 12 + useWindowDimensions, 6 13 View, 7 14 type ViewStyle, 8 15 } from 'react-native' ··· 34 41 } 35 42 36 43 interface ProfileFeedgensProps { 44 + ref?: React.Ref<SectionRef> 37 45 did: string 38 46 scrollElRef: ListRef 39 47 headerOffset: number ··· 43 51 setScrollViewTag: (tag: number | null) => void 44 52 } 45 53 46 - export const ProfileFeedgens = React.forwardRef< 47 - SectionRef, 48 - ProfileFeedgensProps 49 - >(function ProfileFeedgensImpl( 50 - {did, scrollElRef, headerOffset, enabled, style, testID, setScrollViewTag}, 54 + export function ProfileFeedgens({ 51 55 ref, 52 - ) { 56 + did, 57 + scrollElRef, 58 + headerOffset, 59 + enabled, 60 + style, 61 + testID, 62 + setScrollViewTag, 63 + }: ProfileFeedgensProps) { 53 64 const {_} = useLingui() 54 65 const t = useTheme() 55 - const [isPTRing, setIsPTRing] = React.useState(false) 56 - const opts = React.useMemo(() => ({enabled}), [enabled]) 66 + const [isPTRing, setIsPTRing] = useState(false) 67 + const {height} = useWindowDimensions() 68 + const opts = useMemo(() => ({enabled}), [enabled]) 57 69 const { 58 70 data, 59 71 isPending, ··· 67 79 const isEmpty = !isPending && !data?.pages[0]?.feeds.length 68 80 const {data: preferences} = usePreferencesQuery() 69 81 70 - const items = React.useMemo(() => { 82 + const items = useMemo(() => { 71 83 let items: any[] = [] 72 84 if (isError && isEmpty) { 73 85 items = items.concat([ERROR_ITEM]) ··· 91 103 92 104 const queryClient = useQueryClient() 93 105 94 - const onScrollToTop = React.useCallback(() => { 106 + const onScrollToTop = useCallback(() => { 95 107 scrollElRef.current?.scrollToOffset({ 96 108 animated: isNative, 97 109 offset: -headerOffset, ··· 99 111 queryClient.invalidateQueries({queryKey: RQKEY(did)}) 100 112 }, [scrollElRef, queryClient, headerOffset, did]) 101 113 102 - React.useImperativeHandle(ref, () => ({ 114 + useImperativeHandle(ref, () => ({ 103 115 scrollToTop: onScrollToTop, 104 116 })) 105 117 106 - const onRefresh = React.useCallback(async () => { 118 + const onRefresh = useCallback(async () => { 107 119 setIsPTRing(true) 108 120 try { 109 121 await refetch() ··· 113 125 setIsPTRing(false) 114 126 }, [refetch, setIsPTRing]) 115 127 116 - const onEndReached = React.useCallback(async () => { 128 + const onEndReached = useCallback(async () => { 117 129 if (isFetchingNextPage || !hasNextPage || isError) return 118 130 119 131 try { ··· 123 135 } 124 136 }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage]) 125 137 126 - const onPressRetryLoadMore = React.useCallback(() => { 138 + const onPressRetryLoadMore = useCallback(() => { 127 139 fetchNextPage() 128 140 }, [fetchNextPage]) 129 141 130 142 // rendering 131 143 // = 132 144 133 - const renderItem = React.useCallback( 145 + const renderItem = useCallback( 134 146 ({item, index}: ListRenderItemInfo<any>) => { 135 147 if (item === EMPTY) { 136 148 return ( ··· 174 186 [_, t, error, refetch, onPressRetryLoadMore, preferences], 175 187 ) 176 188 177 - React.useEffect(() => { 189 + useEffect(() => { 178 190 if (isIOS && enabled && scrollElRef.current) { 179 191 const nativeTag = findNodeHandle(scrollElRef.current) 180 192 setScrollViewTag(nativeTag) 181 193 } 182 194 }, [enabled, scrollElRef, setScrollViewTag]) 183 195 184 - const ProfileFeedgensFooter = React.useCallback(() => { 196 + const ProfileFeedgensFooter = useCallback(() => { 185 197 if (isEmpty) return null 186 198 return ( 187 199 <ListFooter ··· 217 229 removeClippedSubviews={true} 218 230 desktopFixedHeight 219 231 onEndReached={onEndReached} 232 + contentContainerStyle={{minHeight: height + headerOffset}} 220 233 /> 221 234 </View> 222 235 ) 223 - }) 236 + } 224 237 225 238 function keyExtractor(item: any) { 226 239 return item._reactKey || item.uri
+2 -1
src/view/com/home/HomeHeaderLayout.web.tsx
··· 1 - import React from 'react' 1 + import {type JSX} from 'react' 2 2 import {View} from 'react-native' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 + import type React from 'react' 5 6 6 7 import {useKawaiiMode} from '#/state/preferences/kawaii' 7 8 import {useSession} from '#/state/session'
+1
src/view/com/home/HomeHeaderLayoutMobile.tsx
··· 1 + import {type JSX} from 'react' 1 2 import {View} from 'react-native' 2 3 import Animated from 'react-native-reanimated' 3 4 import {msg} from '@lingui/macro'
+2 -2
src/view/com/lightbox/ImageViewing/@types/index.ts
··· 6 6 * 7 7 */ 8 8 9 - import {TransformsStyle} from 'react-native' 10 - import {MeasuredDimensions} from 'react-native-reanimated' 9 + import {type TransformsStyle} from 'react-native' 10 + import {type MeasuredDimensions} from 'react-native-reanimated' 11 11 12 12 export type Dimensions = { 13 13 width: number
+1 -1
src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx
··· 5 5 * LICENSE file in the root directory of this source tree. 6 6 * 7 7 */ 8 - import {StyleSheet, TouchableOpacity, ViewStyle} from 'react-native' 8 + import {StyleSheet, TouchableOpacity, type ViewStyle} from 'react-native' 9 9 import {SafeAreaView} from 'react-native-safe-area-context' 10 10 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 11 11 import {msg} from '@lingui/macro'
+7 -7
src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx
··· 3 3 import { 4 4 Gesture, 5 5 GestureDetector, 6 - PanGesture, 6 + type PanGesture, 7 7 } from 'react-native-gesture-handler' 8 8 import Animated, { 9 9 runOnJS, 10 - SharedValue, 10 + type SharedValue, 11 11 useAnimatedReaction, 12 12 useAnimatedRef, 13 13 useAnimatedStyle, ··· 16 16 } from 'react-native-reanimated' 17 17 import {Image} from 'expo-image' 18 18 19 - import type { 20 - Dimensions as ImageDimensions, 21 - ImageSource, 22 - Transform, 19 + import { 20 + type Dimensions as ImageDimensions, 21 + type ImageSource, 22 + type Transform, 23 23 } from '../../@types' 24 24 import { 25 25 applyRounding, ··· 28 28 prependPinch, 29 29 prependTransform, 30 30 readTransform, 31 - TransformMatrix, 31 + type TransformMatrix, 32 32 } from '../../transforms' 33 33 34 34 const MIN_SCREEN_ZOOM = 2
+5 -5
src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx
··· 11 11 import { 12 12 Gesture, 13 13 GestureDetector, 14 - PanGesture, 14 + type PanGesture, 15 15 } from 'react-native-gesture-handler' 16 16 import Animated, { 17 17 runOnJS, 18 - SharedValue, 18 + type SharedValue, 19 19 useAnimatedProps, 20 20 useAnimatedReaction, 21 21 useAnimatedRef, ··· 27 27 28 28 import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED' 29 29 import { 30 - Dimensions as ImageDimensions, 31 - ImageSource, 32 - Transform, 30 + type Dimensions as ImageDimensions, 31 + type ImageSource, 32 + type Transform, 33 33 } from '../../@types' 34 34 35 35 const MAX_ORIGINAL_IMAGE_ZOOM = 2
+6 -6
src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.tsx
··· 2 2 3 3 import React from 'react' 4 4 import {View} from 'react-native' 5 - import {PanGesture} from 'react-native-gesture-handler' 6 - import {SharedValue} from 'react-native-reanimated' 5 + import {type PanGesture} from 'react-native-gesture-handler' 6 + import {type SharedValue} from 'react-native-reanimated' 7 7 8 - import {Dimensions} from '#/lib/media/types' 8 + import {type Dimensions} from '#/lib/media/types' 9 9 import { 10 - Dimensions as ImageDimensions, 11 - ImageSource, 12 - Transform, 10 + type Dimensions as ImageDimensions, 11 + type ImageSource, 12 + type Transform, 13 13 } from '../../@types' 14 14 15 15 type Props = {
+1 -1
src/view/com/lightbox/ImageViewing/transforms.ts
··· 1 - import type {Position} from './@types' 1 + import {type Position} from './@types' 2 2 3 3 export type TransformMatrix = [ 4 4 number,
+1 -1
src/view/com/lists/ListMembers.tsx
··· 1 - import React, {useCallback} from 'react' 1 + import React, {type JSX, useCallback} from 'react' 2 2 import { 3 3 Dimensions, 4 4 type GestureResponderEvent,
+5 -5
src/view/com/lists/MyLists.tsx
··· 1 - import React from 'react' 1 + import React, {type JSX} from 'react' 2 2 import { 3 3 ActivityIndicator, 4 4 FlatList as RNFlatList, 5 5 RefreshControl, 6 - StyleProp, 6 + type StyleProp, 7 7 View, 8 - ViewStyle, 8 + type ViewStyle, 9 9 } from 'react-native' 10 - import {AppBskyGraphDefs as GraphDefs} from '@atproto/api' 10 + import {type AppBskyGraphDefs as GraphDefs} from '@atproto/api' 11 11 import {msg} from '@lingui/macro' 12 12 import {useLingui} from '@lingui/react' 13 13 ··· 16 16 import {s} from '#/lib/styles' 17 17 import {logger} from '#/logger' 18 18 import {useModerationOpts} from '#/state/preferences/moderation-opts' 19 - import {MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists' 19 + import {type MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists' 20 20 import {atoms as a, useTheme} from '#/alf' 21 21 import {BulletList_Stroke2_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 22 22 import * as ListCard from '#/components/ListCard'
+169 -158
src/view/com/lists/ProfileLists.tsx
··· 1 - import React from 'react' 1 + import { 2 + useCallback, 3 + useEffect, 4 + useImperativeHandle, 5 + useMemo, 6 + useState, 7 + } from 'react' 2 8 import { 3 9 findNodeHandle, 4 10 type ListRenderItemInfo, 5 11 type StyleProp, 12 + useWindowDimensions, 6 13 View, 7 14 type ViewStyle, 8 15 } from 'react-native' ··· 33 40 } 34 41 35 42 interface ProfileListsProps { 43 + ref?: React.Ref<SectionRef> 36 44 did: string 37 45 scrollElRef: ListRef 38 46 headerOffset: number ··· 42 50 setScrollViewTag: (tag: number | null) => void 43 51 } 44 52 45 - export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( 46 - function ProfileListsImpl( 47 - {did, scrollElRef, headerOffset, enabled, style, testID, setScrollViewTag}, 48 - ref, 49 - ) { 50 - const t = useTheme() 51 - const {_} = useLingui() 52 - const [isPTRing, setIsPTRing] = React.useState(false) 53 - const opts = React.useMemo(() => ({enabled}), [enabled]) 54 - const { 55 - data, 56 - isPending, 57 - hasNextPage, 58 - fetchNextPage, 59 - isFetchingNextPage, 60 - isError, 61 - error, 62 - refetch, 63 - } = useProfileListsQuery(did, opts) 64 - const isEmpty = !isPending && !data?.pages[0]?.lists.length 53 + export function ProfileLists({ 54 + ref, 55 + did, 56 + scrollElRef, 57 + headerOffset, 58 + enabled, 59 + style, 60 + testID, 61 + setScrollViewTag, 62 + }: ProfileListsProps) { 63 + const t = useTheme() 64 + const {_} = useLingui() 65 + const {height} = useWindowDimensions() 66 + const [isPTRing, setIsPTRing] = useState(false) 67 + const opts = useMemo(() => ({enabled}), [enabled]) 68 + const { 69 + data, 70 + isPending, 71 + hasNextPage, 72 + fetchNextPage, 73 + isFetchingNextPage, 74 + isError, 75 + error, 76 + refetch, 77 + } = useProfileListsQuery(did, opts) 78 + const isEmpty = !isPending && !data?.pages[0]?.lists.length 65 79 66 - const items = React.useMemo(() => { 67 - let items: any[] = [] 68 - if (isError && isEmpty) { 69 - items = items.concat([ERROR_ITEM]) 70 - } 71 - if (isPending) { 72 - items = items.concat([LOADING]) 73 - } else if (isEmpty) { 74 - items = items.concat([EMPTY]) 75 - } else if (data?.pages) { 76 - for (const page of data?.pages) { 77 - items = items.concat(page.lists) 78 - } 79 - } 80 - if (isError && !isEmpty) { 81 - items = items.concat([LOAD_MORE_ERROR_ITEM]) 80 + const items = useMemo(() => { 81 + let items: any[] = [] 82 + if (isError && isEmpty) { 83 + items = items.concat([ERROR_ITEM]) 84 + } 85 + if (isPending) { 86 + items = items.concat([LOADING]) 87 + } else if (isEmpty) { 88 + items = items.concat([EMPTY]) 89 + } else if (data?.pages) { 90 + for (const page of data?.pages) { 91 + items = items.concat(page.lists) 82 92 } 83 - return items 84 - }, [isError, isEmpty, isPending, data]) 93 + } 94 + if (isError && !isEmpty) { 95 + items = items.concat([LOAD_MORE_ERROR_ITEM]) 96 + } 97 + return items 98 + }, [isError, isEmpty, isPending, data]) 85 99 86 - // events 87 - // = 100 + // events 101 + // = 88 102 89 - const queryClient = useQueryClient() 103 + const queryClient = useQueryClient() 90 104 91 - const onScrollToTop = React.useCallback(() => { 92 - scrollElRef.current?.scrollToOffset({ 93 - animated: isNative, 94 - offset: -headerOffset, 95 - }) 96 - queryClient.invalidateQueries({queryKey: RQKEY(did)}) 97 - }, [scrollElRef, queryClient, headerOffset, did]) 105 + const onScrollToTop = useCallback(() => { 106 + scrollElRef.current?.scrollToOffset({ 107 + animated: isNative, 108 + offset: -headerOffset, 109 + }) 110 + queryClient.invalidateQueries({queryKey: RQKEY(did)}) 111 + }, [scrollElRef, queryClient, headerOffset, did]) 98 112 99 - React.useImperativeHandle(ref, () => ({ 100 - scrollToTop: onScrollToTop, 101 - })) 113 + useImperativeHandle(ref, () => ({ 114 + scrollToTop: onScrollToTop, 115 + })) 102 116 103 - const onRefresh = React.useCallback(async () => { 104 - setIsPTRing(true) 105 - try { 106 - await refetch() 107 - } catch (err) { 108 - logger.error('Failed to refresh lists', {message: err}) 109 - } 110 - setIsPTRing(false) 111 - }, [refetch, setIsPTRing]) 117 + const onRefresh = useCallback(async () => { 118 + setIsPTRing(true) 119 + try { 120 + await refetch() 121 + } catch (err) { 122 + logger.error('Failed to refresh lists', {message: err}) 123 + } 124 + setIsPTRing(false) 125 + }, [refetch, setIsPTRing]) 112 126 113 - const onEndReached = React.useCallback(async () => { 114 - if (isFetchingNextPage || !hasNextPage || isError) return 115 - try { 116 - await fetchNextPage() 117 - } catch (err) { 118 - logger.error('Failed to load more lists', {message: err}) 119 - } 120 - }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage]) 127 + const onEndReached = useCallback(async () => { 128 + if (isFetchingNextPage || !hasNextPage || isError) return 129 + try { 130 + await fetchNextPage() 131 + } catch (err) { 132 + logger.error('Failed to load more lists', {message: err}) 133 + } 134 + }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage]) 121 135 122 - const onPressRetryLoadMore = React.useCallback(() => { 123 - fetchNextPage() 124 - }, [fetchNextPage]) 136 + const onPressRetryLoadMore = useCallback(() => { 137 + fetchNextPage() 138 + }, [fetchNextPage]) 125 139 126 - // rendering 127 - // = 140 + // rendering 141 + // = 128 142 129 - const renderItemInner = React.useCallback( 130 - ({item, index}: ListRenderItemInfo<any>) => { 131 - if (item === EMPTY) { 132 - return ( 133 - <EmptyState 134 - icon="list-ul" 135 - message={_(msg`You have no lists.`)} 136 - testID="listsEmpty" 137 - /> 138 - ) 139 - } else if (item === ERROR_ITEM) { 140 - return ( 141 - <ErrorMessage 142 - message={cleanError(error)} 143 - onPressTryAgain={refetch} 144 - /> 145 - ) 146 - } else if (item === LOAD_MORE_ERROR_ITEM) { 147 - return ( 148 - <LoadMoreRetryBtn 149 - label={_( 150 - msg`There was an issue fetching your lists. Tap here to try again.`, 151 - )} 152 - onPress={onPressRetryLoadMore} 153 - /> 154 - ) 155 - } else if (item === LOADING) { 156 - return <FeedLoadingPlaceholder /> 157 - } 143 + const renderItemInner = useCallback( 144 + ({item, index}: ListRenderItemInfo<any>) => { 145 + if (item === EMPTY) { 158 146 return ( 159 - <View 160 - style={[ 161 - (index !== 0 || isWeb) && a.border_t, 162 - t.atoms.border_contrast_low, 163 - a.px_lg, 164 - a.py_lg, 165 - ]}> 166 - <ListCard.Default view={item} /> 167 - </View> 147 + <EmptyState 148 + icon="list-ul" 149 + message={_(msg`You have no lists.`)} 150 + testID="listsEmpty" 151 + /> 168 152 ) 169 - }, 170 - [error, refetch, onPressRetryLoadMore, _, t.atoms.border_contrast_low], 171 - ) 172 - 173 - React.useEffect(() => { 174 - if (isIOS && enabled && scrollElRef.current) { 175 - const nativeTag = findNodeHandle(scrollElRef.current) 176 - setScrollViewTag(nativeTag) 153 + } else if (item === ERROR_ITEM) { 154 + return ( 155 + <ErrorMessage message={cleanError(error)} onPressTryAgain={refetch} /> 156 + ) 157 + } else if (item === LOAD_MORE_ERROR_ITEM) { 158 + return ( 159 + <LoadMoreRetryBtn 160 + label={_( 161 + msg`There was an issue fetching your lists. Tap here to try again.`, 162 + )} 163 + onPress={onPressRetryLoadMore} 164 + /> 165 + ) 166 + } else if (item === LOADING) { 167 + return <FeedLoadingPlaceholder /> 177 168 } 178 - }, [enabled, scrollElRef, setScrollViewTag]) 179 - 180 - const ProfileListsFooter = React.useCallback(() => { 181 - if (isEmpty) return null 182 169 return ( 183 - <ListFooter 184 - hasNextPage={hasNextPage} 185 - isFetchingNextPage={isFetchingNextPage} 186 - onRetry={fetchNextPage} 187 - error={cleanError(error)} 188 - height={180 + headerOffset} 189 - /> 170 + <View 171 + style={[ 172 + (index !== 0 || isWeb) && a.border_t, 173 + t.atoms.border_contrast_low, 174 + a.px_lg, 175 + a.py_lg, 176 + ]}> 177 + <ListCard.Default view={item} /> 178 + </View> 190 179 ) 191 - }, [ 192 - hasNextPage, 193 - error, 194 - isFetchingNextPage, 195 - headerOffset, 196 - fetchNextPage, 197 - isEmpty, 198 - ]) 180 + }, 181 + [error, refetch, onPressRetryLoadMore, _, t.atoms.border_contrast_low], 182 + ) 183 + 184 + useEffect(() => { 185 + if (isIOS && enabled && scrollElRef.current) { 186 + const nativeTag = findNodeHandle(scrollElRef.current) 187 + setScrollViewTag(nativeTag) 188 + } 189 + }, [enabled, scrollElRef, setScrollViewTag]) 199 190 191 + const ProfileListsFooter = useCallback(() => { 192 + if (isEmpty) return null 200 193 return ( 201 - <View testID={testID} style={style}> 202 - <List 203 - testID={testID ? `${testID}-flatlist` : undefined} 204 - ref={scrollElRef} 205 - data={items} 206 - keyExtractor={keyExtractor} 207 - renderItem={renderItemInner} 208 - ListFooterComponent={ProfileListsFooter} 209 - refreshing={isPTRing} 210 - onRefresh={onRefresh} 211 - headerOffset={headerOffset} 212 - progressViewOffset={ios(0)} 213 - removeClippedSubviews={true} 214 - desktopFixedHeight 215 - onEndReached={onEndReached} 216 - /> 217 - </View> 194 + <ListFooter 195 + hasNextPage={hasNextPage} 196 + isFetchingNextPage={isFetchingNextPage} 197 + onRetry={fetchNextPage} 198 + error={cleanError(error)} 199 + height={180 + headerOffset} 200 + /> 218 201 ) 219 - }, 220 - ) 202 + }, [ 203 + hasNextPage, 204 + error, 205 + isFetchingNextPage, 206 + headerOffset, 207 + fetchNextPage, 208 + isEmpty, 209 + ]) 210 + 211 + return ( 212 + <View testID={testID} style={style}> 213 + <List 214 + testID={testID ? `${testID}-flatlist` : undefined} 215 + ref={scrollElRef} 216 + data={items} 217 + keyExtractor={keyExtractor} 218 + renderItem={renderItemInner} 219 + ListFooterComponent={ProfileListsFooter} 220 + refreshing={isPTRing} 221 + onRefresh={onRefresh} 222 + headerOffset={headerOffset} 223 + progressViewOffset={ios(0)} 224 + removeClippedSubviews={true} 225 + desktopFixedHeight 226 + onEndReached={onEndReached} 227 + contentContainerStyle={{minHeight: height + headerOffset}} 228 + /> 229 + </View> 230 + ) 231 + } 221 232 222 233 function keyExtractor(item: any) { 223 234 return item._reactKey || item.uri
+3 -3
src/view/com/modals/InviteCodes.tsx
··· 6 6 View, 7 7 } from 'react-native' 8 8 import {setStringAsync} from 'expo-clipboard' 9 - import {ComAtprotoServerDefs} from '@atproto/api' 9 + import {type ComAtprotoServerDefs} from '@atproto/api' 10 10 import { 11 11 FontAwesomeIcon, 12 - FontAwesomeIconStyle, 12 + type FontAwesomeIconStyle, 13 13 } from '@fortawesome/react-native-fontawesome' 14 14 import {msg, Trans} from '@lingui/macro' 15 15 import {useLingui} from '@lingui/react' ··· 22 22 import {useInvitesAPI, useInvitesState} from '#/state/invites' 23 23 import {useModalControls} from '#/state/modals' 24 24 import { 25 - InviteCodesQueryResponse, 25 + type InviteCodesQueryResponse, 26 26 useInviteCodesQuery, 27 27 } from '#/state/queries/invites' 28 28 import {ErrorMessage} from '../util/error/ErrorMessage'
+2 -2
src/view/com/modals/UserAddRemoveLists.tsx
··· 5 5 useWindowDimensions, 6 6 View, 7 7 } from 'react-native' 8 - import {AppBskyGraphDefs as GraphDefs} from '@atproto/api' 8 + import {type AppBskyGraphDefs as GraphDefs} from '@atproto/api' 9 9 import {msg, Trans} from '@lingui/macro' 10 10 import {useLingui} from '@lingui/react' 11 11 ··· 18 18 import {useModalControls} from '#/state/modals' 19 19 import { 20 20 getMembership, 21 - ListMembersip, 21 + type ListMembersip, 22 22 useDangerousListMembershipsQuery, 23 23 useListMembershipAddMutation, 24 24 useListMembershipRemoveMutation,
+1 -1
src/view/com/notifications/NotificationFeedItem.tsx
··· 250 250 : '' 251 251 252 252 let a11yLabel = '' 253 - let notificationContent: ReactElement 253 + let notificationContent: ReactElement<any> 254 254 let icon = ( 255 255 <HeartIconFilled 256 256 size="xl"
+1
src/view/com/pager/Pager.tsx
··· 1 1 import { 2 + type JSX, 2 3 memo, 3 4 useCallback, 4 5 useContext,
+1
src/view/com/pager/Pager.web.tsx
··· 1 1 import { 2 2 Children, 3 + type JSX, 3 4 useCallback, 4 5 useImperativeHandle, 5 6 useRef,
+1 -1
src/view/com/pager/PagerWithHeader.tsx
··· 1 - import {memo, useCallback, useEffect, useRef, useState} from 'react' 1 + import {type JSX, memo, useCallback, useEffect, useRef, useState} from 'react' 2 2 import { 3 3 type LayoutChangeEvent, 4 4 type NativeScrollEvent,
+8 -3
src/view/com/pager/PagerWithHeader.web.tsx
··· 1 1 import * as React from 'react' 2 - import {ScrollView, View} from 'react-native' 2 + import {type JSX} from 'react' 3 + import {type ScrollView, View} from 'react-native' 3 4 import {useAnimatedRef} from 'react-native-reanimated' 4 5 5 - import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager' 6 + import { 7 + Pager, 8 + type PagerRef, 9 + type RenderTabBarFnProps, 10 + } from '#/view/com/pager/Pager' 6 11 import {atoms as a, web} from '#/alf' 7 12 import * as Layout from '#/components/Layout' 8 - import {ListMethods} from '../util/List' 13 + import {type ListMethods} from '../util/List' 9 14 import {TabBar} from './TabBar' 10 15 11 16 export interface PagerWithHeaderChildParams {
+3 -1
src/view/com/pager/TabBar.web.tsx
··· 106 106 <PressableWithHover 107 107 testID={`${testID}-selector-${i}`} 108 108 key={`${item}-${i}`} 109 - ref={node => (itemRefs.current[i] = node as any)} 109 + ref={node => { 110 + itemRefs.current[i] = node as any 111 + }} 110 112 style={styles.item} 111 113 hoverStyle={t.atoms.bg_contrast_25} 112 114 onPress={() => onPressItem(i)}
+1 -1
src/view/com/post-thread/PostLikedBy.tsx
··· 1 1 import {useCallback, useMemo, useState} from 'react' 2 - import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api' 2 + import {type AppBskyFeedGetLikes as GetLikes} from '@atproto/api' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5
+2 -2
src/view/com/post-thread/PostQuotes.tsx
··· 1 1 import {useCallback, useState} from 'react' 2 2 import { 3 - AppBskyFeedDefs, 3 + type AppBskyFeedDefs, 4 4 AppBskyFeedPost, 5 5 moderatePost, 6 - ModerationDecision, 6 + type ModerationDecision, 7 7 } from '@atproto/api' 8 8 import {msg} from '@lingui/macro' 9 9 import {useLingui} from '@lingui/react'
+1 -1
src/view/com/post-thread/PostRepostedBy.tsx
··· 1 1 import {useCallback, useMemo, useState} from 'react' 2 - import {AppBskyActorDefs as ActorDefs} from '@atproto/api' 2 + import {type AppBskyActorDefs as ActorDefs} from '@atproto/api' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5
+2 -2
src/view/com/posts/CustomFeedEmptyState.tsx
··· 2 2 import {StyleSheet, View} from 'react-native' 3 3 import { 4 4 FontAwesomeIcon, 5 - FontAwesomeIconStyle, 5 + type FontAwesomeIconStyle, 6 6 } from '@fortawesome/react-native-fontawesome' 7 7 import {Trans} from '@lingui/macro' 8 8 import {useNavigation} from '@react-navigation/native' 9 9 10 10 import {usePalette} from '#/lib/hooks/usePalette' 11 11 import {MagnifyingGlassIcon} from '#/lib/icons' 12 - import {NavigationProp} from '#/lib/routes/types' 12 + import {type NavigationProp} from '#/lib/routes/types' 13 13 import {s} from '#/lib/styles' 14 14 import {isWeb} from '#/platform/detection' 15 15 import {Button} from '../util/forms/Button'
+2 -2
src/view/com/posts/FollowingEmptyState.tsx
··· 2 2 import {StyleSheet, View} from 'react-native' 3 3 import { 4 4 FontAwesomeIcon, 5 - FontAwesomeIconStyle, 5 + type FontAwesomeIconStyle, 6 6 } from '@fortawesome/react-native-fontawesome' 7 7 import {Trans} from '@lingui/macro' 8 8 import {useNavigation} from '@react-navigation/native' 9 9 10 10 import {usePalette} from '#/lib/hooks/usePalette' 11 11 import {MagnifyingGlassIcon} from '#/lib/icons' 12 - import {NavigationProp} from '#/lib/routes/types' 12 + import {type NavigationProp} from '#/lib/routes/types' 13 13 import {s} from '#/lib/styles' 14 14 import {isWeb} from '#/platform/detection' 15 15 import {Button} from '../util/forms/Button'
+2 -2
src/view/com/posts/FollowingEndOfFeed.tsx
··· 2 2 import {Dimensions, StyleSheet, View} from 'react-native' 3 3 import { 4 4 FontAwesomeIcon, 5 - FontAwesomeIconStyle, 5 + type FontAwesomeIconStyle, 6 6 } from '@fortawesome/react-native-fontawesome' 7 7 import {Trans} from '@lingui/macro' 8 8 import {useNavigation} from '@react-navigation/native' 9 9 10 10 import {usePalette} from '#/lib/hooks/usePalette' 11 - import {NavigationProp} from '#/lib/routes/types' 11 + import {type NavigationProp} from '#/lib/routes/types' 12 12 import {s} from '#/lib/styles' 13 13 import {isWeb} from '#/platform/detection' 14 14 import {Button} from '../util/forms/Button'
+9 -1
src/view/com/posts/PostFeed.tsx
··· 1 - import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react' 1 + import { 2 + type JSX, 3 + memo, 4 + useCallback, 5 + useEffect, 6 + useMemo, 7 + useRef, 8 + useState, 9 + } from 'react' 2 10 import { 3 11 ActivityIndicator, 4 12 AppState,
+1 -1
src/view/com/profile/ProfileFollowers.tsx
··· 1 1 import React from 'react' 2 - import {AppBskyActorDefs as ActorDefs} from '@atproto/api' 2 + import {type AppBskyActorDefs as ActorDefs} from '@atproto/api' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5
+1 -1
src/view/com/profile/ProfileFollows.tsx
··· 1 1 import React from 'react' 2 - import {AppBskyActorDefs as ActorDefs} from '@atproto/api' 2 + import {type AppBskyActorDefs as ActorDefs} from '@atproto/api' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5
+1 -1
src/view/com/util/Alert.web.tsx
··· 1 - import {AlertButton, AlertStatic} from 'react-native' 1 + import {type AlertButton, type AlertStatic} from 'react-native' 2 2 3 3 class WebAlert implements Pick<AlertStatic, 'alert'> { 4 4 public alert(title: string, message?: string, buttons?: AlertButton[]): void {
+3 -2
src/view/com/util/BottomSheetCustomBackdrop.tsx
··· 1 - import React, {useMemo} from 'react' 1 + import {useMemo} from 'react' 2 2 import {TouchableWithoutFeedback} from 'react-native' 3 3 import Animated, { 4 4 Extrapolation, 5 5 interpolate, 6 6 useAnimatedStyle, 7 7 } from 'react-native-reanimated' 8 - import {BottomSheetBackdropProps} from '@discord/bottom-sheet/src' 8 + import {type BottomSheetBackdropProps} from '@discord/bottom-sheet/src' 9 9 import {msg} from '@lingui/macro' 10 10 import {useLingui} from '@lingui/react' 11 + import type React from 'react' 11 12 12 13 export function createCustomBackdrop( 13 14 onClose?: (() => void) | undefined,
+3 -3
src/view/com/util/EmptyState.tsx
··· 1 - import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' 2 - import {IconProp} from '@fortawesome/fontawesome-svg-core' 1 + import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native' 2 + import {type IconProp} from '@fortawesome/fontawesome-svg-core' 3 3 import { 4 4 FontAwesomeIcon, 5 - FontAwesomeIconStyle, 5 + type FontAwesomeIconStyle, 6 6 } from '@fortawesome/react-native-fontawesome' 7 7 8 8 import {usePalette} from '#/lib/hooks/usePalette'
+2 -2
src/view/com/util/EmptyStateWithButton.tsx
··· 1 1 import {StyleSheet, View} from 'react-native' 2 - import {IconProp} from '@fortawesome/fontawesome-svg-core' 2 + import {type IconProp} from '@fortawesome/fontawesome-svg-core' 3 3 import { 4 4 FontAwesomeIcon, 5 - FontAwesomeIconStyle, 5 + type FontAwesomeIconStyle, 6 6 } from '@fortawesome/react-native-fontawesome' 7 7 8 8 import {usePalette} from '#/lib/hooks/usePalette'
+2 -2
src/view/com/util/ErrorBoundary.tsx
··· 1 - import {Component, ErrorInfo, ReactNode} from 'react' 2 - import {StyleProp, ViewStyle} from 'react-native' 1 + import {Component, type ErrorInfo, type ReactNode} from 'react' 2 + import {type StyleProp, type ViewStyle} from 'react-native' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5
-1
src/view/com/util/EventStopper.tsx
··· 1 1 import {View, type ViewStyle} from 'react-native' 2 - import type React from 'react' 3 2 4 3 /** 5 4 * This utility function captures events and stops
+2 -2
src/view/com/util/FeedInfoText.tsx
··· 1 - import {StyleProp, StyleSheet, TextStyle} from 'react-native' 1 + import {type StyleProp, StyleSheet, type TextStyle} from 'react-native' 2 2 3 3 import {sanitizeDisplayName} from '#/lib/strings/display-names' 4 - import {TypographyVariant} from '#/lib/ThemeContext' 4 + import {type TypographyVariant} from '#/lib/ThemeContext' 5 5 import {useFeedSourceInfoQuery} from '#/state/queries/feed' 6 6 import {TextLinkOnWebOnly} from './Link' 7 7 import {LoadingPlaceholder} from './LoadingPlaceholder'
+1 -1
src/view/com/util/Link.tsx
··· 1 - import {memo, useCallback, useMemo} from 'react' 1 + import {type JSX, memo, useCallback, useMemo} from 'react' 2 2 import { 3 3 type GestureResponderEvent, 4 4 Platform,
+1 -1
src/view/com/util/List.tsx
··· 57 57 ...props 58 58 }, 59 59 ref, 60 - ): React.ReactElement => { 60 + ): React.ReactElement<any> => { 61 61 const isScrolledDown = useSharedValue(false) 62 62 const t = useTheme() 63 63 const dedupe = useDedupe(400)
+13 -6
src/view/com/util/List.web.tsx
··· 1 - import React, {isValidElement, memo, startTransition, useRef} from 'react' 1 + import React, { 2 + isValidElement, 3 + type JSX, 4 + memo, 5 + startTransition, 6 + useRef, 7 + } from 'react' 2 8 import { 3 9 type FlatListProps, 4 10 StyleSheet, ··· 202 208 behavior: animated ? 'smooth' : 'instant', 203 209 }) 204 210 }, 211 + 205 212 scrollToEnd({animated = true}: {animated?: boolean}) { 206 213 const element = getScrollableNode() 207 214 element?.scrollTo({ ··· 382 389 containerRef, 383 390 onVisibleChange, 384 391 }: { 385 - root?: React.RefObject<HTMLDivElement> | null 392 + root?: React.RefObject<HTMLDivElement | null> | null 386 393 topMargin?: string 387 394 bottomMargin?: string 388 - containerRef: React.RefObject<Element> 395 + containerRef: React.RefObject<Element | null> 389 396 onVisibleChange: (isVisible: boolean) => void 390 397 }) { 391 398 const [containerHeight, setContainerHeight] = React.useState(0) ··· 404 411 } 405 412 406 413 function useResizeObserver( 407 - ref: React.RefObject<Element>, 414 + ref: React.RefObject<Element | null>, 408 415 onResize: undefined | ((w: number, h: number) => void), 409 416 ) { 410 417 const handleResize = useNonReactiveCallback(onResize ?? (() => {})) ··· 509 516 onVisibleChange, 510 517 style, 511 518 }: { 512 - root?: React.RefObject<HTMLDivElement> | null 519 + root?: React.RefObject<HTMLDivElement | null> | null 513 520 topMargin?: string 514 521 bottomMargin?: string 515 522 onVisibleChange: (isVisible: boolean) => void ··· 551 558 552 559 export const List = memo(React.forwardRef(ListImpl)) as <ItemT>( 553 560 props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>}, 554 - ) => React.ReactElement 561 + ) => React.ReactElement<any> 555 562 556 563 // https://stackoverflow.com/questions/7944460/detect-safari-browser 557 564
+1 -1
src/view/com/util/LoadMoreRetryBtn.tsx
··· 1 1 import {StyleSheet} from 'react-native' 2 2 import { 3 3 FontAwesomeIcon, 4 - FontAwesomeIconStyle, 4 + type FontAwesomeIconStyle, 5 5 } from '@fortawesome/react-native-fontawesome' 6 6 7 7 import {usePalette} from '#/lib/hooks/usePalette'
-17
src/view/com/util/LoadingScreen.tsx
··· 1 - import {ActivityIndicator, View} from 'react-native' 2 - 3 - import {s} from '#/lib/styles' 4 - import * as Layout from '#/components/Layout' 5 - 6 - /** 7 - * @deprecated use Layout compoenents directly 8 - */ 9 - export function LoadingScreen() { 10 - return ( 11 - <Layout.Content> 12 - <View style={s.p20}> 13 - <ActivityIndicator size="large" /> 14 - </View> 15 - </Layout.Content> 16 - ) 17 - }
+1 -1
src/view/com/util/MainScrollProvider.tsx
··· 1 1 import React, {useCallback, useEffect} from 'react' 2 - import {NativeScrollEvent} from 'react-native' 2 + import {type NativeScrollEvent} from 'react-native' 3 3 import {interpolate, useSharedValue, withSpring} from 'react-native-reanimated' 4 4 import EventEmitter from 'eventemitter3' 5 5
-1
src/view/com/util/PostMeta.tsx
··· 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 import {useQueryClient} from '@tanstack/react-query' 7 - import type React from 'react' 8 7 9 8 import {useActorStatus} from '#/lib/actor-status' 10 9 import {makeProfileLink} from '#/lib/routes/links'
+8 -3
src/view/com/util/PressableWithHover.tsx
··· 1 - import {forwardRef, PropsWithChildren} from 'react' 2 - import {Pressable, PressableProps, StyleProp, ViewStyle} from 'react-native' 3 - import {View} from 'react-native' 1 + import {forwardRef, type PropsWithChildren} from 'react' 2 + import { 3 + Pressable, 4 + type PressableProps, 5 + type StyleProp, 6 + type ViewStyle, 7 + } from 'react-native' 8 + import {type View} from 'react-native' 4 9 5 10 import {addStyle} from '#/lib/styles' 6 11 import {useInteractionState} from '#/components/hooks/useInteractionState'
+2 -2
src/view/com/util/TimeElapsed.tsx
··· 1 - import React from 'react' 2 - import {I18n} from '@lingui/core' 1 + import React, {type JSX} from 'react' 2 + import {type I18n} from '@lingui/core' 3 3 import {useLingui} from '@lingui/react' 4 4 5 5 import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
+13 -7
src/view/com/util/UserAvatar.tsx
··· 1 - import React, {memo, useCallback, useMemo, useState} from 'react' 1 + import {memo, useCallback, useMemo, useState} from 'react' 2 2 import { 3 3 Image, 4 4 Pressable, ··· 375 375 } 376 376 }, [circular, size]) 377 377 378 - const onOpenCamera = React.useCallback(async () => { 378 + const onOpenCamera = useCallback(async () => { 379 379 if (!(await requestCameraAccessIfNeeded())) { 380 380 return 381 381 } ··· 389 389 ) 390 390 }, [onSelectNewAvatar, requestCameraAccessIfNeeded]) 391 391 392 - const onOpenLibrary = React.useCallback(async () => { 392 + const onOpenLibrary = useCallback(async () => { 393 393 if (!(await requestPhotoAccessIfNeeded())) { 394 394 return 395 395 } ··· 433 433 circular, 434 434 ]) 435 435 436 - const onRemoveAvatar = React.useCallback(() => { 436 + const onRemoveAvatar = useCallback(() => { 437 437 onSelectNewAvatar(null) 438 438 }, [onSelectNewAvatar]) 439 439 ··· 542 542 disableNavigation, 543 543 onBeforePress, 544 544 live, 545 - ...rest 545 + ...props 546 546 }: PreviewableUserAvatarProps): React.ReactNode => { 547 547 const {_} = useLingui() 548 548 const queryClient = useQueryClient() ··· 571 571 moderation={moderation} 572 572 type={profile.associated?.labeler ? 'labeler' : 'user'} 573 573 live={status.isActive || live} 574 - {...rest} 574 + {...props} 575 575 /> 576 576 ) 577 + 578 + const linkStyle = 579 + props.type !== 'algo' && props.type !== 'list' 580 + ? a.rounded_full 581 + : {borderRadius: props.size > 32 ? 8 : 3} 577 582 578 583 return ( 579 584 <ProfileHoverCard did={profile.did} disable={disableHoverCard}> ··· 610 615 did: profile.did, 611 616 handle: profile.handle, 612 617 })} 613 - onPress={onPress}> 618 + onPress={onPress} 619 + style={linkStyle}> 614 620 {avatarEl} 615 621 </Link> 616 622 )}
+2
src/view/com/util/ViewHeader.tsx
··· 1 + import {type JSX} from 'react' 2 + 1 3 import {Header} from '#/components/Layout' 2 4 3 5 /**
+4 -4
src/view/com/util/ViewSelector.tsx
··· 1 - import React, {useEffect, useState} from 'react' 1 + import React, {type JSX, useEffect, useState} from 'react' 2 2 import { 3 - NativeScrollEvent, 4 - NativeSyntheticEvent, 3 + type NativeScrollEvent, 4 + type NativeSyntheticEvent, 5 5 Pressable, 6 6 RefreshControl, 7 7 ScrollView, ··· 36 36 renderItem: (item: any) => JSX.Element 37 37 ListFooterComponent?: 38 38 | React.ComponentType<any> 39 - | React.ReactElement 39 + | React.ReactElement<any> 40 40 | null 41 41 | undefined 42 42 onSelectView?: (viewIndex: number) => void
+3 -3
src/view/com/util/Views.tsx
··· 1 1 import {forwardRef} from 'react' 2 - import {FlatListComponent} from 'react-native' 3 - import {View, ViewProps} from 'react-native' 2 + import {type FlatListComponent} from 'react-native' 3 + import {View, type ViewProps} from 'react-native' 4 4 import Animated from 'react-native-reanimated' 5 - import {FlatListPropsWithLayout} from 'react-native-reanimated' 5 + import {type FlatListPropsWithLayout} from 'react-native-reanimated' 6 6 7 7 // If you explode these into functions, don't forget to forwardRef! 8 8
+1 -1
src/view/com/util/WebAuxClickWrapper.tsx
··· 1 - import React from 'react' 2 1 import {Platform} from 'react-native' 2 + import type React from 'react' 3 3 4 4 const onMouseUp = (e: React.MouseEvent & {target: HTMLElement}) => { 5 5 // Only handle whenever it is the middle button
+3 -3
src/view/com/util/error/ErrorMessage.tsx
··· 1 1 import { 2 - StyleProp, 2 + type StyleProp, 3 3 StyleSheet, 4 4 TouchableOpacity, 5 5 View, 6 - ViewStyle, 6 + type ViewStyle, 7 7 } from 'react-native' 8 8 import { 9 9 FontAwesomeIcon, 10 - FontAwesomeIconStyle, 10 + type FontAwesomeIconStyle, 11 11 } from '@fortawesome/react-native-fontawesome' 12 12 import {msg} from '@lingui/macro' 13 13 import {useLingui} from '@lingui/react'
+1 -1
src/view/com/util/error/ErrorScreen.tsx
··· 1 1 import {View} from 'react-native' 2 2 import { 3 3 FontAwesomeIcon, 4 - FontAwesomeIconStyle, 4 + type FontAwesomeIconStyle, 5 5 } from '@fortawesome/react-native-fontawesome' 6 6 import {msg, Trans} from '@lingui/macro' 7 7 import {useLingui} from '@lingui/react'
+1 -1
src/view/com/util/fab/FAB.web.tsx
··· 1 1 import {View} from 'react-native' 2 2 3 3 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 4 - import {FABInner, FABProps} from './FABInner' 4 + import {FABInner, type FABProps} from './FABInner' 5 5 6 6 export const FAB = (_opts: FABProps) => { 7 7 const {isDesktop} = useWebMediaQueries()
+12 -5
src/view/com/util/fab/FABInner.tsx
··· 1 - import {ComponentProps} from 'react' 2 - import {StyleSheet, TouchableWithoutFeedback} from 'react-native' 1 + import {type ComponentProps, type JSX} from 'react' 2 + import { 3 + type Pressable, 4 + type StyleProp, 5 + StyleSheet, 6 + type ViewStyle, 7 + } from 'react-native' 3 8 import Animated from 'react-native-reanimated' 4 9 import {useSafeAreaInsets} from 'react-native-safe-area-context' 5 10 import {LinearGradient} from 'expo-linear-gradient' ··· 12 17 import {gradients} from '#/lib/styles' 13 18 import {isWeb} from '#/platform/detection' 14 19 import {ios} from '#/alf' 20 + import {atoms as a} from '#/alf' 15 21 16 - export interface FABProps 17 - extends ComponentProps<typeof TouchableWithoutFeedback> { 22 + export interface FABProps extends ComponentProps<typeof Pressable> { 18 23 testID?: string 19 24 icon: JSX.Element 25 + style?: StyleProp<ViewStyle> 20 26 } 21 27 22 - export function FABInner({testID, icon, onPress, ...props}: FABProps) { 28 + export function FABInner({testID, icon, onPress, style, ...props}: FABProps) { 23 29 const insets = useSafeAreaInsets() 24 30 const {isMobile, isTablet} = useWebMediaQueries() 25 31 const playHaptic = useHaptics() ··· 51 57 playHaptic('Heavy') 52 58 })} 53 59 targetScale={0.9} 60 + style={[a.rounded_full, style]} 54 61 {...props}> 55 62 <LinearGradient 56 63 colors={[gradients.blueLight.start, gradients.blueLight.end]}
+1 -1
src/view/com/util/forms/NativeDropdown.web.tsx
··· 161 161 menuRef, 162 162 }: { 163 163 items: DropdownItem[] 164 - menuRef: React.RefObject<HTMLDivElement> 164 + menuRef: React.RefObject<HTMLDivElement | null> 165 165 }) { 166 166 const pal = usePalette('default') 167 167 const theme = useTheme()
-1
src/view/com/util/images/Gallery.tsx
··· 4 4 import {type AppBskyEmbedImages} from '@atproto/api' 5 5 import {msg} from '@lingui/macro' 6 6 import {useLingui} from '@lingui/react' 7 - import type React from 'react' 8 7 9 8 import {type Dimensions} from '#/lib/media/types' 10 9 import {
+1 -1
src/view/com/util/images/Image.tsx
··· 1 - import {Image, ImageProps, ImageSource} from 'expo-image' 1 + import {Image, type ImageProps, type ImageSource} from 'expo-image' 2 2 3 3 interface HighPriorityImageProps extends ImageProps { 4 4 source: ImageSource
+1 -1
src/view/com/util/layouts/LoggedOutLayout.tsx
··· 1 - import React from 'react' 2 1 import {ScrollView, StyleSheet, View} from 'react-native' 2 + import type React from 'react' 3 3 4 4 import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle' 5 5 import {useIsKeyboardVisible} from '#/lib/hooks/useIsKeyboardVisible'
+1 -1
src/view/icons/Logomark.tsx
··· 1 - import Svg, {Path, PathProps, SvgProps} from 'react-native-svg' 1 + import Svg, {Path, type PathProps, type SvgProps} from 'react-native-svg' 2 2 3 3 import {usePalette} from '#/lib/hooks/usePalette' 4 4
+4 -1
src/view/screens/CommunityGuidelines.tsx
··· 5 5 import {useFocusEffect} from '@react-navigation/native' 6 6 7 7 import {usePalette} from '#/lib/hooks/usePalette' 8 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 8 + import { 9 + type CommonNavigatorParams, 10 + type NativeStackScreenProps, 11 + } from '#/lib/routes/types' 9 12 import {s} from '#/lib/styles' 10 13 import {useSetMinimalShellMode} from '#/state/shell' 11 14 import {TextLink} from '#/view/com/util/Link'
+4 -1
src/view/screens/CopyrightPolicy.tsx
··· 5 5 import {useFocusEffect} from '@react-navigation/native' 6 6 7 7 import {usePalette} from '#/lib/hooks/usePalette' 8 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 8 + import { 9 + type CommonNavigatorParams, 10 + type NativeStackScreenProps, 11 + } from '#/lib/routes/types' 9 12 import {s} from '#/lib/styles' 10 13 import {useSetMinimalShellMode} from '#/state/shell' 11 14 import {TextLink} from '#/view/com/util/Link'
+1 -1
src/view/screens/NotFound.tsx
··· 9 9 } from '@react-navigation/native' 10 10 11 11 import {usePalette} from '#/lib/hooks/usePalette' 12 - import {NavigationProp} from '#/lib/routes/types' 12 + import {type NavigationProp} from '#/lib/routes/types' 13 13 import {s} from '#/lib/styles' 14 14 import {useSetMinimalShellMode} from '#/state/shell' 15 15 import {Button} from '#/view/com/util/forms/Button'
+4 -1
src/view/screens/ProfileFeedLikedBy.tsx
··· 3 3 import {useLingui} from '@lingui/react' 4 4 import {useFocusEffect} from '@react-navigation/native' 5 5 6 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 6 + import { 7 + type CommonNavigatorParams, 8 + type NativeStackScreenProps, 9 + } from '#/lib/routes/types' 7 10 import {makeRecordUri} from '#/lib/strings/url-helpers' 8 11 import {useSetMinimalShellMode} from '#/state/shell' 9 12 import {PostLikedBy as PostLikedByComponent} from '#/view/com/post-thread/PostLikedBy'
-450
src/view/screens/SavedFeeds.tsx
··· 1 - import React from 'react' 2 - import {ActivityIndicator, Pressable, StyleSheet, View} from 'react-native' 3 - import Animated, {LinearTransition} from 'react-native-reanimated' 4 - import {type AppBskyActorDefs} from '@atproto/api' 5 - import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 6 - import {msg, Trans} from '@lingui/macro' 7 - import {useLingui} from '@lingui/react' 8 - import {useFocusEffect} from '@react-navigation/native' 9 - import {useNavigation} from '@react-navigation/native' 10 - import {type NativeStackScreenProps} from '@react-navigation/native-stack' 11 - 12 - import {useHaptics} from '#/lib/haptics' 13 - import {usePalette} from '#/lib/hooks/usePalette' 14 - import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 15 - import { 16 - type CommonNavigatorParams, 17 - type NavigationProp, 18 - } from '#/lib/routes/types' 19 - import {colors, s} from '#/lib/styles' 20 - import {logger} from '#/logger' 21 - import { 22 - useOverwriteSavedFeedsMutation, 23 - usePreferencesQuery, 24 - } from '#/state/queries/preferences' 25 - import {type UsePreferencesQueryResponse} from '#/state/queries/preferences/types' 26 - import {useSetMinimalShellMode} from '#/state/shell' 27 - import {FeedSourceCard} from '#/view/com/feeds/FeedSourceCard' 28 - import {TextLink} from '#/view/com/util/Link' 29 - import {Text} from '#/view/com/util/text/Text' 30 - import * as Toast from '#/view/com/util/Toast' 31 - import {NoFollowingFeed} from '#/screens/Feeds/NoFollowingFeed' 32 - import {NoSavedFeedsOfAnyType} from '#/screens/Feeds/NoSavedFeedsOfAnyType' 33 - import {atoms as a, useTheme} from '#/alf' 34 - import {Button, ButtonIcon, ButtonText} from '#/components/Button' 35 - import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline' 36 - import {FloppyDisk_Stroke2_Corner0_Rounded as SaveIcon} from '#/components/icons/FloppyDisk' 37 - import * as Layout from '#/components/Layout' 38 - import {Loader} from '#/components/Loader' 39 - import {Text as NewText} from '#/components/Typography' 40 - 41 - type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'> 42 - export function SavedFeeds({}: Props) { 43 - const {data: preferences} = usePreferencesQuery() 44 - if (!preferences) { 45 - return <View /> 46 - } 47 - return <SavedFeedsInner preferences={preferences} /> 48 - } 49 - 50 - function SavedFeedsInner({ 51 - preferences, 52 - }: { 53 - preferences: UsePreferencesQueryResponse 54 - }) { 55 - const pal = usePalette('default') 56 - const {_} = useLingui() 57 - const {isMobile, isDesktop} = useWebMediaQueries() 58 - const setMinimalShellMode = useSetMinimalShellMode() 59 - const {mutateAsync: overwriteSavedFeeds, isPending: isOverwritePending} = 60 - useOverwriteSavedFeedsMutation() 61 - const navigation = useNavigation<NavigationProp>() 62 - 63 - /* 64 - * Use optimistic data if exists and no error, otherwise fallback to remote 65 - * data 66 - */ 67 - const [currentFeeds, setCurrentFeeds] = React.useState( 68 - () => preferences.savedFeeds || [], 69 - ) 70 - const hasUnsavedChanges = currentFeeds !== preferences.savedFeeds 71 - const pinnedFeeds = currentFeeds.filter(f => f.pinned) 72 - const unpinnedFeeds = currentFeeds.filter(f => !f.pinned) 73 - const noSavedFeedsOfAnyType = pinnedFeeds.length + unpinnedFeeds.length === 0 74 - const noFollowingFeed = 75 - currentFeeds.every(f => f.type !== 'timeline') && !noSavedFeedsOfAnyType 76 - 77 - useFocusEffect( 78 - React.useCallback(() => { 79 - setMinimalShellMode(false) 80 - }, [setMinimalShellMode]), 81 - ) 82 - 83 - const onSaveChanges = React.useCallback(async () => { 84 - try { 85 - await overwriteSavedFeeds(currentFeeds) 86 - Toast.show(_(msg({message: 'Feeds updated!', context: 'toast'}))) 87 - if (navigation.canGoBack()) { 88 - navigation.goBack() 89 - } else { 90 - navigation.navigate('Feeds') 91 - } 92 - } catch (e) { 93 - Toast.show(_(msg`There was an issue contacting the server`), 'xmark') 94 - logger.error('Failed to toggle pinned feed', {message: e}) 95 - } 96 - }, [_, overwriteSavedFeeds, currentFeeds, navigation]) 97 - 98 - return ( 99 - <Layout.Screen> 100 - <Layout.Header.Outer> 101 - <Layout.Header.BackButton /> 102 - <Layout.Header.Content align="left"> 103 - <Layout.Header.TitleText> 104 - <Trans>Feeds</Trans> 105 - </Layout.Header.TitleText> 106 - </Layout.Header.Content> 107 - <Button 108 - testID="saveChangesBtn" 109 - size="small" 110 - variant={hasUnsavedChanges ? 'solid' : 'solid'} 111 - color={hasUnsavedChanges ? 'primary' : 'secondary'} 112 - onPress={onSaveChanges} 113 - label={_(msg`Save changes`)} 114 - disabled={isOverwritePending || !hasUnsavedChanges}> 115 - <ButtonIcon icon={isOverwritePending ? Loader : SaveIcon} /> 116 - <ButtonText> 117 - {isDesktop ? <Trans>Save changes</Trans> : <Trans>Save</Trans>} 118 - </ButtonText> 119 - </Button> 120 - </Layout.Header.Outer> 121 - 122 - <Layout.Content> 123 - {noSavedFeedsOfAnyType && ( 124 - <View style={[pal.border, a.border_b]}> 125 - <NoSavedFeedsOfAnyType /> 126 - </View> 127 - )} 128 - 129 - <View style={[pal.text, pal.border, styles.title]}> 130 - <Text type="title" style={pal.text}> 131 - <Trans>Pinned Feeds</Trans> 132 - </Text> 133 - </View> 134 - 135 - {preferences ? ( 136 - !pinnedFeeds.length ? ( 137 - <View 138 - style={[ 139 - pal.border, 140 - isMobile && s.flex1, 141 - pal.viewLight, 142 - styles.empty, 143 - ]}> 144 - <Text type="lg" style={[pal.text]}> 145 - <Trans>You don't have any pinned feeds.</Trans> 146 - </Text> 147 - </View> 148 - ) : ( 149 - pinnedFeeds.map(f => ( 150 - <ListItem 151 - key={f.id} 152 - feed={f} 153 - isPinned 154 - currentFeeds={currentFeeds} 155 - setCurrentFeeds={setCurrentFeeds} 156 - preferences={preferences} 157 - /> 158 - )) 159 - ) 160 - ) : ( 161 - <ActivityIndicator style={{marginTop: 20}} /> 162 - )} 163 - 164 - {noFollowingFeed && ( 165 - <View style={[pal.border, a.border_b]}> 166 - <NoFollowingFeed /> 167 - </View> 168 - )} 169 - 170 - <View style={[pal.text, pal.border, styles.title]}> 171 - <Text type="title" style={pal.text}> 172 - <Trans>Saved Feeds</Trans> 173 - </Text> 174 - </View> 175 - {preferences ? ( 176 - !unpinnedFeeds.length ? ( 177 - <View 178 - style={[ 179 - pal.border, 180 - isMobile && s.flex1, 181 - pal.viewLight, 182 - styles.empty, 183 - ]}> 184 - <Text type="lg" style={[pal.text]}> 185 - <Trans>You don't have any saved feeds.</Trans> 186 - </Text> 187 - </View> 188 - ) : ( 189 - unpinnedFeeds.map(f => ( 190 - <ListItem 191 - key={f.id} 192 - feed={f} 193 - isPinned={false} 194 - currentFeeds={currentFeeds} 195 - setCurrentFeeds={setCurrentFeeds} 196 - preferences={preferences} 197 - /> 198 - )) 199 - ) 200 - ) : ( 201 - <ActivityIndicator style={{marginTop: 20}} /> 202 - )} 203 - 204 - <View style={styles.footerText}> 205 - <Text type="sm" style={pal.textLight}> 206 - <Trans> 207 - Feeds are custom algorithms that users build with a little coding 208 - expertise.{' '} 209 - <TextLink 210 - type="sm" 211 - style={pal.link} 212 - href="https://github.com/bluesky-social/feed-generator" 213 - text={_(msg`See this guide`)} 214 - />{' '} 215 - for more information. 216 - </Trans> 217 - </Text> 218 - </View> 219 - </Layout.Content> 220 - </Layout.Screen> 221 - ) 222 - } 223 - 224 - function ListItem({ 225 - feed, 226 - isPinned, 227 - currentFeeds, 228 - setCurrentFeeds, 229 - }: { 230 - feed: AppBskyActorDefs.SavedFeed 231 - isPinned: boolean 232 - currentFeeds: AppBskyActorDefs.SavedFeed[] 233 - setCurrentFeeds: React.Dispatch<AppBskyActorDefs.SavedFeed[]> 234 - preferences: UsePreferencesQueryResponse 235 - }) { 236 - const {_} = useLingui() 237 - const pal = usePalette('default') 238 - const playHaptic = useHaptics() 239 - const feedUri = feed.value 240 - 241 - const onTogglePinned = React.useCallback(async () => { 242 - playHaptic() 243 - setCurrentFeeds( 244 - currentFeeds.map(f => 245 - f.id === feed.id ? {...feed, pinned: !feed.pinned} : f, 246 - ), 247 - ) 248 - }, [playHaptic, feed, currentFeeds, setCurrentFeeds]) 249 - 250 - const onPressUp = React.useCallback(async () => { 251 - if (!isPinned) return 252 - 253 - const nextFeeds = currentFeeds.slice() 254 - const ids = currentFeeds.map(f => f.id) 255 - const index = ids.indexOf(feed.id) 256 - const nextIndex = index - 1 257 - 258 - if (index === -1 || index === 0) return 259 - ;[nextFeeds[index], nextFeeds[nextIndex]] = [ 260 - nextFeeds[nextIndex], 261 - nextFeeds[index], 262 - ] 263 - 264 - setCurrentFeeds(nextFeeds) 265 - }, [feed, isPinned, setCurrentFeeds, currentFeeds]) 266 - 267 - const onPressDown = React.useCallback(async () => { 268 - if (!isPinned) return 269 - 270 - const nextFeeds = currentFeeds.slice() 271 - const ids = currentFeeds.map(f => f.id) 272 - const index = ids.indexOf(feed.id) 273 - const nextIndex = index + 1 274 - 275 - if (index === -1 || index >= nextFeeds.filter(f => f.pinned).length - 1) 276 - return 277 - ;[nextFeeds[index], nextFeeds[nextIndex]] = [ 278 - nextFeeds[nextIndex], 279 - nextFeeds[index], 280 - ] 281 - 282 - setCurrentFeeds(nextFeeds) 283 - }, [feed, isPinned, setCurrentFeeds, currentFeeds]) 284 - 285 - const onPressRemove = React.useCallback(async () => { 286 - playHaptic() 287 - setCurrentFeeds(currentFeeds.filter(f => f.id !== feed.id)) 288 - }, [playHaptic, feed, currentFeeds, setCurrentFeeds]) 289 - 290 - return ( 291 - <Animated.View 292 - style={[styles.itemContainer, pal.border]} 293 - layout={LinearTransition.duration(100)}> 294 - {feed.type === 'timeline' ? ( 295 - <FollowingFeedCard /> 296 - ) : ( 297 - <FeedSourceCard 298 - key={feedUri} 299 - feedUri={feedUri} 300 - style={[isPinned && a.pr_sm]} 301 - showMinimalPlaceholder 302 - hideTopBorder={true} 303 - /> 304 - )} 305 - {isPinned ? ( 306 - <> 307 - <Pressable 308 - accessibilityRole="button" 309 - onPress={onPressUp} 310 - hitSlop={5} 311 - style={state => ({ 312 - backgroundColor: pal.viewLight.backgroundColor, 313 - paddingHorizontal: 12, 314 - paddingVertical: 10, 315 - borderRadius: 4, 316 - marginRight: 8, 317 - opacity: state.hovered || state.pressed ? 0.5 : 1, 318 - })} 319 - testID={`feed-${feed.type}-moveUp`}> 320 - <FontAwesomeIcon 321 - icon="arrow-up" 322 - size={14} 323 - style={[pal.textLight]} 324 - /> 325 - </Pressable> 326 - <Pressable 327 - accessibilityRole="button" 328 - onPress={onPressDown} 329 - hitSlop={5} 330 - style={state => ({ 331 - backgroundColor: pal.viewLight.backgroundColor, 332 - paddingHorizontal: 12, 333 - paddingVertical: 10, 334 - borderRadius: 4, 335 - marginRight: 8, 336 - opacity: state.hovered || state.pressed ? 0.5 : 1, 337 - })} 338 - testID={`feed-${feed.type}-moveDown`}> 339 - <FontAwesomeIcon 340 - icon="arrow-down" 341 - size={14} 342 - style={[pal.textLight]} 343 - /> 344 - </Pressable> 345 - </> 346 - ) : ( 347 - <Pressable 348 - testID={`feed-${feedUri}-toggleSave`} 349 - accessibilityRole="button" 350 - accessibilityLabel={_(msg`Remove from my feeds`)} 351 - accessibilityHint="" 352 - onPress={onPressRemove} 353 - hitSlop={5} 354 - style={state => ({ 355 - marginRight: 8, 356 - paddingHorizontal: 12, 357 - paddingVertical: 10, 358 - borderRadius: 4, 359 - opacity: state.hovered || state.focused ? 0.5 : 1, 360 - })}> 361 - <FontAwesomeIcon 362 - icon={['far', 'trash-can']} 363 - size={19} 364 - color={pal.colors.icon} 365 - /> 366 - </Pressable> 367 - )} 368 - <View style={{paddingRight: 16}}> 369 - <Pressable 370 - accessibilityRole="button" 371 - hitSlop={5} 372 - onPress={onTogglePinned} 373 - style={state => ({ 374 - backgroundColor: pal.viewLight.backgroundColor, 375 - paddingHorizontal: 12, 376 - paddingVertical: 10, 377 - borderRadius: 4, 378 - opacity: state.hovered || state.focused ? 0.5 : 1, 379 - })} 380 - testID={`feed-${feed.type}-togglePin`}> 381 - <FontAwesomeIcon 382 - icon="thumb-tack" 383 - size={14} 384 - color={isPinned ? colors.blue3 : pal.colors.icon} 385 - /> 386 - </Pressable> 387 - </View> 388 - </Animated.View> 389 - ) 390 - } 391 - 392 - function FollowingFeedCard() { 393 - const t = useTheme() 394 - return ( 395 - <View style={[a.flex_row, a.align_center, a.flex_1, a.p_lg]}> 396 - <View 397 - style={[ 398 - a.align_center, 399 - a.justify_center, 400 - a.rounded_sm, 401 - a.mr_md, 402 - { 403 - width: 36, 404 - height: 36, 405 - backgroundColor: t.palette.primary_500, 406 - }, 407 - ]}> 408 - <FilterTimeline 409 - style={[ 410 - { 411 - width: 22, 412 - height: 22, 413 - }, 414 - ]} 415 - fill={t.palette.white} 416 - /> 417 - </View> 418 - <View style={[a.flex_1, a.flex_row, a.gap_sm, a.align_center]}> 419 - <NewText style={[a.text_sm, a.font_bold, a.leading_snug]}> 420 - <Trans context="feed-name">Following</Trans> 421 - </NewText> 422 - </View> 423 - </View> 424 - ) 425 - } 426 - 427 - const styles = StyleSheet.create({ 428 - empty: { 429 - paddingHorizontal: 20, 430 - paddingVertical: 20, 431 - borderRadius: 8, 432 - marginHorizontal: 10, 433 - marginTop: 10, 434 - }, 435 - title: { 436 - paddingHorizontal: 14, 437 - paddingTop: 20, 438 - paddingBottom: 10, 439 - borderBottomWidth: StyleSheet.hairlineWidth, 440 - }, 441 - itemContainer: { 442 - flexDirection: 'row', 443 - alignItems: 'center', 444 - borderBottomWidth: StyleSheet.hairlineWidth, 445 - }, 446 - footerText: { 447 - paddingHorizontal: 26, 448 - paddingVertical: 22, 449 - }, 450 - })
+1 -1
src/view/screens/Storybook/Dialogs.tsx
··· 22 22 React.useState<boolean>() 23 23 const [shouldRenderUnmountTest, setShouldRenderUnmountTest] = 24 24 React.useState(false) 25 - const unmountTestInterval = React.useRef<number>() 25 + const unmountTestInterval = React.useRef<number>(undefined) 26 26 27 27 const onUnmountTestStartPressWithClose = () => { 28 28 setShouldRenderUnmountTest(true)
+1 -1
src/view/screens/Storybook/ListContained.tsx
··· 2 2 import {View} from 'react-native' 3 3 4 4 import {ScrollProvider} from '#/lib/ScrollContext' 5 - import {List, ListMethods} from '#/view/com/util/List' 5 + import {List, type ListMethods} from '#/view/com/util/List' 6 6 import {Button, ButtonText} from '#/components/Button' 7 7 import * as Toggle from '#/components/forms/Toggle' 8 8 import {Text} from '#/components/Typography'
+4 -1
src/view/screens/Support.tsx
··· 5 5 6 6 import {HELP_DESK_URL} from '#/lib/constants' 7 7 import {usePalette} from '#/lib/hooks/usePalette' 8 - import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 8 + import { 9 + type CommonNavigatorParams, 10 + type NativeStackScreenProps, 11 + } from '#/lib/routes/types' 9 12 import {s} from '#/lib/styles' 10 13 import {useSetMinimalShellMode} from '#/state/shell' 11 14 import {TextLink} from '#/view/com/util/Link'
+1 -1
src/view/shell/Drawer.tsx
··· 1 - import React, {type ComponentProps} from 'react' 1 + import React, {type ComponentProps, type JSX} from 'react' 2 2 import {Linking, ScrollView, TouchableOpacity, View} from 'react-native' 3 3 import {useSafeAreaInsets} from 'react-native-safe-area-context' 4 4 import {msg, Plural, plural, Trans} from '@lingui/macro'
+1 -1
src/view/shell/bottom-bar/BottomBar.tsx
··· 1 - import {useCallback} from 'react' 1 + import {type JSX, useCallback} from 'react' 2 2 import {type GestureResponderEvent, View} from 'react-native' 3 3 import Animated from 'react-native-reanimated' 4 4 import {useSafeAreaInsets} from 'react-native-safe-area-context'
+1 -1
src/view/shell/bottom-bar/BottomBarWeb.tsx
··· 230 230 } 231 231 232 232 const NavItem: React.FC<{ 233 - children: (props: {isActive: boolean}) => React.ReactChild 233 + children: (props: {isActive: boolean}) => React.ReactNode 234 234 href: string 235 235 routeName: string 236 236 hasNew?: boolean
+1 -1
src/view/shell/desktop/LeftNav.tsx
··· 1 - import {useCallback, useMemo, useState} from 'react' 1 + import {type JSX, useCallback, useMemo, useState} from 'react' 2 2 import {StyleSheet, View} from 'react-native' 3 3 import {type AppBskyActorDefs} from '@atproto/api' 4 4 import {msg, plural, Trans} from '@lingui/macro'
+22 -41
yarn.lock
··· 7589 7589 resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" 7590 7590 integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== 7591 7591 7592 - "@types/prop-types@*": 7593 - version "15.7.5" 7594 - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" 7595 - integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== 7596 - 7597 7592 "@types/psl@^1.1.1": 7598 7593 version "1.1.1" 7599 7594 resolved "https://registry.yarnpkg.com/@types/psl/-/psl-1.1.1.tgz#3ba9e6d4bd2a32652a639fd5df7e539151d0a3b2" ··· 7609 7604 resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" 7610 7605 integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== 7611 7606 7612 - "@types/react-dom@^19.1.2": 7613 - version "19.1.3" 7614 - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.3.tgz#3f0c60804441bf34d19f8dd0d44405c0c0e21bfa" 7615 - integrity sha512-rJXC08OG0h3W6wDMFxQrZF00Kq6qQvw0djHRdzl3U5DnIERz0MRce3WVc7IS6JYBwtaP/DwYtRRjVlvivNveKg== 7607 + "@types/react-dom@^19.1.8": 7608 + version "19.1.9" 7609 + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.9.tgz#5ab695fce1e804184767932365ae6569c11b4b4b" 7610 + integrity sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ== 7616 7611 7617 - "@types/react-responsive@^8.0.5": 7618 - version "8.0.5" 7619 - resolved "https://registry.yarnpkg.com/@types/react-responsive/-/react-responsive-8.0.5.tgz#77769862d2a0711434feb972be08e3e6c334440a" 7620 - integrity sha512-k3gQJgI87oP5IrVZe//3LKJFnAeFaqqWmmtl5eoYL2H3HqFcIhUaE30kRK1CsW3DHdojZxcVj4ZNc2ClsEu2PA== 7612 + "@types/react@^19.1.12": 7613 + version "19.1.12" 7614 + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.12.tgz#7bfaa76aabbb0b4fe0493c21a3a7a93d33e8937b" 7615 + integrity sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w== 7621 7616 dependencies: 7622 - "@types/react" "*" 7623 - 7624 - "@types/react@*", "@types/react@^18": 7625 - version "18.2.20" 7626 - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.20.tgz#1605557a83df5c8a2cc4eeb743b3dfc0eb6aaeb2" 7627 - integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw== 7628 - dependencies: 7629 - "@types/prop-types" "*" 7630 - "@types/scheduler" "*" 7631 7617 csstype "^3.0.2" 7632 7618 7633 7619 "@types/retry@0.12.0": 7634 7620 version "0.12.0" 7635 7621 resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" 7636 7622 integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== 7637 - 7638 - "@types/scheduler@*": 7639 - version "0.16.3" 7640 - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" 7641 - integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== 7642 7623 7643 7624 "@types/semver@^7.3.12": 7644 7625 version "7.5.0" ··· 14515 14496 resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.5.tgz#55796b688cbd72390d2d399eaaf1832c9413e3c0" 14516 14497 integrity sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q== 14517 14498 14518 - matchmediaquery@^0.3.0: 14519 - version "0.3.1" 14520 - resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.3.1.tgz#8247edc47e499ebb7c58f62a9ff9ccf5b815c6d7" 14521 - integrity sha512-Hlk20WQHRIm9EE9luN1kjRjYXAQToHOIAHPJn9buxBwuhfTHoKUcX+lXBbxc85DVQfXYbEQ4HcwQdd128E3qHQ== 14499 + matchmediaquery@^0.4.2: 14500 + version "0.4.2" 14501 + resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.4.2.tgz#22582bd4ae63ad9f54c53001bba80cbed0f7eafa" 14502 + integrity sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA== 14522 14503 dependencies: 14523 14504 css-mediaquery "^0.1.2" 14524 14505 ··· 17124 17105 use-callback-ref "^1.3.3" 17125 17106 use-sidecar "^1.1.3" 17126 17107 17127 - react-responsive@^9.0.2: 17128 - version "9.0.2" 17129 - resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-9.0.2.tgz#34531ca77a61e7a8775714016d21241df7e4205c" 17130 - integrity sha512-+4CCab7z8G8glgJoRjAwocsgsv6VA2w7JPxFWHRc7kvz8mec1/K5LutNC2MG28Mn8mu6+bu04XZxHv5gyfT7xQ== 17108 + react-responsive@^10.0.1: 17109 + version "10.0.1" 17110 + resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-10.0.1.tgz#293d4d2562da93409861216f0110d146c5676eb3" 17111 + integrity sha512-OM5/cRvbtUWEX8le8RCT8scA8y2OPtb0Q/IViEyCEM5FBN8lRrkUOZnu87I88A6njxDldvxG+rLBxWiA7/UM9g== 17131 17112 dependencies: 17132 17113 hyphenate-style-name "^1.0.0" 17133 - matchmediaquery "^0.3.0" 17114 + matchmediaquery "^0.4.2" 17134 17115 prop-types "^15.6.1" 17135 - shallow-equal "^1.2.1" 17116 + shallow-equal "^3.1.0" 17136 17117 17137 17118 react-server-dom-webpack@~19.0.0: 17138 17119 version "19.0.0" ··· 17985 17966 resolved "https://registry.yarnpkg.com/sf-symbols-typescript/-/sf-symbols-typescript-1.0.0.tgz#94e9210bf27e7583f9749a0d07bd4f4937ea488f" 17986 17967 integrity sha512-DkS7q3nN68dEMb4E18HFPDAvyrjDZK9YAQQF2QxeFu9gp2xRDXFMF8qLJ1EmQ/qeEGQmop4lmMM1WtYJTIcCMw== 17987 17968 17988 - shallow-equal@^1.2.1: 17989 - version "1.2.1" 17990 - resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da" 17991 - integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA== 17969 + shallow-equal@^3.1.0: 17970 + version "3.1.0" 17971 + resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-3.1.0.tgz#e7a54bac629c7f248eff6c2f5b63122ba4320bec" 17972 + integrity sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg== 17992 17973 17993 17974 sharp@^0.33.5: 17994 17975 version "0.33.5"