Bluesky app fork with some witchin' additions 💫

Merge with upstream https://github.com/bluesky-social/social-app/

xan.lol 883ec190 f7056909

verified
+995 -405
+1
.gitignore
··· 128 bskyweb/static/media/*.webp 129 bskyweb/static/media/*.jpg 130 bskyweb/static/media/*.png
··· 128 bskyweb/static/media/*.webp 129 bskyweb/static/media/*.jpg 130 bskyweb/static/media/*.png 131 + bskyweb/static/media/*.svg
+1 -1
package.json
··· 1 { 2 "name": "witchsky-app", 3 - "version": "1.112.0", 4 "private": true, 5 "engines": { 6 "node": ">=18"
··· 1 { 2 "name": "witchsky-app", 3 + "version": "1.113.0", 4 "private": true, 5 "engines": { 6 "node": ">=18"
-2
src/App.native.tsx
··· 61 import {ThemeProvider as Alf} from '#/alf' 62 import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 63 import {Provider as ContextMenuProvider} from '#/components/ContextMenu' 64 - import {NuxDialogs} from '#/components/dialogs/nuxs' 65 import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry' 66 import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs' 67 import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay' ··· 165 <IntentDialogProvider> 166 <TestCtrls /> 167 <Shell /> 168 - <NuxDialogs /> 169 <ToastOutlet /> 170 </IntentDialogProvider> 171 </GlobalGestureEventsProvider>
··· 61 import {ThemeProvider as Alf} from '#/alf' 62 import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 63 import {Provider as ContextMenuProvider} from '#/components/ContextMenu' 64 import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry' 65 import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs' 66 import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay' ··· 164 <IntentDialogProvider> 165 <TestCtrls /> 166 <Shell /> 167 <ToastOutlet /> 168 </IntentDialogProvider> 169 </GlobalGestureEventsProvider>
-2
src/App.web.tsx
··· 48 import {ThemeProvider as Alf} from '#/alf' 49 import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 50 import {Provider as ContextMenuProvider} from '#/components/ContextMenu' 51 - import {NuxDialogs} from '#/components/dialogs/nuxs' 52 import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry' 53 import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs' 54 import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay' ··· 138 <HideBottomBarBorderProvider> 139 <IntentDialogProvider> 140 <Shell /> 141 - <NuxDialogs /> 142 <ToastOutlet /> 143 </IntentDialogProvider> 144 </HideBottomBarBorderProvider>
··· 48 import {ThemeProvider as Alf} from '#/alf' 49 import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 50 import {Provider as ContextMenuProvider} from '#/components/ContextMenu' 51 import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry' 52 import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs' 53 import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay' ··· 137 <HideBottomBarBorderProvider> 138 <IntentDialogProvider> 139 <Shell /> 140 <ToastOutlet /> 141 </IntentDialogProvider> 142 </HideBottomBarBorderProvider>
+33 -30
src/ageAssurance/components/NoAccessScreen.tsx
··· 9 useCreateSupportLink, 10 } from '#/lib/hooks/useCreateSupportLink' 11 import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo' 12 - import {isAppPassword} from '#/lib/jwt' 13 import {logger} from '#/logger' 14 import {isWeb} from '#/platform/detection' 15 import {isNative} from '#/platform/detection' 16 import {useIsBirthdateUpdateAllowed} from '#/state/birthdate' 17 - import {useSession, useSessionApi} from '#/state/session' 18 import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' 19 import {Admonition} from '#/components/Admonition' 20 import {AgeAssuranceAppealDialog} from '#/components/ageAssurance/AgeAssuranceAppealDialog' ··· 30 import {createStaticClick, SimpleInlineLinkText} from '#/components/Link' 31 import {Outlet as PortalOutlet} from '#/components/Portal' 32 import * as Toast from '#/components/Toast' 33 - import {Span, Text} from '#/components/Typography' 34 import {BottomSheetOutlet} from '#/../modules/bottom-sheet' 35 import {useAgeAssurance} from '#/ageAssurance' 36 import {useAgeAssuranceDataContext} from '#/ageAssurance/data' ··· 54 const isBirthdateUpdateAllowed = useIsBirthdateUpdateAllowed() 55 const {logoutCurrentAccount} = useSessionApi() 56 const createSupportLink = useCreateSupportLink() 57 - 58 - const {currentAccount} = useSession() 59 - const isUsingAppPassword = isAppPassword(currentAccount?.accessJwt || '') 60 61 const aa = useAgeAssurance() 62 const isBlocked = aa.state.status === aa.Status.Blocked ··· 89 logoutCurrentAccount('AgeAssuranceNoAccessScreen') 90 }, [logoutCurrentAccount]) 91 92 - const birthdateUpdateText = canUpdateBirthday ? ( 93 - <Text style={[textStyles]}> 94 <Trans> 95 - If you believe your birthdate is incorrect, you can update it by{' '} 96 - <SimpleInlineLinkText 97 - label={_(msg`Click here to update your birthdate`)} 98 - style={[textStyles]} 99 - {...createStaticClick(() => { 100 - logger.metric('ageAssurance:noAccessScreen:openBirthdateDialog', {}) 101 - birthdateControl.open() 102 - })}> 103 - clicking here 104 - </SimpleInlineLinkText> 105 - . 106 </Trans> 107 - </Text> 108 ) : ( 109 <Text style={[textStyles]}> 110 <Trans> ··· 211 </ButtonText> 212 </Button> 213 214 - {isUsingAppPassword && ( 215 - <Admonition type="info"> 216 - <Trans> 217 - Hmm, it looks like you're logged in with an{' '} 218 - <Span style={[a.italic]}>App Password</Span>. To set your 219 - birthdate, you'll need to log in with your main account 220 - password, or ask whomever controls this account to do so. 221 - </Trans> 222 - </Admonition> 223 - )} 224 </View> 225 )} 226
··· 9 useCreateSupportLink, 10 } from '#/lib/hooks/useCreateSupportLink' 11 import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo' 12 import {logger} from '#/logger' 13 import {isWeb} from '#/platform/detection' 14 import {isNative} from '#/platform/detection' 15 import {useIsBirthdateUpdateAllowed} from '#/state/birthdate' 16 + import {useSessionApi} from '#/state/session' 17 import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' 18 import {Admonition} from '#/components/Admonition' 19 import {AgeAssuranceAppealDialog} from '#/components/ageAssurance/AgeAssuranceAppealDialog' ··· 29 import {createStaticClick, SimpleInlineLinkText} from '#/components/Link' 30 import {Outlet as PortalOutlet} from '#/components/Portal' 31 import * as Toast from '#/components/Toast' 32 + import {Text} from '#/components/Typography' 33 import {BottomSheetOutlet} from '#/../modules/bottom-sheet' 34 import {useAgeAssurance} from '#/ageAssurance' 35 import {useAgeAssuranceDataContext} from '#/ageAssurance/data' ··· 53 const isBirthdateUpdateAllowed = useIsBirthdateUpdateAllowed() 54 const {logoutCurrentAccount} = useSessionApi() 55 const createSupportLink = useCreateSupportLink() 56 57 const aa = useAgeAssurance() 58 const isBlocked = aa.state.status === aa.Status.Blocked ··· 85 logoutCurrentAccount('AgeAssuranceNoAccessScreen') 86 }, [logoutCurrentAccount]) 87 88 + const orgAdmonition = ( 89 + <Admonition type="tip"> 90 <Trans> 91 + For organizational accounts, use the birthdate of the person who is 92 + responsible for the account. 93 </Trans> 94 + </Admonition> 95 + ) 96 + 97 + const birthdateUpdateText = canUpdateBirthday ? ( 98 + <> 99 + <Text style={[textStyles]}> 100 + <Trans> 101 + If you believe your birthdate is incorrect, you can update it by{' '} 102 + <SimpleInlineLinkText 103 + label={_(msg`Click here to update your birthdate`)} 104 + style={[textStyles]} 105 + {...createStaticClick(() => { 106 + logger.metric( 107 + 'ageAssurance:noAccessScreen:openBirthdateDialog', 108 + {}, 109 + ) 110 + birthdateControl.open() 111 + })}> 112 + clicking here 113 + </SimpleInlineLinkText> 114 + . 115 + </Trans> 116 + </Text> 117 + 118 + {orgAdmonition} 119 + </> 120 ) : ( 121 <Text style={[textStyles]}> 122 <Trans> ··· 223 </ButtonText> 224 </Button> 225 226 + {orgAdmonition} 227 </View> 228 )} 229
+305 -74
src/components/FeedInterstitials.tsx
··· 1 import React, {useCallback, useEffect, useRef} from 'react' 2 import {ScrollView, View} from 'react-native' 3 import {type AppBskyFeedDefs, AtUri} from '@atproto/api' 4 import {msg, Trans} from '@lingui/macro' 5 import {useLingui} from '@lingui/react' 6 import {useNavigation} from '@react-navigation/native' 7 8 import {type NavigationProp} from '#/lib/routes/types' 9 - import {logEvent} from '#/lib/statsig/statsig' 10 import {logger} from '#/logger' 11 import {type MetricEvents} from '#/logger/metrics' 12 import {isIOS} from '#/platform/detection' ··· 15 import {useGetPopularFeedsQuery} from '#/state/queries/feed' 16 import {type FeedDescriptor} from '#/state/queries/post-feed' 17 import {useProfilesQuery} from '#/state/queries/profile' 18 - import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows' 19 import {useSession} from '#/state/session' 20 import * as userActionHistory from '#/state/userActionHistory' 21 import {type SeenPost} from '#/state/userActionHistory' ··· 32 import * as FeedCard from '#/components/FeedCard' 33 import {ArrowRight_Stroke2_Corner0_Rounded as ArrowRight} from '#/components/icons/Arrow' 34 import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag' 35 import {InlineLinkText} from '#/components/Link' 36 import * as ProfileCard from '#/components/ProfileCard' 37 import {Text} from '#/components/Typography' 38 import type * as bsky from '#/types/bsky' 39 import {FollowDialogWithoutGuide} from './ProgressGuide/FollowDialog' 40 import {ProgressGuideList} from './ProgressGuide/List' 41 42 const MOBILE_CARD_WIDTH = 165 43 const FINAL_CARD_WIDTH = 120 ··· 203 } 204 205 export function SuggestedFollowsProfile({did}: {did: string}) { 206 const { 207 isLoading: isSuggestionsLoading, 208 data, ··· 210 } = useSuggestedFollowsByActorQuery({ 211 did, 212 }) 213 return ( 214 <ProfileGrid 215 isSuggestionsLoading={isSuggestionsLoading} 216 - profiles={data?.suggestions ?? []} 217 recId={data?.recId} 218 error={error} 219 viewContext="profile" 220 /> 221 ) 222 } 223 224 export function SuggestedFollowsHome() { 225 const { 226 isLoading: isSuggestionsLoading, 227 - profiles, 228 - error, 229 } = useExperimentalSuggestedUsersQuery() 230 return ( 231 <ProfileGrid 232 isSuggestionsLoading={isSuggestionsLoading} 233 - profiles={profiles} 234 - error={error} 235 viewContext="feed" 236 /> 237 ) 238 } ··· 241 isSuggestionsLoading, 242 error, 243 profiles, 244 recId, 245 viewContext = 'feed', 246 isVisible = true, 247 }: { 248 isSuggestionsLoading: boolean 249 profiles: bsky.profile.AnyProfileView[] 250 recId?: number 251 error: Error | null 252 viewContext: 'profile' | 'profileHeader' | 'feed' 253 isVisible?: boolean 254 }) { 255 const t = useTheme() 256 const {_} = useLingui() 257 const moderationOpts = useModerationOpts() 258 const {gtMobile} = useBreakpoints() 259 const followDialogControl = useDialogControl() ··· 261 const isLoading = isSuggestionsLoading || !moderationOpts 262 const isProfileHeaderContext = viewContext === 'profileHeader' 263 const isFeedContext = viewContext === 'feed' 264 265 const maxLength = gtMobile ? 3 : isProfileHeaderContext ? 12 : 6 266 const minLength = gtMobile ? 3 : 4 ··· 367 : error || !profiles.length 368 ? null 369 : profiles.slice(0, maxLength).map((profile, index) => ( 370 - <ProfileCard.Link 371 key={profile.did} 372 - profile={profile} 373 - onPress={() => { 374 - logEvent('suggestedUser:press', { 375 - logContext: isFeedContext 376 - ? 'InterstitialDiscover' 377 - : 'InterstitialProfile', 378 - recId, 379 - position: index, 380 - suggestedDid: profile.did, 381 - category: null, 382 - }) 383 - }} 384 style={[ 385 a.flex_1, 386 gtMobile && ··· 389 a.flex_grow, 390 {width: `calc(30% - ${a.gap_md.gap / 2}px)`}, 391 ]), 392 ]}> 393 - {({hovered, pressed}) => ( 394 - <CardOuter 395 - style={[(hovered || pressed) && t.atoms.border_contrast_high]}> 396 - <ProfileCard.Outer> 397 - <View 398 - style={[ 399 - a.flex_col, 400 - a.align_center, 401 - a.gap_sm, 402 - a.pb_sm, 403 - a.mb_auto, 404 - ]}> 405 - <ProfileCard.Avatar 406 - profile={profile} 407 - moderationOpts={moderationOpts} 408 - disabledPreview 409 - size={88} 410 - /> 411 - <View style={[a.flex_col, a.align_center, a.max_w_full]}> 412 - <ProfileCard.Name 413 profile={profile} 414 moderationOpts={moderationOpts} 415 /> 416 - <ProfileCard.Description 417 - profile={profile} 418 - numberOfLines={2} 419 - style={[ 420 - t.atoms.text_contrast_medium, 421 - a.text_center, 422 - a.text_xs, 423 - ]} 424 - /> 425 </View> 426 - </View> 427 428 - <ProfileCard.FollowButton 429 - profile={profile} 430 - moderationOpts={moderationOpts} 431 - logContext="FeedInterstitial" 432 - withIcon={false} 433 - style={[a.rounded_sm]} 434 - onFollow={() => { 435 - logEvent('suggestedUser:follow', { 436 - logContext: isFeedContext 437 - ? 'InterstitialDiscover' 438 - : 'InterstitialProfile', 439 - location: 'Card', 440 - recId, 441 - position: index, 442 - suggestedDid: profile.did, 443 - category: null, 444 - }) 445 - }} 446 - /> 447 - </ProfileCard.Outer> 448 - </CardOuter> 449 - )} 450 - </ProfileCard.Link> 451 )) 452 453 - if (error || (!isLoading && profiles.length < minLength)) { 454 logger.debug(`Not enough profiles to show suggested follows`) 455 return null 456 }
··· 1 import React, {useCallback, useEffect, useRef} from 'react' 2 import {ScrollView, View} from 'react-native' 3 + import Animated, {LinearTransition} from 'react-native-reanimated' 4 import {type AppBskyFeedDefs, AtUri} from '@atproto/api' 5 import {msg, Trans} from '@lingui/macro' 6 import {useLingui} from '@lingui/react' 7 import {useNavigation} from '@react-navigation/native' 8 9 import {type NavigationProp} from '#/lib/routes/types' 10 + import {logEvent, useGate} from '#/lib/statsig/statsig' 11 import {logger} from '#/logger' 12 import {type MetricEvents} from '#/logger/metrics' 13 import {isIOS} from '#/platform/detection' ··· 16 import {useGetPopularFeedsQuery} from '#/state/queries/feed' 17 import {type FeedDescriptor} from '#/state/queries/post-feed' 18 import {useProfilesQuery} from '#/state/queries/profile' 19 + import { 20 + useSuggestedFollowsByActorQuery, 21 + useSuggestedFollowsQuery, 22 + } from '#/state/queries/suggested-follows' 23 import {useSession} from '#/state/session' 24 import * as userActionHistory from '#/state/userActionHistory' 25 import {type SeenPost} from '#/state/userActionHistory' ··· 36 import * as FeedCard from '#/components/FeedCard' 37 import {ArrowRight_Stroke2_Corner0_Rounded as ArrowRight} from '#/components/icons/Arrow' 38 import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag' 39 + import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' 40 import {InlineLinkText} from '#/components/Link' 41 import * as ProfileCard from '#/components/ProfileCard' 42 import {Text} from '#/components/Typography' 43 import type * as bsky from '#/types/bsky' 44 import {FollowDialogWithoutGuide} from './ProgressGuide/FollowDialog' 45 import {ProgressGuideList} from './ProgressGuide/List' 46 + 47 + const DISMISS_ANIMATION_DURATION = 200 48 49 const MOBILE_CARD_WIDTH = 165 50 const FINAL_CARD_WIDTH = 120 ··· 210 } 211 212 export function SuggestedFollowsProfile({did}: {did: string}) { 213 + const {gtMobile} = useBreakpoints() 214 + const moderationOpts = useModerationOpts() 215 + const maxLength = gtMobile ? 4 : 6 216 const { 217 isLoading: isSuggestionsLoading, 218 data, ··· 220 } = useSuggestedFollowsByActorQuery({ 221 did, 222 }) 223 + const { 224 + data: moreSuggestions, 225 + fetchNextPage, 226 + hasNextPage, 227 + isFetchingNextPage, 228 + } = useSuggestedFollowsQuery({limit: 25}) 229 + 230 + const [dismissedDids, setDismissedDids] = React.useState<Set<string>>( 231 + new Set(), 232 + ) 233 + const [dismissingDids, setDismissingDids] = React.useState<Set<string>>( 234 + new Set(), 235 + ) 236 + 237 + const onDismiss = React.useCallback((dismissedDid: string) => { 238 + // Start the fade animation 239 + setDismissingDids(prev => new Set(prev).add(dismissedDid)) 240 + // After animation completes, actually remove from list 241 + setTimeout(() => { 242 + setDismissedDids(prev => new Set(prev).add(dismissedDid)) 243 + setDismissingDids(prev => { 244 + const next = new Set(prev) 245 + next.delete(dismissedDid) 246 + return next 247 + }) 248 + }, DISMISS_ANIMATION_DURATION) 249 + }, []) 250 + 251 + // Combine profiles from the actor-specific query with fallback suggestions 252 + const allProfiles = React.useMemo(() => { 253 + const actorProfiles = data?.suggestions ?? [] 254 + const fallbackProfiles = 255 + moreSuggestions?.pages.flatMap(page => page.actors) ?? [] 256 + 257 + // Dedupe by did, preferring actor-specific profiles 258 + const seen = new Set<string>() 259 + const combined: bsky.profile.AnyProfileView[] = [] 260 + 261 + for (const profile of actorProfiles) { 262 + if (!seen.has(profile.did)) { 263 + seen.add(profile.did) 264 + combined.push(profile) 265 + } 266 + } 267 + 268 + for (const profile of fallbackProfiles) { 269 + if (!seen.has(profile.did) && profile.did !== did) { 270 + seen.add(profile.did) 271 + combined.push(profile) 272 + } 273 + } 274 + 275 + return combined 276 + }, [data?.suggestions, moreSuggestions?.pages, did]) 277 + 278 + const filteredProfiles = React.useMemo(() => { 279 + return allProfiles.filter(p => !dismissedDids.has(p.did)) 280 + }, [allProfiles, dismissedDids]) 281 + 282 + // Fetch more when running low 283 + React.useEffect(() => { 284 + if ( 285 + moderationOpts && 286 + filteredProfiles.length < maxLength && 287 + hasNextPage && 288 + !isFetchingNextPage 289 + ) { 290 + fetchNextPage() 291 + } 292 + }, [ 293 + filteredProfiles.length, 294 + maxLength, 295 + hasNextPage, 296 + isFetchingNextPage, 297 + fetchNextPage, 298 + moderationOpts, 299 + ]) 300 + 301 return ( 302 <ProfileGrid 303 isSuggestionsLoading={isSuggestionsLoading} 304 + profiles={filteredProfiles} 305 + totalProfileCount={allProfiles.length} 306 recId={data?.recId} 307 error={error} 308 viewContext="profile" 309 + onDismiss={onDismiss} 310 + dismissingDids={dismissingDids} 311 /> 312 ) 313 } 314 315 export function SuggestedFollowsHome() { 316 + const {gtMobile} = useBreakpoints() 317 + const moderationOpts = useModerationOpts() 318 + const maxLength = gtMobile ? 4 : 6 319 const { 320 isLoading: isSuggestionsLoading, 321 + profiles: experimentalProfiles, 322 + error: experimentalError, 323 } = useExperimentalSuggestedUsersQuery() 324 + const { 325 + data: moreSuggestions, 326 + fetchNextPage, 327 + hasNextPage, 328 + isFetchingNextPage, 329 + error: suggestionsError, 330 + } = useSuggestedFollowsQuery({limit: 25}) 331 + 332 + const [dismissedDids, setDismissedDids] = React.useState<Set<string>>( 333 + new Set(), 334 + ) 335 + const [dismissingDids, setDismissingDids] = React.useState<Set<string>>( 336 + new Set(), 337 + ) 338 + 339 + const onDismiss = React.useCallback((did: string) => { 340 + // Start the fade animation 341 + setDismissingDids(prev => new Set(prev).add(did)) 342 + // After animation completes, actually remove from list 343 + setTimeout(() => { 344 + setDismissedDids(prev => new Set(prev).add(did)) 345 + setDismissingDids(prev => { 346 + const next = new Set(prev) 347 + next.delete(did) 348 + return next 349 + }) 350 + }, DISMISS_ANIMATION_DURATION) 351 + }, []) 352 + 353 + // Combine profiles from experimental query with paginated suggestions 354 + const allProfiles = React.useMemo(() => { 355 + const fallbackProfiles = 356 + moreSuggestions?.pages.flatMap(page => page.actors) ?? [] 357 + 358 + // Dedupe by did, preferring experimental profiles 359 + const seen = new Set<string>() 360 + const combined: bsky.profile.AnyProfileView[] = [] 361 + 362 + for (const profile of experimentalProfiles) { 363 + if (!seen.has(profile.did)) { 364 + seen.add(profile.did) 365 + combined.push(profile) 366 + } 367 + } 368 + 369 + for (const profile of fallbackProfiles) { 370 + if (!seen.has(profile.did)) { 371 + seen.add(profile.did) 372 + combined.push(profile) 373 + } 374 + } 375 + 376 + return combined 377 + }, [experimentalProfiles, moreSuggestions?.pages]) 378 + 379 + const filteredProfiles = React.useMemo(() => { 380 + return allProfiles.filter(p => !dismissedDids.has(p.did)) 381 + }, [allProfiles, dismissedDids]) 382 + 383 + // Fetch more when running low 384 + React.useEffect(() => { 385 + if ( 386 + moderationOpts && 387 + filteredProfiles.length < maxLength && 388 + hasNextPage && 389 + !isFetchingNextPage 390 + ) { 391 + fetchNextPage() 392 + } 393 + }, [ 394 + filteredProfiles.length, 395 + maxLength, 396 + hasNextPage, 397 + isFetchingNextPage, 398 + fetchNextPage, 399 + moderationOpts, 400 + ]) 401 + 402 return ( 403 <ProfileGrid 404 isSuggestionsLoading={isSuggestionsLoading} 405 + profiles={filteredProfiles} 406 + totalProfileCount={allProfiles.length} 407 + error={experimentalError || suggestionsError} 408 viewContext="feed" 409 + onDismiss={onDismiss} 410 + dismissingDids={dismissingDids} 411 /> 412 ) 413 } ··· 416 isSuggestionsLoading, 417 error, 418 profiles, 419 + totalProfileCount, 420 recId, 421 viewContext = 'feed', 422 + onDismiss, 423 + dismissingDids, 424 isVisible = true, 425 }: { 426 isSuggestionsLoading: boolean 427 profiles: bsky.profile.AnyProfileView[] 428 + totalProfileCount?: number 429 recId?: number 430 error: Error | null 431 + dismissingDids?: Set<string> 432 viewContext: 'profile' | 'profileHeader' | 'feed' 433 + onDismiss?: (did: string) => void 434 isVisible?: boolean 435 }) { 436 const t = useTheme() 437 const {_} = useLingui() 438 + const gate = useGate() 439 const moderationOpts = useModerationOpts() 440 const {gtMobile} = useBreakpoints() 441 const followDialogControl = useDialogControl() ··· 443 const isLoading = isSuggestionsLoading || !moderationOpts 444 const isProfileHeaderContext = viewContext === 'profileHeader' 445 const isFeedContext = viewContext === 'feed' 446 + const showDismissButton = onDismiss && gate('suggested_users_dismiss') 447 448 const maxLength = gtMobile ? 3 : isProfileHeaderContext ? 12 : 6 449 const minLength = gtMobile ? 3 : 4 ··· 550 : error || !profiles.length 551 ? null 552 : profiles.slice(0, maxLength).map((profile, index) => ( 553 + <Animated.View 554 key={profile.did} 555 + layout={LinearTransition.duration(DISMISS_ANIMATION_DURATION)} 556 style={[ 557 a.flex_1, 558 gtMobile && ··· 561 a.flex_grow, 562 {width: `calc(30% - ${a.gap_md.gap / 2}px)`}, 563 ]), 564 + { 565 + opacity: dismissingDids?.has(profile.did) ? 0 : 1, 566 + transitionProperty: 'opacity', 567 + transitionDuration: `${DISMISS_ANIMATION_DURATION}ms`, 568 + }, 569 ]}> 570 + <ProfileCard.Link 571 + profile={profile} 572 + onPress={() => { 573 + logEvent('suggestedUser:press', { 574 + logContext: isFeedContext 575 + ? 'InterstitialDiscover' 576 + : 'InterstitialProfile', 577 + recId, 578 + position: index, 579 + suggestedDid: profile.did, 580 + category: null, 581 + }) 582 + }}> 583 + {({hovered, pressed}) => ( 584 + <CardOuter 585 + style={[ 586 + (hovered || pressed) && t.atoms.border_contrast_high, 587 + ]}> 588 + <ProfileCard.Outer> 589 + {showDismissButton && ( 590 + <Button 591 + label={_(msg`Dismiss this suggestion`)} 592 + onPress={e => { 593 + e.preventDefault() 594 + onDismiss!(profile.did) 595 + logEvent('suggestedUser:dismiss', { 596 + logContext: isFeedContext 597 + ? 'InterstitialDiscover' 598 + : 'InterstitialProfile', 599 + position: index, 600 + suggestedDid: profile.did, 601 + recId, 602 + }) 603 + }} 604 + style={[ 605 + a.absolute, 606 + a.z_10, 607 + a.p_xs, 608 + {top: -4, right: -4}, 609 + ]}> 610 + {({ 611 + hovered: dismissHovered, 612 + pressed: dismissPressed, 613 + }) => ( 614 + <X 615 + size="xs" 616 + fill={ 617 + dismissHovered || dismissPressed 618 + ? t.atoms.text.color 619 + : t.atoms.text_contrast_medium.color 620 + } 621 + /> 622 + )} 623 + </Button> 624 + )} 625 + <View 626 + style={[ 627 + a.flex_col, 628 + a.align_center, 629 + a.gap_sm, 630 + a.pb_sm, 631 + a.mb_auto, 632 + ]}> 633 + <ProfileCard.Avatar 634 profile={profile} 635 moderationOpts={moderationOpts} 636 + disabledPreview 637 + size={88} 638 /> 639 + <View style={[a.flex_col, a.align_center, a.max_w_full]}> 640 + <ProfileCard.Name 641 + profile={profile} 642 + moderationOpts={moderationOpts} 643 + /> 644 + <ProfileCard.Description 645 + profile={profile} 646 + numberOfLines={2} 647 + style={[ 648 + t.atoms.text_contrast_medium, 649 + a.text_center, 650 + a.text_xs, 651 + ]} 652 + /> 653 + </View> 654 </View> 655 656 + <ProfileCard.FollowButton 657 + profile={profile} 658 + moderationOpts={moderationOpts} 659 + logContext="FeedInterstitial" 660 + withIcon={false} 661 + style={[a.rounded_sm]} 662 + onFollow={() => { 663 + logEvent('suggestedUser:follow', { 664 + logContext: isFeedContext 665 + ? 'InterstitialDiscover' 666 + : 'InterstitialProfile', 667 + location: 'Card', 668 + recId, 669 + position: index, 670 + suggestedDid: profile.did, 671 + category: null, 672 + }) 673 + }} 674 + /> 675 + </ProfileCard.Outer> 676 + </CardOuter> 677 + )} 678 + </ProfileCard.Link> 679 + </Animated.View> 680 )) 681 682 + // Use totalProfileCount (before dismissals) for minLength check on initial render. 683 + const profileCountForMinCheck = totalProfileCount ?? profiles.length 684 + if (error || (!isLoading && profileCountForMinCheck < minLength)) { 685 logger.debug(`Not enough profiles to show suggested follows`) 686 return null 687 }
+2 -1
src/components/InternationalPhoneCodeSelect.tsx
··· 1 import {Fragment, useMemo} from 'react' 2 import {Image} from 'expo-image' 3 import {msg} from '@lingui/macro' 4 import {useLingui} from '@lingui/react' ··· 113 /> 114 ) 115 } 116 - return unicodeFlag + ' ' 117 }
··· 1 import {Fragment, useMemo} from 'react' 2 + import {Text as RNText} from 'react-native' 3 import {Image} from 'expo-image' 4 import {msg} from '@lingui/macro' 5 import {useLingui} from '@lingui/react' ··· 114 /> 115 ) 116 } 117 + return <RNText style={[{lineHeight: 21}]}>{unicodeFlag + ' '}</RNText> 118 }
+7 -3
src/components/contacts/FindContactsBannerNUX.tsx
··· 6 import {useLingui} from '@lingui/react' 7 8 import {HITSLOP_10} from '#/lib/constants' 9 import {logger} from '#/logger' 10 import {isWeb} from '#/platform/detection' 11 import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs' ··· 20 const t = useTheme() 21 const {_} = useLingui() 22 const {visible, close} = useInternalState() 23 - const isFeatureEnabled = useIsFindContactsFeatureEnabledBasedOnGeolocation() 24 25 - if (!visible || !isFeatureEnabled) return null 26 27 return ( 28 <View style={[a.w_full, a.p_lg, a.border_b, t.atoms.border_contrast_low]}> ··· 88 const {nux} = useNux(Nux.FindContactsDismissibleBanner) 89 const {mutate: save, variables} = useSaveNux() 90 const hidden = !!variables 91 92 const visible = useMemo(() => { 93 if (isWeb) return false 94 if (hidden) return false 95 if (nux && nux.completed) return false 96 return true 97 - }, [hidden, nux]) 98 99 const close = () => { 100 save({
··· 6 import {useLingui} from '@lingui/react' 7 8 import {HITSLOP_10} from '#/lib/constants' 9 + import {useGate} from '#/lib/statsig/statsig' 10 import {logger} from '#/logger' 11 import {isWeb} from '#/platform/detection' 12 import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs' ··· 21 const t = useTheme() 22 const {_} = useLingui() 23 const {visible, close} = useInternalState() 24 25 + if (!visible) return null 26 27 return ( 28 <View style={[a.w_full, a.p_lg, a.border_b, t.atoms.border_contrast_low]}> ··· 88 const {nux} = useNux(Nux.FindContactsDismissibleBanner) 89 const {mutate: save, variables} = useSaveNux() 90 const hidden = !!variables 91 + const isFeatureEnabled = useIsFindContactsFeatureEnabledBasedOnGeolocation() 92 + const gate = useGate() 93 94 const visible = useMemo(() => { 95 if (isWeb) return false 96 if (hidden) return false 97 if (nux && nux.completed) return false 98 + if (!isFeatureEnabled) return false 99 + if (gate('disable_settings_find_contacts')) return false 100 return true 101 + }, [hidden, nux, isFeatureEnabled, gate]) 102 103 const close = () => { 104 save({
+10 -8
src/components/contacts/country-allowlist.ts
··· 18 'IT', 19 ] satisfies CountryCode[] as string[] 20 21 - export function isFindContactsFeatureEnabled(countryCode: string): boolean { 22 return FIND_CONTACTS_FEATURE_COUNTRY_ALLOWLIST.includes( 23 countryCode.toUpperCase(), 24 ) ··· 26 27 export function useIsFindContactsFeatureEnabledBasedOnGeolocation() { 28 const location = useGeolocation() 29 - 30 - if (IS_DEV) return true 31 - 32 - // they can try, by they'll need a phone number 33 - // from one of the allowlisted countries 34 - if (!location.countryCode) return true 35 - 36 return isFindContactsFeatureEnabled(location.countryCode) 37 }
··· 18 'IT', 19 ] satisfies CountryCode[] as string[] 20 21 + export function isFindContactsFeatureEnabled(countryCode?: string): boolean { 22 + if (IS_DEV) return true 23 + 24 + /* 25 + * This should never happen unless geolocation fails entirely. In that 26 + * case, let the user try, since it should work as long as they have a 27 + * phone number from one of the allow-listed countries. 28 + */ 29 + if (!countryCode) return true 30 + 31 return FIND_CONTACTS_FEATURE_COUNTRY_ALLOWLIST.includes( 32 countryCode.toUpperCase(), 33 ) ··· 35 36 export function useIsFindContactsFeatureEnabledBasedOnGeolocation() { 37 const location = useGeolocation() 38 return isFindContactsFeatureEnabled(location.countryCode) 39 }
+2 -4
src/components/contacts/screens/ViewMatches.tsx
··· 104 match => !state.dismissedMatches.includes(match.profile.did), 105 ) 106 107 - console.log(matches) 108 - 109 const followableDids = matches.map(match => match.profile.did) 110 const [didFollowAll, setDidFollowAll] = useState(followableDids.length === 0) 111 ··· 449 const contactName = useMemo(() => { 450 if (!contact) return null 451 452 - const name = contact.firstName ?? contact.lastName ?? contact.name 453 if (name) return _(msg`Your contact ${name}`) 454 const phone = 455 contact.phoneNumbers?.find(p => p.isPrimary) ?? contact.phoneNumbers?.[0] ··· 520 const {_} = useLingui() 521 const {currentAccount} = useSession() 522 523 - const name = contact.firstName ?? contact.lastName ?? contact.name 524 const phone = 525 contact.phoneNumbers?.find(phone => phone.isPrimary) ?? 526 contact.phoneNumbers?.[0]
··· 104 match => !state.dismissedMatches.includes(match.profile.did), 105 ) 106 107 const followableDids = matches.map(match => match.profile.did) 108 const [didFollowAll, setDidFollowAll] = useState(followableDids.length === 0) 109 ··· 447 const contactName = useMemo(() => { 448 if (!contact) return null 449 450 + const name = contact.name ?? contact.firstName ?? contact.lastName 451 if (name) return _(msg`Your contact ${name}`) 452 const phone = 453 contact.phoneNumbers?.find(p => p.isPrimary) ?? contact.phoneNumbers?.[0] ··· 518 const {_} = useLingui() 519 const {currentAccount} = useSession() 520 521 + const name = contact.name ?? contact.firstName ?? contact.lastName 522 const phone = 523 contact.phoneNumbers?.find(phone => phone.isPrimary) ?? 524 contact.phoneNumbers?.[0]
+14 -1
src/components/dialogs/BirthDateSettings.tsx
··· 4 import {useLingui} from '@lingui/react' 5 6 import {useCleanError} from '#/lib/hooks/useCleanError' 7 import {getAge, getDateAgo} from '#/lib/strings/time' 8 import {logger} from '#/logger' 9 import {isIOS, isWeb} from '#/platform/detection' ··· 15 usePreferencesQuery, 16 type UsePreferencesQueryResponse, 17 } from '#/state/queries/preferences' 18 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 19 import {atoms as a, useTheme, web} from '#/alf' 20 import {Admonition} from '#/components/Admonition' ··· 23 import {DateField} from '#/components/forms/DateField' 24 import {SimpleInlineLinkText} from '#/components/Link' 25 import {Loader} from '#/components/Loader' 26 - import {Text} from '#/components/Typography' 27 28 export function BirthDateSettingsDialog({ 29 control, ··· 34 const {_} = useLingui() 35 const {isLoading, error, data: preferences} = usePreferencesQuery() 36 const isBirthdateUpdateAllowed = useIsBirthdateUpdateAllowed() 37 38 return ( 39 <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> ··· 65 } 66 style={[a.rounded_sm]} 67 /> 68 ) : ( 69 <BirthdayInner control={control} preferences={preferences} /> 70 )}
··· 4 import {useLingui} from '@lingui/react' 5 6 import {useCleanError} from '#/lib/hooks/useCleanError' 7 + import {isAppPassword} from '#/lib/jwt' 8 import {getAge, getDateAgo} from '#/lib/strings/time' 9 import {logger} from '#/logger' 10 import {isIOS, isWeb} from '#/platform/detection' ··· 16 usePreferencesQuery, 17 type UsePreferencesQueryResponse, 18 } from '#/state/queries/preferences' 19 + import {useSession} from '#/state/session' 20 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 21 import {atoms as a, useTheme, web} from '#/alf' 22 import {Admonition} from '#/components/Admonition' ··· 25 import {DateField} from '#/components/forms/DateField' 26 import {SimpleInlineLinkText} from '#/components/Link' 27 import {Loader} from '#/components/Loader' 28 + import {Span, Text} from '#/components/Typography' 29 30 export function BirthDateSettingsDialog({ 31 control, ··· 36 const {_} = useLingui() 37 const {isLoading, error, data: preferences} = usePreferencesQuery() 38 const isBirthdateUpdateAllowed = useIsBirthdateUpdateAllowed() 39 + const {currentAccount} = useSession() 40 + const isUsingAppPassword = isAppPassword(currentAccount?.accessJwt || '') 41 42 return ( 43 <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> ··· 69 } 70 style={[a.rounded_sm]} 71 /> 72 + ) : isUsingAppPassword ? ( 73 + <Admonition type="info"> 74 + <Trans> 75 + Hmm, it looks like you're logged in with an{' '} 76 + <Span style={[a.italic]}>App Password</Span>. To set your 77 + birthdate, you'll need to log in with your main account 78 + password, or ask whomever controls this account to do so. 79 + </Trans> 80 + </Admonition> 81 ) : ( 82 <BirthdayInner control={control} preferences={preferences} /> 83 )}
+19 -12
src/components/dialogs/nuxs/FindContactsAnnouncement.tsx
··· 6 import {useLingui} from '@lingui/react' 7 8 import {logger} from '#/logger' 9 - import {isWeb} from '#/platform/detection' 10 import {atoms as a, useTheme, web} from '#/alf' 11 import {Button, ButtonText} from '#/components/Button' 12 - import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from '#/components/contacts/country-allowlist' 13 import * as Dialog from '#/components/Dialog' 14 import {useNuxDialogContext} from '#/components/dialogs/nuxs' 15 import {Text} from '#/components/Typography' 16 import {navigate} from '#/Navigation' 17 18 - export function FindContactsAnnouncement() { 19 - const isFeatureEnabled = useIsFindContactsFeatureEnabledBasedOnGeolocation() 20 21 - if (!isFeatureEnabled) { 22 - return null 23 - } 24 - 25 - return <Inner /> 26 - } 27 - 28 - function Inner() { 29 const t = useTheme() 30 const {_} = useLingui() 31 const nuxDialogs = useNuxDialogContext()
··· 6 import {useLingui} from '@lingui/react' 7 8 import {logger} from '#/logger' 9 + import {isNative, isWeb} from '#/platform/detection' 10 import {atoms as a, useTheme, web} from '#/alf' 11 import {Button, ButtonText} from '#/components/Button' 12 + import {isFindContactsFeatureEnabled} from '#/components/contacts/country-allowlist' 13 import * as Dialog from '#/components/Dialog' 14 import {useNuxDialogContext} from '#/components/dialogs/nuxs' 15 + import { 16 + createIsEnabledCheck, 17 + isExistingUserAsOf, 18 + } from '#/components/dialogs/nuxs/utils' 19 import {Text} from '#/components/Typography' 20 + import {IS_E2E} from '#/env' 21 import {navigate} from '#/Navigation' 22 23 + export const enabled = createIsEnabledCheck(props => { 24 + return ( 25 + !IS_E2E && 26 + isNative && 27 + isExistingUserAsOf( 28 + '2025-12-16T00:00:00.000Z', 29 + props.currentProfile.createdAt, 30 + ) && 31 + isFindContactsFeatureEnabled(props.geolocation.countryCode) 32 + ) 33 + }) 34 35 + export function FindContactsAnnouncement() { 36 const t = useTheme() 37 const {_} = useLingui() 38 const nuxDialogs = useNuxDialogContext()
+17 -21
src/components/dialogs/nuxs/index.tsx
··· 10 11 import {useGate} from '#/lib/statsig/statsig' 12 import {logger} from '#/logger' 13 - import {isNative} from '#/platform/detection' 14 import {STALE} from '#/state/queries' 15 import {Nux, useNuxs, useResetNuxs, useSaveNux} from '#/state/queries/nuxs' 16 import { ··· 20 import {useProfileQuery} from '#/state/queries/profile' 21 import {type SessionAccount, useSession} from '#/state/session' 22 import {useOnboardingState} from '#/state/shell' 23 import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing' 24 - import {ENV} from '#/env' 25 - /* 26 - * NUXs 27 - */ 28 - import {FindContactsAnnouncement} from './FindContactsAnnouncement' 29 - import {isExistingUserAsOf} from './utils' 30 31 type Context = { 32 activeNux: Nux | undefined ··· 35 36 const queuedNuxs: { 37 id: Nux 38 - enabled?: (props: { 39 - gate: ReturnType<typeof useGate> 40 - currentAccount: SessionAccount 41 - currentProfile: AppBskyActorDefs.ProfileViewDetailed 42 - preferences: UsePreferencesQueryResponse 43 - }) => boolean 44 }[] = [ 45 { 46 id: Nux.FindContactsAnnouncement, 47 - enabled: ({currentProfile}) => { 48 - return ( 49 - isNative && 50 - ENV !== 'e2e' && 51 - isExistingUserAsOf('2025-12-16T00:00:00.000Z', currentProfile.createdAt) 52 - ) 53 - }, 54 }, 55 ] 56 ··· 101 preferences: UsePreferencesQueryResponse 102 }) { 103 const gate = useGate() 104 const {nuxs} = useNuxs() 105 const [snoozed, setSnoozed] = useState(() => { 106 return isSnoozed() ··· 143 // then check gate (track exposure) 144 if ( 145 enabled && 146 - !enabled({gate, currentAccount, currentProfile, preferences}) 147 ) { 148 continue 149 } ··· 178 currentAccount, 179 currentProfile, 180 preferences, 181 ]) 182 183 const ctx = useMemo(() => {
··· 10 11 import {useGate} from '#/lib/statsig/statsig' 12 import {logger} from '#/logger' 13 import {STALE} from '#/state/queries' 14 import {Nux, useNuxs, useResetNuxs, useSaveNux} from '#/state/queries/nuxs' 15 import { ··· 19 import {useProfileQuery} from '#/state/queries/profile' 20 import {type SessionAccount, useSession} from '#/state/session' 21 import {useOnboardingState} from '#/state/shell' 22 + import { 23 + enabled as isFindContactsAnnouncementEnabled, 24 + FindContactsAnnouncement, 25 + } from '#/components/dialogs/nuxs/FindContactsAnnouncement' 26 import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing' 27 + import {type EnabledCheckProps} from '#/components/dialogs/nuxs/utils' 28 + import {useGeolocation} from '#/geolocation' 29 30 type Context = { 31 activeNux: Nux | undefined ··· 34 35 const queuedNuxs: { 36 id: Nux 37 + enabled?: (props: EnabledCheckProps) => boolean 38 }[] = [ 39 { 40 id: Nux.FindContactsAnnouncement, 41 + enabled: isFindContactsAnnouncementEnabled, 42 }, 43 ] 44 ··· 89 preferences: UsePreferencesQueryResponse 90 }) { 91 const gate = useGate() 92 + const geolocation = useGeolocation() 93 const {nuxs} = useNuxs() 94 const [snoozed, setSnoozed] = useState(() => { 95 return isSnoozed() ··· 132 // then check gate (track exposure) 133 if ( 134 enabled && 135 + !enabled({ 136 + gate, 137 + currentAccount, 138 + currentProfile, 139 + preferences, 140 + geolocation, 141 + }) 142 ) { 143 continue 144 } ··· 173 currentAccount, 174 currentProfile, 175 preferences, 176 + geolocation, 177 ]) 178 179 const ctx = useMemo(() => {
+21
src/components/dialogs/nuxs/utils.ts
··· 1 const ONE_DAY = 1000 * 60 * 60 * 24 2 3 export function isDaysOld(days: number, createdAt?: string) {
··· 1 + import {type AppBskyActorDefs} from '@atproto/api' 2 + 3 + import {type useGate} from '#/lib/statsig/statsig' 4 + import {type UsePreferencesQueryResponse} from '#/state/queries/preferences' 5 + import {type SessionAccount} from '#/state/session' 6 + import {type Geolocation} from '#/geolocation' 7 + 8 + export type EnabledCheckProps = { 9 + gate: ReturnType<typeof useGate> 10 + currentAccount: SessionAccount 11 + currentProfile: AppBskyActorDefs.ProfileViewDetailed 12 + preferences: UsePreferencesQueryResponse 13 + geolocation: Geolocation 14 + } 15 + 16 + export function createIsEnabledCheck( 17 + cb: (props: EnabledCheckProps) => boolean, 18 + ) { 19 + return cb 20 + } 21 + 22 const ONE_DAY = 1000 * 60 * 60 * 24 23 24 export function isDaysOld(days: number, createdAt?: string) {
+2
src/lib/statsig/gates.ts
··· 4 | 'debug_show_feedcontext' 5 | 'debug_subscriptions' 6 | 'disable_onboarding_find_contacts' 7 | 'explore_show_suggested_feeds' 8 | 'feed_reply_button_open_thread' 9 | 'old_postonboarding' ··· 11 | 'onboarding_suggested_starterpacks' 12 | 'remove_show_latest_button' 13 | 'show_composer_prompt' 14 | 'test_gate_1' 15 | 'test_gate_2'
··· 4 | 'debug_show_feedcontext' 5 | 'debug_subscriptions' 6 | 'disable_onboarding_find_contacts' 7 + | 'disable_settings_find_contacts' 8 | 'explore_show_suggested_feeds' 9 | 'feed_reply_button_open_thread' 10 | 'old_postonboarding' ··· 12 | 'onboarding_suggested_starterpacks' 13 | 'remove_show_latest_button' 14 | 'show_composer_prompt' 15 + | 'suggested_users_dismiss' 16 | 'test_gate_1' 17 | 'test_gate_2'
+201 -178
src/locale/locales/en/messages.po
··· 38 msgid "{0, plural, one {# following} other {# following}}" 39 msgstr "" 40 41 - #: src/components/contacts/screens/ViewMatches.tsx:267 42 msgid "{0, plural, one {# friend found!} other {# friends found!}}" 43 msgstr "" 44 ··· 576 577 #: src/Navigation.tsx:534 578 #: src/screens/Settings/AboutSettings.tsx:75 579 - #: src/screens/Settings/Settings.tsx:258 580 - #: src/screens/Settings/Settings.tsx:261 581 msgid "About" 582 msgstr "" 583 ··· 604 msgstr "" 605 606 #: src/screens/Settings/AccessibilitySettings.tsx:44 607 - #: src/screens/Settings/Settings.tsx:234 608 - #: src/screens/Settings/Settings.tsx:237 609 msgid "Accessibility" 610 msgstr "" 611 ··· 616 #: src/Navigation.tsx:401 617 #: src/screens/Login/LoginForm.tsx:194 618 #: src/screens/Settings/AccountSettings.tsx:51 619 - #: src/screens/Settings/Settings.tsx:178 620 - #: src/screens/Settings/Settings.tsx:181 621 msgid "Account" 622 msgstr "" 623 ··· 648 msgid "Account Muted by List" 649 msgstr "" 650 651 - #: src/screens/Settings/Settings.tsx:640 652 msgid "Account options" 653 msgstr "" 654 ··· 656 msgid "Account provider" 657 msgstr "" 658 659 - #: src/screens/Settings/Settings.tsx:676 660 msgid "Account removed from quick access" 661 msgstr "" 662 ··· 741 msgid "Add alt text (optional)" 742 msgstr "" 743 744 - #: src/screens/Settings/Settings.tsx:580 745 - #: src/screens/Settings/Settings.tsx:583 746 #: src/view/shell/desktop/LeftNav.tsx:262 747 #: src/view/shell/desktop/LeftNav.tsx:266 748 msgid "Add another account" ··· 844 msgid "Add user to list" 845 msgstr "" 846 847 - #: src/ageAssurance/components/NoAccessScreen.tsx:210 848 msgid "Add your birthdate" 849 msgstr "" 850 ··· 914 msgid "Age assurance inquiry was submitted" 915 msgstr "" 916 917 - #: src/ageAssurance/components/NoAccessScreen.tsx:342 918 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:191 919 msgid "Age assurance only takes a few minutes" 920 msgstr "" ··· 934 msgid "All accounts have been followed!" 935 msgstr "" 936 937 - #: src/components/contacts/screens/ViewMatches.tsx:143 938 msgid "All friends followed!" 939 msgstr "" 940 ··· 1070 msgid "An error occurred while generating your starter pack. Want to try again?" 1071 msgstr "" 1072 1073 - #: src/components/contacts/screens/ViewMatches.tsx:242 1074 msgid "An error occurred while hiding suggestion. {0}" 1075 msgstr "" 1076 ··· 1108 msgstr "" 1109 1110 #: src/components/contacts/components/HeroImage.tsx:28 1111 - #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:71 1112 msgid "An illustration depicting user avatars flowing from a contact book into the Bluesky app" 1113 msgstr "" 1114 ··· 1272 1273 #: src/Navigation.tsx:393 1274 #: src/screens/Settings/AppearanceSettings.tsx:73 1275 - #: src/screens/Settings/Settings.tsx:226 1276 - #: src/screens/Settings/Settings.tsx:229 1277 msgid "Appearance" 1278 msgstr "" 1279 ··· 1282 msgid "Apply default recommended feeds" 1283 msgstr "" 1284 1285 - #: src/screens/Settings/Settings.tsx:512 1286 - #: src/screens/Settings/Settings.tsx:514 1287 msgid "Apply Pull Request" 1288 msgstr "" 1289 ··· 1448 msgid "Begin the age assurance process by completing the fields below." 1449 msgstr "" 1450 1451 - #: src/components/dialogs/BirthDateSettings.tsx:149 1452 msgid "Birthdate" 1453 msgstr "" 1454 ··· 1585 msgid "Bluesky is more fun with friends" 1586 msgstr "" 1587 1588 - #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:99 1589 msgid "Bluesky is more fun with friends! Import your contacts to see who’s already here." 1590 msgstr "" 1591 1592 - #: src/components/contacts/screens/ViewMatches.tsx:314 1593 msgid "Bluesky is more fun with friends. Do you want to invite some of yours? <0/>" 1594 msgstr "" 1595 ··· 1637 msgid "Breaking site rules" 1638 msgstr "" 1639 1640 - #: src/view/com/feeds/ProfileFeedgens.tsx:158 1641 - #: src/view/com/feeds/ProfileFeedgens.tsx:159 1642 msgid "Browse custom feeds" 1643 msgstr "" 1644 1645 - #: src/components/FeedInterstitials.tsx:547 1646 msgid "Browse more accounts" 1647 msgstr "" 1648 1649 - #: src/components/FeedInterstitials.tsx:676 1650 msgid "Browse more feeds on the Explore page" 1651 msgstr "" 1652 1653 - #: src/components/FeedInterstitials.tsx:657 1654 - #: src/components/FeedInterstitials.tsx:660 1655 msgid "Browse more suggestions" 1656 msgstr "" 1657 1658 - #: src/components/FeedInterstitials.tsx:685 1659 msgid "Browse more suggestions on the Explore page" 1660 msgstr "" 1661 ··· 1761 #: src/screens/Settings/components/ChangeHandleDialog.tsx:85 1762 #: src/screens/Settings/components/ChangePasswordDialog.tsx:247 1763 #: src/screens/Settings/components/ChangePasswordDialog.tsx:253 1764 - #: src/screens/Settings/Settings.tsx:303 1765 #: src/screens/Takendown.tsx:107 1766 #: src/screens/Takendown.tsx:110 1767 #: src/view/com/composer/Composer.tsx:1050 ··· 1997 msgid "Choose your username" 1998 msgstr "" 1999 2000 - #: src/screens/Settings/Settings.tsx:504 2001 msgid "Clear all storage data" 2002 msgstr "" 2003 2004 - #: src/screens/Settings/Settings.tsx:506 2005 msgid "Clear all storage data (restart after this)" 2006 msgstr "" 2007 ··· 2022 msgid "click here" 2023 msgstr "" 2024 2025 - #: src/ageAssurance/components/NoAccessScreen.tsx:114 2026 msgid "Click here to contact our support team" 2027 msgstr "" 2028 2029 - #: src/ageAssurance/components/NoAccessScreen.tsx:233 2030 msgid "Click here to log out" 2031 msgstr "" 2032 ··· 2034 msgid "Click here to restart the verification process." 2035 msgstr "" 2036 2037 - #: src/ageAssurance/components/NoAccessScreen.tsx:97 2038 - #: src/ageAssurance/components/NoAccessScreen.tsx:207 2039 msgid "Click here to update your birthdate" 2040 msgstr "" 2041 ··· 2121 msgid "Close dialog" 2122 msgstr "" 2123 2124 - #: src/view/shell/index.web.tsx:111 2125 msgid "Close drawer menu" 2126 msgstr "" 2127 ··· 2252 msgid "Confirm delete account" 2253 msgstr "" 2254 2255 - #: src/ageAssurance/components/NoAccessScreen.tsx:356 2256 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:87 2257 #: src/components/dialogs/DeviceLocationRequestDialog.tsx:40 2258 #: src/components/dialogs/DeviceLocationRequestDialog.tsx:105 ··· 2279 msgid "Connection issue" 2280 msgstr "" 2281 2282 - #: src/ageAssurance/components/NoAccessScreen.tsx:293 2283 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:130 2284 #: src/components/ageAssurance/AgeAssuranceAppealDialog.tsx:29 2285 msgid "Contact our moderation team" ··· 2312 msgid "Content & Media" 2313 msgstr "" 2314 2315 - #: src/screens/Settings/Settings.tsx:208 2316 - #: src/screens/Settings/Settings.tsx:211 2317 msgid "Content and media" 2318 msgstr "" 2319 ··· 2581 msgid "Could not upload contacts. You need to re-verify your phone number to proceed" 2582 msgstr "" 2583 2584 - #: src/components/InternationalPhoneCodeSelect.tsx:79 2585 msgid "Country code" 2586 msgstr "" 2587 ··· 2593 msgid "Create" 2594 msgstr "" 2595 2596 - #: src/view/com/lists/ProfileLists.tsx:159 2597 - #: src/view/com/lists/ProfileLists.tsx:160 2598 msgid "Create a list" 2599 msgstr "" 2600 ··· 2608 msgid "Create a starter pack" 2609 msgstr "" 2610 2611 - #: src/view/screens/Profile.tsx:542 2612 - #: src/view/screens/Profile.tsx:543 2613 msgid "Create a Starter Pack" 2614 msgstr "" 2615 ··· 2741 msgid "Deactivate account" 2742 msgstr "" 2743 2744 - #: src/screens/Settings/Settings.tsx:469 2745 msgid "Debug Moderation" 2746 msgstr "" 2747 ··· 2794 msgid "Delete chat" 2795 msgstr "" 2796 2797 - #: src/screens/Settings/Settings.tsx:476 2798 msgid "Delete chat declaration record" 2799 msgstr "" 2800 ··· 2907 msgid "Developer mode enabled" 2908 msgstr "" 2909 2910 - #: src/screens/Settings/Settings.tsx:285 2911 - #: src/screens/Settings/Settings.tsx:288 2912 msgid "Developer options" 2913 msgstr "" 2914 ··· 3018 msgid "Dismiss this section" 3019 msgstr "" 3020 3021 #: src/screens/Settings/AccessibilitySettings.tsx:69 3022 #: src/screens/Settings/AccessibilitySettings.tsx:74 3023 msgid "Display larger alt text badges" ··· 3068 3069 #: src/components/contacts/components/InviteInfo.tsx:72 3070 #: src/components/contacts/components/InviteInfo.tsx:78 3071 - #: src/components/contacts/screens/ViewMatches.tsx:394 3072 - #: src/components/contacts/screens/ViewMatches.tsx:411 3073 - #: src/components/dialogs/BirthDateSettings.tsx:183 3074 - #: src/components/dialogs/BirthDateSettings.tsx:190 3075 #: src/components/dialogs/ServerInput.tsx:240 3076 #: src/components/dialogs/ServerInput.tsx:242 3077 #: src/components/dms/AfterReportDialog.tsx:142 ··· 3445 msgid "Enter the username or email address you used when you created your account" 3446 msgstr "" 3447 3448 - #: src/components/dialogs/BirthDateSettings.tsx:150 3449 msgid "Enter your birthdate" 3450 msgstr "" 3451 ··· 3695 msgid "Failed to follow all suggested accounts, please try again" 3696 msgstr "" 3697 3698 - #: src/components/contacts/screens/ViewMatches.tsx:147 3699 msgid "Failed to follow all your friends, please try again" 3700 msgstr "" 3701 3702 - #: src/components/contacts/screens/ViewMatches.tsx:235 3703 msgid "Failed to hide suggestion, please check your internet connection" 3704 msgstr "" 3705 3706 - #: src/components/contacts/screens/ViewMatches.tsx:580 3707 msgid "Failed to launch SMS app" 3708 msgstr "" 3709 ··· 3991 msgid "Find Friends" 3992 msgstr "" 3993 3994 - #: src/screens/Settings/Settings.tsx:217 3995 - #: src/screens/Settings/Settings.tsx:220 3996 msgid "Find friends from contacts" 3997 msgstr "" 3998 ··· 4013 msgid "Find posts, users, and feeds on Bluesky" 4014 msgstr "" 4015 4016 - #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:89 4017 msgid "Find your friends" 4018 msgstr "" 4019 ··· 4088 msgid "Follow account" 4089 msgstr "" 4090 4091 - #: src/components/contacts/screens/ViewMatches.tsx:275 4092 - #: src/components/contacts/screens/ViewMatches.tsx:290 4093 #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:265 4094 #: src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx:156 4095 #: src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx:163 ··· 4203 4204 #: src/lib/interests.ts:61 4205 msgid "Food" 4206 msgstr "" 4207 4208 #: src/view/com/modals/DeleteAccount.tsx:125 ··· 4527 msgid "Held by Bluesky for 7 days to prevent abuse, then deleted" 4528 msgstr "" 4529 4530 - #: src/screens/Settings/Settings.tsx:250 4531 #: src/screens/Settings/Settings.tsx:254 4532 #: src/view/shell/desktop/RightNav.tsx:123 4533 #: src/view/shell/desktop/RightNav.tsx:124 4534 #: src/view/shell/Drawer.tsx:381 ··· 4548 msgid "Hey there 👋" 4549 msgstr "" 4550 4551 - #: src/ageAssurance/components/NoAccessScreen.tsx:158 4552 msgid "Hey there!" 4553 msgstr "" 4554 4555 - #: src/ageAssurance/components/NoAccessScreen.tsx:189 4556 msgid "Hi there!" 4557 msgstr "" 4558 ··· 4652 msgid "Hides the content" 4653 msgstr "" 4654 4655 - #: src/ageAssurance/components/NoAccessScreen.tsx:216 4656 msgid "Hmm, it looks like you're logged in with an <0>App Password</0>. To set your birthdate, you'll need to log in with your main account password, or ask whomever controls this account to do so." 4657 msgstr "" 4658 ··· 4745 msgid "I understand" 4746 msgstr "" 4747 4748 - #: src/components/contacts/screens/ViewMatches.tsx:576 4749 msgid "I'm on Bluesky as {0} - come find me! https://bsky.app/download" 4750 msgstr "" 4751 ··· 4757 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." 4758 msgstr "" 4759 4760 - #: src/ageAssurance/components/NoAccessScreen.tsx:110 4761 msgid "If you believe your birthdate is incorrect, please <0>contact our support team</0>." 4762 msgstr "" 4763 4764 - #: src/ageAssurance/components/NoAccessScreen.tsx:94 4765 msgid "If you believe your birthdate is incorrect, you can update it by <0>clicking here</0>." 4766 msgstr "" 4767 ··· 4835 msgid "Import contacts" 4836 msgstr "" 4837 4838 - #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:107 4839 - #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:118 4840 msgid "Import Contacts" 4841 msgstr "" 4842 ··· 4845 msgid "Import contacts to find your friends" 4846 msgstr "" 4847 4848 - #: src/ageAssurance/components/NoAccessScreen.tsx:192 4849 msgid "In order to provide an age-appropriate experience, we need to know your birthdate. This is a one-time thing, and your data will be kept private." 4850 msgstr "" 4851 ··· 4918 msgid "Introducing activity notifications" 4919 msgstr "" 4920 4921 - #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:48 4922 msgid "Introducing finding friends via contacts" 4923 msgstr "" 4924 ··· 4953 msgid "Invalid Verification Code" 4954 msgstr "" 4955 4956 - #: src/components/contacts/screens/ViewMatches.tsx:585 4957 msgid "Invite" 4958 msgstr "" 4959 4960 - #: src/components/contacts/screens/ViewMatches.tsx:565 4961 msgid "Invite {name} to join Bluesky" 4962 msgstr "" 4963 ··· 4974 msgid "Invite Friends" 4975 msgstr "" 4976 4977 - #: src/components/contacts/screens/ViewMatches.tsx:300 4978 msgid "Invite friends <0/>" 4979 msgstr "" 4980 ··· 4990 msgid "Invites, but personal" 4991 msgstr "" 4992 4993 - #: src/ageAssurance/components/NoAccessScreen.tsx:353 4994 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:84 4995 msgid "Is your location not accurate? <0>Tap here to confirm your location.</0>" 4996 msgstr "" ··· 5078 msgstr "" 5079 5080 #: src/screens/Settings/LanguageSettings.tsx:78 5081 - #: src/screens/Settings/Settings.tsx:242 5082 - #: src/screens/Settings/Settings.tsx:245 5083 msgid "Languages" 5084 msgstr "" 5085 ··· 5087 msgid "Larger" 5088 msgstr "" 5089 5090 - #: src/ageAssurance/components/NoAccessScreen.tsx:336 5091 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:185 5092 msgid "Last initiated {timeAgo} ago" 5093 msgstr "" 5094 5095 - #: src/ageAssurance/components/NoAccessScreen.tsx:334 5096 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:183 5097 msgid "Last initiated just now" 5098 msgstr "" ··· 5401 msgstr "" 5402 5403 #: src/view/com/lists/MyLists.tsx:72 5404 - #: src/view/com/lists/ProfileLists.tsx:155 5405 msgid "Lists allow you to see content from your favorite people." 5406 msgstr "" 5407 ··· 5628 5629 #: src/Navigation.tsx:179 5630 #: src/screens/Moderation/index.tsx:99 5631 - #: src/screens/Settings/Settings.tsx:192 5632 - #: src/screens/Settings/Settings.tsx:195 5633 msgid "Moderation" 5634 msgstr "" 5635 ··· 5818 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." 5819 msgstr "" 5820 5821 - #: src/components/dialogs/BirthDateSettings.tsx:43 5822 #: src/components/dialogs/BirthDateSettings.tsx:47 5823 msgid "My Birthdate" 5824 msgstr "" 5825 ··· 5932 #: src/screens/ProfileList/index.tsx:284 5933 #: src/view/screens/Feeds.tsx:552 5934 #: src/view/screens/Notifications.tsx:167 5935 - #: src/view/screens/Profile.tsx:571 5936 msgid "New post" 5937 msgstr "" 5938 ··· 5974 msgid "News" 5975 msgstr "" 5976 5977 - #: src/components/contacts/screens/ViewMatches.tsx:394 5978 - #: src/components/contacts/screens/ViewMatches.tsx:409 5979 #: src/screens/Login/ForgotPasswordForm.tsx:137 5980 #: src/screens/Login/ForgotPasswordForm.tsx:143 5981 #: src/screens/Login/LoginForm.tsx:346 ··· 6006 msgid "No app passwords yet" 6007 msgstr "" 6008 6009 - #: src/components/contacts/screens/ViewMatches.tsx:679 6010 msgid "No contacts found" 6011 msgstr "" 6012 6013 - #: src/components/contacts/screens/ViewMatches.tsx:657 6014 msgid "No contacts with the name “{query}” found" 6015 msgstr "" 6016 6017 #: src/screens/Settings/components/ChangeHandleDialog.tsx:408 ··· 6041 6042 #: src/components/LikedByList.tsx:84 6043 #: src/view/com/post-thread/PostLikedBy.tsx:84 6044 - #: src/view/screens/Profile.tsx:511 6045 msgid "No likes yet" 6046 msgstr "" 6047 6048 #: src/components/ProfileCard.tsx:531 ··· 6051 msgid "No longer following {0}" 6052 msgstr "" 6053 6054 - #: src/view/screens/Profile.tsx:467 6055 msgid "No media yet" 6056 msgstr "" 6057 ··· 6063 msgid "No more doomscrolling junk-filled algorithms. Find feeds that work for you, not against you." 6064 msgstr "" 6065 6066 - #: src/components/contacts/screens/ViewMatches.tsx:561 6067 msgid "No name" 6068 msgstr "" 6069 ··· 6096 msgid "No quotes yet" 6097 msgstr "" 6098 6099 - #: src/view/screens/Profile.tsx:452 6100 msgid "No replies yet" 6101 msgstr "" 6102 ··· 6139 msgid "No search results found for \"{search}\"." 6140 msgstr "" 6141 6142 #: src/components/dialogs/EmbedConsent.tsx:104 6143 #: src/components/dialogs/EmbedConsent.tsx:111 6144 msgid "No thanks" 6145 msgstr "" 6146 6147 - #: src/view/screens/Profile.tsx:489 6148 msgid "No video posts yet" 6149 msgstr "" 6150 ··· 6244 #: src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx:30 6245 #: src/screens/Settings/NotificationSettings/RepostNotificationSettings.tsx:30 6246 #: src/screens/Settings/NotificationSettings/RepostsOnRepostsNotificationSettings.tsx:30 6247 - #: src/screens/Settings/Settings.tsx:200 6248 - #: src/screens/Settings/Settings.tsx:203 6249 #: src/view/screens/Notifications.tsx:130 6250 #: src/view/shell/bottom-bar/BottomBar.tsx:252 6251 #: src/view/shell/desktop/LeftNav.tsx:709 ··· 6310 msgid "on<0><1/><2><3/></2></0>" 6311 msgstr "" 6312 6313 - #: src/screens/Settings/Settings.tsx:402 6314 msgid "Onboarding reset" 6315 msgstr "" 6316 ··· 6412 msgid "Open message options" 6413 msgstr "" 6414 6415 - #: src/screens/Settings/Settings.tsx:467 6416 msgid "Open moderation debug page" 6417 msgstr "" 6418 ··· 6441 msgid "Open starter pack menu" 6442 msgstr "" 6443 6444 - #: src/screens/Settings/Settings.tsx:460 6445 - #: src/screens/Settings/Settings.tsx:474 6446 msgid "Open storybook page" 6447 msgstr "" 6448 6449 - #: src/screens/Settings/Settings.tsx:453 6450 msgid "Open system log" 6451 msgstr "" 6452 ··· 6509 msgid "Opens GIF select dialog" 6510 msgstr "" 6511 6512 - #: src/screens/Settings/Settings.tsx:251 6513 msgid "Opens helpdesk in browser" 6514 msgstr "" 6515 ··· 6966 msgid "Post" 6967 msgstr "" 6968 6969 - #: src/view/screens/Profile.tsx:469 6970 - #: src/view/screens/Profile.tsx:470 6971 msgid "Post a photo" 6972 msgstr "" 6973 6974 - #: src/view/screens/Profile.tsx:491 6975 - #: src/view/screens/Profile.tsx:492 6976 msgid "Post a video" 6977 msgstr "" 6978 ··· 7116 msgid "Privacy" 7117 msgstr "" 7118 7119 - #: src/screens/Settings/Settings.tsx:186 7120 - #: src/screens/Settings/Settings.tsx:189 7121 msgid "Privacy and security" 7122 msgstr "" 7123 ··· 7395 #: src/components/StarterPack/Wizard/WizardListCard.tsx:105 7396 #: src/components/StarterPack/Wizard/WizardListCard.tsx:112 7397 #: src/screens/Bookmarks/index.tsx:266 7398 - #: src/screens/Settings/Settings.tsx:678 7399 #: src/view/com/modals/UserAddRemoveLists.tsx:235 7400 #: src/view/com/posts/PostFeedErrorMessage.tsx:220 7401 msgid "Remove" ··· 7409 msgid "Remove {historyItem}" 7410 msgstr "" 7411 7412 - #: src/screens/Settings/Settings.tsx:657 7413 - #: src/screens/Settings/Settings.tsx:660 7414 msgid "Remove account" 7415 msgstr "" 7416 ··· 7455 msgid "Remove from my feeds" 7456 msgstr "" 7457 7458 - #: src/screens/Settings/Settings.tsx:670 7459 msgid "Remove from quick access?" 7460 msgstr "" 7461 ··· 7499 msgid "Remove subtitle file" 7500 msgstr "" 7501 7502 - #: src/components/contacts/screens/ViewMatches.tsx:499 7503 #: src/screens/Settings/FindContactsSettings.tsx:323 7504 msgid "Remove suggestion" 7505 msgstr "" ··· 7830 msgid "Resend Verification Email" 7831 msgstr "" 7832 7833 - #: src/screens/Settings/Settings.tsx:496 7834 - #: src/screens/Settings/Settings.tsx:498 7835 msgid "Reset activity subscription nudge" 7836 msgstr "" 7837 ··· 7839 msgid "Reset code" 7840 msgstr "" 7841 7842 - #: src/screens/Settings/Settings.tsx:481 7843 - #: src/screens/Settings/Settings.tsx:483 7844 msgid "Reset onboarding state" 7845 msgstr "" 7846 ··· 7916 msgid "Returns to the previous step" 7917 msgstr "" 7918 7919 - #: src/components/dialogs/BirthDateSettings.tsx:190 7920 #: src/components/dialogs/lists/CreateOrEditListDialog.tsx:292 7921 #: src/components/dialogs/lists/CreateOrEditListDialog.tsx:307 7922 #: src/components/dialogs/PostInteractionSettingsDialog.tsx:662 ··· 7942 msgid "Save" 7943 msgstr "" 7944 7945 - #: src/components/dialogs/BirthDateSettings.tsx:183 7946 msgid "Save birthdate" 7947 msgstr "" 7948 ··· 8042 msgid "Search by name or interest" 8043 msgstr "" 8044 8045 - #: src/components/contacts/screens/ViewMatches.tsx:355 8046 msgid "Search contacts" 8047 msgstr "" 8048 ··· 8149 msgid "See jobs at Bluesky" 8150 msgstr "" 8151 8152 - #: src/components/FeedInterstitials.tsx:499 8153 - #: src/components/FeedInterstitials.tsx:562 8154 msgid "See more" 8155 msgstr "" 8156 8157 - #: src/components/FeedInterstitials.tsx:481 8158 msgid "See more suggested profiles" 8159 msgstr "" 8160 ··· 8281 msgid "Select subtitle file (.vtt)" 8282 msgstr "" 8283 8284 - #: src/components/InternationalPhoneCodeSelect.tsx:67 8285 msgid "Select telephone code" 8286 msgstr "" 8287 ··· 8421 msgid "Set who can reply to your post" 8422 msgstr "" 8423 8424 - #: src/ageAssurance/components/NoAccessScreen.tsx:199 8425 msgid "Set your birthdate below and we'll get you back to posting and exploring in no time!" 8426 msgstr "" 8427 ··· 8430 msgstr "" 8431 8432 #: src/Navigation.tsx:215 8433 - #: src/screens/Settings/Settings.tsx:103 8434 #: src/view/shell/desktop/LeftNav.tsx:805 8435 #: src/view/shell/Drawer.tsx:609 8436 msgid "Settings" ··· 8680 msgid "Shows information about when this post was created" 8681 msgstr "" 8682 8683 - #: src/screens/Settings/Settings.tsx:129 8684 msgid "Shows other accounts you can switch to" 8685 msgstr "" 8686 ··· 8741 msgid "Sign in to view post" 8742 msgstr "" 8743 8744 - #: src/screens/Settings/Settings.tsx:268 8745 - #: src/screens/Settings/Settings.tsx:270 8746 - #: src/screens/Settings/Settings.tsx:302 8747 #: src/screens/SignupQueued.tsx:93 8748 #: src/screens/SignupQueued.tsx:96 8749 #: src/screens/Takendown.tsx:93 ··· 8757 msgid "Sign Out" 8758 msgstr "" 8759 8760 - #: src/screens/Settings/Settings.tsx:299 8761 #: src/view/shell/desktop/LeftNav.tsx:209 8762 msgid "Sign out?" 8763 msgstr "" ··· 8772 msgid "Signed in as @{0}" 8773 msgstr "" 8774 8775 - #: src/components/FeedInterstitials.tsx:476 8776 msgid "Similar accounts" 8777 msgstr "" 8778 ··· 8823 msgid "Some of your verifications are invalid." 8824 msgstr "" 8825 8826 - #: src/components/FeedInterstitials.tsx:639 8827 msgid "Some other feeds you might like" 8828 msgstr "" 8829 ··· 8880 msgid "Sorry, we're unable to load account suggestions at this time." 8881 msgstr "" 8882 8883 - #: src/App.native.tsx:127 8884 - #: src/App.web.tsx:100 8885 msgid "Sorry! Your session expired. Please sign in again." 8886 msgstr "" 8887 ··· 8969 msgid "Starter packs let you easily share your favorite feeds and people with your friends." 8970 msgstr "" 8971 8972 - #: src/view/screens/Profile.tsx:539 8973 - msgid "Starter packs let you share your favorite feeds and people with your friends." 8974 msgstr "" 8975 8976 #: src/screens/Settings/AboutSettings.tsx:100 ··· 8983 msgid "Step {0} of {1}" 8984 msgstr "" 8985 8986 - #: src/screens/Settings/Settings.tsx:407 8987 msgid "Storage cleared, you need to restart the app now." 8988 msgstr "" 8989 ··· 8992 msgstr "" 8993 8994 #: src/Navigation.tsx:308 8995 - #: src/screens/Settings/Settings.tsx:462 8996 msgid "Storybook" 8997 msgstr "" 8998 ··· 9062 msgstr "" 9063 9064 #. Accounts suggested to the user for them to follow 9065 - #: src/components/FeedInterstitials.tsx:474 9066 #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:155 9067 msgid "Suggested for you" 9068 msgstr "" ··· 9092 msgid "Support for this feature in your country has not been enabled yet! Please check back later." 9093 msgstr "" 9094 9095 - #: src/screens/Settings/Settings.tsx:127 9096 - #: src/screens/Settings/Settings.tsx:141 9097 - #: src/screens/Settings/Settings.tsx:620 9098 #: src/view/shell/desktop/LeftNav.tsx:247 9099 msgid "Switch account" 9100 msgstr "" ··· 9122 #: src/screens/Log.tsx:58 9123 #: src/screens/Settings/AboutSettings.tsx:107 9124 #: src/screens/Settings/AboutSettings.tsx:110 9125 - #: src/screens/Settings/Settings.tsx:455 9126 msgid "System log" 9127 msgstr "" 9128 ··· 9193 msgid "Terms" 9194 msgstr "" 9195 9196 - #: src/components/dialogs/BirthDateSettings.tsx:169 9197 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:30 9198 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:97 9199 #: src/Navigation.tsx:338 ··· 9222 msgid "Thanks, you have successfully verified your email address. You can close this dialog." 9223 msgstr "" 9224 9225 - #: src/ageAssurance/components/NoAccessScreen.tsx:382 9226 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:113 9227 msgid "Thanks! You're all set." 9228 msgstr "" ··· 9268 msgid "The author of this thread has hidden this reply." 9269 msgstr "" 9270 9271 - #: src/components/dialogs/BirthDateSettings.tsx:156 9272 msgid "The birthdate you've entered means you are under 18 years old. Certain content and features may be unavailable to you." 9273 msgstr "" 9274 ··· 9364 msgid "Theme" 9365 msgstr "" 9366 9367 - #: src/components/dialogs/BirthDateSettings.tsx:91 9368 msgid "There is a limit to how often you can change your birthdate. You may need to wait a day or two before updating it again." 9369 msgstr "" 9370 ··· 9409 msgid "There was an issue fetching your app passwords" 9410 msgstr "" 9411 9412 - #: src/view/com/feeds/ProfileFeedgens.tsx:174 9413 - #: src/view/com/lists/ProfileLists.tsx:175 9414 msgid "There was an issue fetching your lists. Tap here to try again." 9415 msgstr "" 9416 ··· 9588 msgid "This handle is reserved. Please try a different one." 9589 msgstr "" 9590 9591 - #: src/components/dialogs/BirthDateSettings.tsx:51 9592 msgid "This information is private and not shared with other users." 9593 msgstr "" 9594 ··· 9718 msgid "This will delete \"{0}\" from your muted words. You can always add it back later." 9719 msgstr "" 9720 9721 - #: src/screens/Settings/Settings.tsx:672 9722 msgid "This will remove @{0} from the quick access list." 9723 msgstr "" 9724 ··· 9766 msgid "To disable your email 2FA method, please verify your access to <0>{0}</0>" 9767 msgstr "" 9768 9769 - #: src/ageAssurance/components/NoAccessScreen.tsx:230 9770 msgid "To log out, <0>click here</0>." 9771 msgstr "" 9772 ··· 9897 msgid "Unable to delete" 9898 msgstr "" 9899 9900 - #: src/screens/Settings/Settings.tsx:521 9901 msgid "Unapply Pull Request" 9902 msgstr "" 9903 9904 - #: src/screens/Settings/Settings.tsx:523 9905 msgid "Unapply Pull Request {currentChannel}" 9906 msgstr "" 9907 ··· 9981 msgid "Unfortunately, none of your subscribed labelers supports this report type." 9982 msgstr "" 9983 9984 - #: src/ageAssurance/components/NoAccessScreen.tsx:176 9985 msgid "Unfortunately, the birthdate you have saved to your profile makes you too young to access Bluesky." 9986 msgstr "" 9987 ··· 10089 msgid "Unpinned list" 10090 msgstr "" 10091 10092 - #: src/screens/Settings/Settings.tsx:488 10093 - #: src/screens/Settings/Settings.tsx:490 10094 msgid "Unsnooze email reminder" 10095 msgstr "" 10096 ··· 10342 msgid "Verify account" 10343 msgstr "" 10344 10345 - #: src/ageAssurance/components/NoAccessScreen.tsx:319 10346 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:168 10347 msgid "Verify again" 10348 msgstr "" ··· 10369 msgid "Verify email dialog" 10370 msgstr "" 10371 10372 - #: src/ageAssurance/components/NoAccessScreen.tsx:307 10373 - #: src/ageAssurance/components/NoAccessScreen.tsx:321 10374 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:156 10375 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:170 10376 msgid "Verify now" ··· 10709 msgid "We were unable to determine if you are allowed to upload videos. Please try again." 10710 msgstr "" 10711 10712 - #: src/components/dialogs/BirthDateSettings.tsx:63 10713 msgid "We were unable to load your birthdate preferences. Please try again." 10714 msgstr "" 10715 ··· 10768 msgid "We're so excited to have you join us!" 10769 msgstr "" 10770 10771 - #: src/ageAssurance/components/NoAccessScreen.tsx:375 10772 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:106 10773 msgid "We're sorry, but based on your device's location, you are currently located in a region that requires age assurance." 10774 msgstr "" ··· 10916 msgid "Write a message" 10917 msgstr "" 10918 10919 - #: src/view/screens/Profile.tsx:433 10920 - #: src/view/screens/Profile.tsx:434 10921 msgid "Write a post" 10922 msgstr "" 10923 ··· 10976 msgid "You are a trusted verifier" 10977 msgstr "" 10978 10979 - #: src/ageAssurance/components/NoAccessScreen.tsx:161 10980 msgid "You are accessing Bluesky from a region that legally requires us to verify your age before allowing you to access the app." 10981 msgstr "" 10982 ··· 10984 msgid "You are creating an account on" 10985 msgstr "" 10986 10987 - #: src/ageAssurance/components/NoAccessScreen.tsx:289 10988 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:126 10989 msgid "You are currently unable to access Bluesky's Age Assurance flow. Please <0>contact our moderation team</0> if you believe this is an error." 10990 msgstr "" ··· 11117 msgid "You don't have any saved feeds." 11118 msgstr "" 11119 11120 - #: src/components/contacts/screens/ViewMatches.tsx:311 11121 msgid "You got here first" 11122 msgstr "" 11123 ··· 11194 msgid "You haven't created a starter pack yet!" 11195 msgstr "" 11196 11197 - #: src/view/com/feeds/ProfileFeedgens.tsx:155 11198 msgid "You haven't made any custom feeds yet." 11199 msgstr "" 11200 ··· 11239 msgid "You must be 13 years of age or older to create an account." 11240 msgstr "" 11241 11242 - #: src/components/dialogs/BirthDateSettings.tsx:165 11243 msgid "You must be at least 13 years old to use Bluesky. Read our <0>Terms of Service</0> for more information." 11244 msgstr "" 11245 ··· 11272 msgid "You previously deactivated @{0}." 11273 msgstr "" 11274 11275 - #: src/screens/Settings/Settings.tsx:418 11276 msgid "You probably want to restart the app now." 11277 msgstr "" 11278 ··· 11284 msgid "You reacted {0} to {1}" 11285 msgstr "" 11286 11287 - #: src/components/dialogs/BirthDateSettings.tsx:77 11288 - #: src/components/dialogs/BirthDateSettings.tsx:87 11289 msgid "You recently changed your birthdate" 11290 msgstr "" 11291 11292 - #: src/screens/Settings/Settings.tsx:300 11293 #: src/view/shell/desktop/LeftNav.tsx:210 11294 msgid "You will be signed out of all your accounts." 11295 msgstr "" ··· 11456 msgid "Your contact {firstAuthorName} is on Bluesky" 11457 msgstr "" 11458 11459 - #: src/components/contacts/screens/ViewMatches.tsx:453 11460 msgid "Your contact {name}" 11461 msgstr "" 11462
··· 38 msgid "{0, plural, one {# following} other {# following}}" 39 msgstr "" 40 41 + #: src/components/contacts/screens/ViewMatches.tsx:265 42 msgid "{0, plural, one {# friend found!} other {# friends found!}}" 43 msgstr "" 44 ··· 576 577 #: src/Navigation.tsx:534 578 #: src/screens/Settings/AboutSettings.tsx:75 579 + #: src/screens/Settings/Settings.tsx:262 580 + #: src/screens/Settings/Settings.tsx:265 581 msgid "About" 582 msgstr "" 583 ··· 604 msgstr "" 605 606 #: src/screens/Settings/AccessibilitySettings.tsx:44 607 + #: src/screens/Settings/Settings.tsx:238 608 + #: src/screens/Settings/Settings.tsx:241 609 msgid "Accessibility" 610 msgstr "" 611 ··· 616 #: src/Navigation.tsx:401 617 #: src/screens/Login/LoginForm.tsx:194 618 #: src/screens/Settings/AccountSettings.tsx:51 619 + #: src/screens/Settings/Settings.tsx:180 620 + #: src/screens/Settings/Settings.tsx:183 621 msgid "Account" 622 msgstr "" 623 ··· 648 msgid "Account Muted by List" 649 msgstr "" 650 651 + #: src/screens/Settings/Settings.tsx:644 652 msgid "Account options" 653 msgstr "" 654 ··· 656 msgid "Account provider" 657 msgstr "" 658 659 + #: src/screens/Settings/Settings.tsx:680 660 msgid "Account removed from quick access" 661 msgstr "" 662 ··· 741 msgid "Add alt text (optional)" 742 msgstr "" 743 744 + #: src/screens/Settings/Settings.tsx:584 745 + #: src/screens/Settings/Settings.tsx:587 746 #: src/view/shell/desktop/LeftNav.tsx:262 747 #: src/view/shell/desktop/LeftNav.tsx:266 748 msgid "Add another account" ··· 844 msgid "Add user to list" 845 msgstr "" 846 847 + #: src/ageAssurance/components/NoAccessScreen.tsx:222 848 msgid "Add your birthdate" 849 msgstr "" 850 ··· 914 msgid "Age assurance inquiry was submitted" 915 msgstr "" 916 917 + #: src/ageAssurance/components/NoAccessScreen.tsx:345 918 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:191 919 msgid "Age assurance only takes a few minutes" 920 msgstr "" ··· 934 msgid "All accounts have been followed!" 935 msgstr "" 936 937 + #: src/components/contacts/screens/ViewMatches.tsx:141 938 msgid "All friends followed!" 939 msgstr "" 940 ··· 1070 msgid "An error occurred while generating your starter pack. Want to try again?" 1071 msgstr "" 1072 1073 + #: src/components/contacts/screens/ViewMatches.tsx:240 1074 msgid "An error occurred while hiding suggestion. {0}" 1075 msgstr "" 1076 ··· 1108 msgstr "" 1109 1110 #: src/components/contacts/components/HeroImage.tsx:28 1111 + #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:78 1112 msgid "An illustration depicting user avatars flowing from a contact book into the Bluesky app" 1113 msgstr "" 1114 ··· 1272 1273 #: src/Navigation.tsx:393 1274 #: src/screens/Settings/AppearanceSettings.tsx:73 1275 + #: src/screens/Settings/Settings.tsx:230 1276 + #: src/screens/Settings/Settings.tsx:233 1277 msgid "Appearance" 1278 msgstr "" 1279 ··· 1282 msgid "Apply default recommended feeds" 1283 msgstr "" 1284 1285 + #: src/screens/Settings/Settings.tsx:516 1286 + #: src/screens/Settings/Settings.tsx:518 1287 msgid "Apply Pull Request" 1288 msgstr "" 1289 ··· 1448 msgid "Begin the age assurance process by completing the fields below." 1449 msgstr "" 1450 1451 + #: src/components/dialogs/BirthDateSettings.tsx:162 1452 msgid "Birthdate" 1453 msgstr "" 1454 ··· 1585 msgid "Bluesky is more fun with friends" 1586 msgstr "" 1587 1588 + #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:106 1589 msgid "Bluesky is more fun with friends! Import your contacts to see who’s already here." 1590 msgstr "" 1591 1592 + #: src/components/contacts/screens/ViewMatches.tsx:312 1593 msgid "Bluesky is more fun with friends. Do you want to invite some of yours? <0/>" 1594 msgstr "" 1595 ··· 1637 msgid "Breaking site rules" 1638 msgstr "" 1639 1640 + #: src/view/com/feeds/ProfileFeedgens.tsx:167 1641 + #: src/view/com/feeds/ProfileFeedgens.tsx:168 1642 msgid "Browse custom feeds" 1643 msgstr "" 1644 1645 + #: src/components/FeedInterstitials.tsx:778 1646 msgid "Browse more accounts" 1647 msgstr "" 1648 1649 + #: src/components/FeedInterstitials.tsx:907 1650 msgid "Browse more feeds on the Explore page" 1651 msgstr "" 1652 1653 + #: src/components/FeedInterstitials.tsx:888 1654 + #: src/components/FeedInterstitials.tsx:891 1655 msgid "Browse more suggestions" 1656 msgstr "" 1657 1658 + #: src/components/FeedInterstitials.tsx:916 1659 msgid "Browse more suggestions on the Explore page" 1660 msgstr "" 1661 ··· 1761 #: src/screens/Settings/components/ChangeHandleDialog.tsx:85 1762 #: src/screens/Settings/components/ChangePasswordDialog.tsx:247 1763 #: src/screens/Settings/components/ChangePasswordDialog.tsx:253 1764 + #: src/screens/Settings/Settings.tsx:307 1765 #: src/screens/Takendown.tsx:107 1766 #: src/screens/Takendown.tsx:110 1767 #: src/view/com/composer/Composer.tsx:1050 ··· 1997 msgid "Choose your username" 1998 msgstr "" 1999 2000 + #: src/screens/Settings/Settings.tsx:508 2001 msgid "Clear all storage data" 2002 msgstr "" 2003 2004 + #: src/screens/Settings/Settings.tsx:510 2005 msgid "Clear all storage data (restart after this)" 2006 msgstr "" 2007 ··· 2022 msgid "click here" 2023 msgstr "" 2024 2025 + #: src/ageAssurance/components/NoAccessScreen.tsx:126 2026 msgid "Click here to contact our support team" 2027 msgstr "" 2028 2029 + #: src/ageAssurance/components/NoAccessScreen.tsx:236 2030 msgid "Click here to log out" 2031 msgstr "" 2032 ··· 2034 msgid "Click here to restart the verification process." 2035 msgstr "" 2036 2037 + #: src/ageAssurance/components/NoAccessScreen.tsx:103 2038 + #: src/ageAssurance/components/NoAccessScreen.tsx:219 2039 msgid "Click here to update your birthdate" 2040 msgstr "" 2041 ··· 2121 msgid "Close dialog" 2122 msgstr "" 2123 2124 + #: src/view/shell/index.web.tsx:113 2125 msgid "Close drawer menu" 2126 msgstr "" 2127 ··· 2252 msgid "Confirm delete account" 2253 msgstr "" 2254 2255 + #: src/ageAssurance/components/NoAccessScreen.tsx:359 2256 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:87 2257 #: src/components/dialogs/DeviceLocationRequestDialog.tsx:40 2258 #: src/components/dialogs/DeviceLocationRequestDialog.tsx:105 ··· 2279 msgid "Connection issue" 2280 msgstr "" 2281 2282 + #: src/ageAssurance/components/NoAccessScreen.tsx:296 2283 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:130 2284 #: src/components/ageAssurance/AgeAssuranceAppealDialog.tsx:29 2285 msgid "Contact our moderation team" ··· 2312 msgid "Content & Media" 2313 msgstr "" 2314 2315 + #: src/screens/Settings/Settings.tsx:210 2316 + #: src/screens/Settings/Settings.tsx:213 2317 msgid "Content and media" 2318 msgstr "" 2319 ··· 2581 msgid "Could not upload contacts. You need to re-verify your phone number to proceed" 2582 msgstr "" 2583 2584 + #: src/components/InternationalPhoneCodeSelect.tsx:80 2585 msgid "Country code" 2586 msgstr "" 2587 ··· 2593 msgid "Create" 2594 msgstr "" 2595 2596 + #: src/view/com/lists/ProfileLists.tsx:166 2597 + #: src/view/com/lists/ProfileLists.tsx:167 2598 msgid "Create a list" 2599 msgstr "" 2600 ··· 2608 msgid "Create a starter pack" 2609 msgstr "" 2610 2611 + #: src/view/screens/Profile.tsx:560 2612 + #: src/view/screens/Profile.tsx:561 2613 msgid "Create a Starter Pack" 2614 msgstr "" 2615 ··· 2741 msgid "Deactivate account" 2742 msgstr "" 2743 2744 + #: src/screens/Settings/Settings.tsx:473 2745 msgid "Debug Moderation" 2746 msgstr "" 2747 ··· 2794 msgid "Delete chat" 2795 msgstr "" 2796 2797 + #: src/screens/Settings/Settings.tsx:480 2798 msgid "Delete chat declaration record" 2799 msgstr "" 2800 ··· 2907 msgid "Developer mode enabled" 2908 msgstr "" 2909 2910 + #: src/screens/Settings/Settings.tsx:289 2911 + #: src/screens/Settings/Settings.tsx:292 2912 msgid "Developer options" 2913 msgstr "" 2914 ··· 3018 msgid "Dismiss this section" 3019 msgstr "" 3020 3021 + #: src/components/FeedInterstitials.tsx:587 3022 + msgid "Dismiss this suggestion" 3023 + msgstr "" 3024 + 3025 #: src/screens/Settings/AccessibilitySettings.tsx:69 3026 #: src/screens/Settings/AccessibilitySettings.tsx:74 3027 msgid "Display larger alt text badges" ··· 3072 3073 #: src/components/contacts/components/InviteInfo.tsx:72 3074 #: src/components/contacts/components/InviteInfo.tsx:78 3075 + #: src/components/contacts/screens/ViewMatches.tsx:392 3076 + #: src/components/contacts/screens/ViewMatches.tsx:409 3077 + #: src/components/dialogs/BirthDateSettings.tsx:196 3078 + #: src/components/dialogs/BirthDateSettings.tsx:203 3079 #: src/components/dialogs/ServerInput.tsx:240 3080 #: src/components/dialogs/ServerInput.tsx:242 3081 #: src/components/dms/AfterReportDialog.tsx:142 ··· 3449 msgid "Enter the username or email address you used when you created your account" 3450 msgstr "" 3451 3452 + #: src/components/dialogs/BirthDateSettings.tsx:163 3453 msgid "Enter your birthdate" 3454 msgstr "" 3455 ··· 3699 msgid "Failed to follow all suggested accounts, please try again" 3700 msgstr "" 3701 3702 + #: src/components/contacts/screens/ViewMatches.tsx:145 3703 msgid "Failed to follow all your friends, please try again" 3704 msgstr "" 3705 3706 + #: src/components/contacts/screens/ViewMatches.tsx:233 3707 msgid "Failed to hide suggestion, please check your internet connection" 3708 msgstr "" 3709 3710 + #: src/components/contacts/screens/ViewMatches.tsx:578 3711 msgid "Failed to launch SMS app" 3712 msgstr "" 3713 ··· 3995 msgid "Find Friends" 3996 msgstr "" 3997 3998 + #: src/screens/Settings/Settings.tsx:221 3999 + #: src/screens/Settings/Settings.tsx:224 4000 msgid "Find friends from contacts" 4001 msgstr "" 4002 ··· 4017 msgid "Find posts, users, and feeds on Bluesky" 4018 msgstr "" 4019 4020 + #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:96 4021 msgid "Find your friends" 4022 msgstr "" 4023 ··· 4092 msgid "Follow account" 4093 msgstr "" 4094 4095 + #: src/components/contacts/screens/ViewMatches.tsx:273 4096 + #: src/components/contacts/screens/ViewMatches.tsx:288 4097 #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:265 4098 #: src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx:156 4099 #: src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx:163 ··· 4207 4208 #: src/lib/interests.ts:61 4209 msgid "Food" 4210 + msgstr "" 4211 + 4212 + #: src/ageAssurance/components/NoAccessScreen.tsx:90 4213 + msgid "For organizational accounts, use the birthdate of the person who is responsible for the account." 4214 msgstr "" 4215 4216 #: src/view/com/modals/DeleteAccount.tsx:125 ··· 4535 msgid "Held by Bluesky for 7 days to prevent abuse, then deleted" 4536 msgstr "" 4537 4538 #: src/screens/Settings/Settings.tsx:254 4539 + #: src/screens/Settings/Settings.tsx:258 4540 #: src/view/shell/desktop/RightNav.tsx:123 4541 #: src/view/shell/desktop/RightNav.tsx:124 4542 #: src/view/shell/Drawer.tsx:381 ··· 4556 msgid "Hey there 👋" 4557 msgstr "" 4558 4559 + #: src/ageAssurance/components/NoAccessScreen.tsx:170 4560 msgid "Hey there!" 4561 msgstr "" 4562 4563 + #: src/ageAssurance/components/NoAccessScreen.tsx:201 4564 msgid "Hi there!" 4565 msgstr "" 4566 ··· 4660 msgid "Hides the content" 4661 msgstr "" 4662 4663 + #: src/components/dialogs/BirthDateSettings.tsx:74 4664 msgid "Hmm, it looks like you're logged in with an <0>App Password</0>. To set your birthdate, you'll need to log in with your main account password, or ask whomever controls this account to do so." 4665 msgstr "" 4666 ··· 4753 msgid "I understand" 4754 msgstr "" 4755 4756 + #: src/components/contacts/screens/ViewMatches.tsx:574 4757 msgid "I'm on Bluesky as {0} - come find me! https://bsky.app/download" 4758 msgstr "" 4759 ··· 4765 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." 4766 msgstr "" 4767 4768 + #: src/ageAssurance/components/NoAccessScreen.tsx:122 4769 msgid "If you believe your birthdate is incorrect, please <0>contact our support team</0>." 4770 msgstr "" 4771 4772 + #: src/ageAssurance/components/NoAccessScreen.tsx:100 4773 msgid "If you believe your birthdate is incorrect, you can update it by <0>clicking here</0>." 4774 msgstr "" 4775 ··· 4843 msgid "Import contacts" 4844 msgstr "" 4845 4846 + #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:114 4847 + #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:125 4848 msgid "Import Contacts" 4849 msgstr "" 4850 ··· 4853 msgid "Import contacts to find your friends" 4854 msgstr "" 4855 4856 + #: src/ageAssurance/components/NoAccessScreen.tsx:204 4857 msgid "In order to provide an age-appropriate experience, we need to know your birthdate. This is a one-time thing, and your data will be kept private." 4858 msgstr "" 4859 ··· 4926 msgid "Introducing activity notifications" 4927 msgstr "" 4928 4929 + #: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:55 4930 msgid "Introducing finding friends via contacts" 4931 msgstr "" 4932 ··· 4961 msgid "Invalid Verification Code" 4962 msgstr "" 4963 4964 + #: src/components/contacts/screens/ViewMatches.tsx:583 4965 msgid "Invite" 4966 msgstr "" 4967 4968 + #: src/components/contacts/screens/ViewMatches.tsx:563 4969 msgid "Invite {name} to join Bluesky" 4970 msgstr "" 4971 ··· 4982 msgid "Invite Friends" 4983 msgstr "" 4984 4985 + #: src/components/contacts/screens/ViewMatches.tsx:298 4986 msgid "Invite friends <0/>" 4987 msgstr "" 4988 ··· 4998 msgid "Invites, but personal" 4999 msgstr "" 5000 5001 + #: src/ageAssurance/components/NoAccessScreen.tsx:356 5002 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:84 5003 msgid "Is your location not accurate? <0>Tap here to confirm your location.</0>" 5004 msgstr "" ··· 5086 msgstr "" 5087 5088 #: src/screens/Settings/LanguageSettings.tsx:78 5089 + #: src/screens/Settings/Settings.tsx:246 5090 + #: src/screens/Settings/Settings.tsx:249 5091 msgid "Languages" 5092 msgstr "" 5093 ··· 5095 msgid "Larger" 5096 msgstr "" 5097 5098 + #: src/ageAssurance/components/NoAccessScreen.tsx:339 5099 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:185 5100 msgid "Last initiated {timeAgo} ago" 5101 msgstr "" 5102 5103 + #: src/ageAssurance/components/NoAccessScreen.tsx:337 5104 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:183 5105 msgid "Last initiated just now" 5106 msgstr "" ··· 5409 msgstr "" 5410 5411 #: src/view/com/lists/MyLists.tsx:72 5412 msgid "Lists allow you to see content from your favorite people." 5413 msgstr "" 5414 ··· 5635 5636 #: src/Navigation.tsx:179 5637 #: src/screens/Moderation/index.tsx:99 5638 + #: src/screens/Settings/Settings.tsx:194 5639 + #: src/screens/Settings/Settings.tsx:197 5640 msgid "Moderation" 5641 msgstr "" 5642 ··· 5825 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." 5826 msgstr "" 5827 5828 #: src/components/dialogs/BirthDateSettings.tsx:47 5829 + #: src/components/dialogs/BirthDateSettings.tsx:51 5830 msgid "My Birthdate" 5831 msgstr "" 5832 ··· 5939 #: src/screens/ProfileList/index.tsx:284 5940 #: src/view/screens/Feeds.tsx:552 5941 #: src/view/screens/Notifications.tsx:167 5942 + #: src/view/screens/Profile.tsx:591 5943 msgid "New post" 5944 msgstr "" 5945 ··· 5981 msgid "News" 5982 msgstr "" 5983 5984 + #: src/components/contacts/screens/ViewMatches.tsx:392 5985 + #: src/components/contacts/screens/ViewMatches.tsx:407 5986 #: src/screens/Login/ForgotPasswordForm.tsx:137 5987 #: src/screens/Login/ForgotPasswordForm.tsx:143 5988 #: src/screens/Login/LoginForm.tsx:346 ··· 6013 msgid "No app passwords yet" 6014 msgstr "" 6015 6016 + #: src/components/contacts/screens/ViewMatches.tsx:677 6017 msgid "No contacts found" 6018 msgstr "" 6019 6020 + #: src/components/contacts/screens/ViewMatches.tsx:655 6021 msgid "No contacts with the name “{query}” found" 6022 + msgstr "" 6023 + 6024 + #: src/view/com/feeds/ProfileFeedgens.tsx:161 6025 + msgid "No custom feeds yet" 6026 msgstr "" 6027 6028 #: src/screens/Settings/components/ChangeHandleDialog.tsx:408 ··· 6052 6053 #: src/components/LikedByList.tsx:84 6054 #: src/view/com/post-thread/PostLikedBy.tsx:84 6055 + #: src/view/screens/Profile.tsx:523 6056 msgid "No likes yet" 6057 + msgstr "" 6058 + 6059 + #: src/view/com/lists/ProfileLists.tsx:160 6060 + msgid "No lists" 6061 msgstr "" 6062 6063 #: src/components/ProfileCard.tsx:531 ··· 6066 msgid "No longer following {0}" 6067 msgstr "" 6068 6069 + #: src/view/screens/Profile.tsx:471 6070 msgid "No media yet" 6071 msgstr "" 6072 ··· 6078 msgid "No more doomscrolling junk-filled algorithms. Find feeds that work for you, not against you." 6079 msgstr "" 6080 6081 + #: src/components/contacts/screens/ViewMatches.tsx:559 6082 msgid "No name" 6083 msgstr "" 6084 ··· 6111 msgid "No quotes yet" 6112 msgstr "" 6113 6114 + #: src/view/screens/Profile.tsx:456 6115 msgid "No replies yet" 6116 msgstr "" 6117 ··· 6154 msgid "No search results found for \"{search}\"." 6155 msgstr "" 6156 6157 + #: src/view/screens/Profile.tsx:555 6158 + msgid "No Starter Packs yet" 6159 + msgstr "" 6160 + 6161 #: src/components/dialogs/EmbedConsent.tsx:104 6162 #: src/components/dialogs/EmbedConsent.tsx:111 6163 msgid "No thanks" 6164 msgstr "" 6165 6166 + #: src/view/screens/Profile.tsx:497 6167 msgid "No video posts yet" 6168 msgstr "" 6169 ··· 6263 #: src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx:30 6264 #: src/screens/Settings/NotificationSettings/RepostNotificationSettings.tsx:30 6265 #: src/screens/Settings/NotificationSettings/RepostsOnRepostsNotificationSettings.tsx:30 6266 + #: src/screens/Settings/Settings.tsx:202 6267 + #: src/screens/Settings/Settings.tsx:205 6268 #: src/view/screens/Notifications.tsx:130 6269 #: src/view/shell/bottom-bar/BottomBar.tsx:252 6270 #: src/view/shell/desktop/LeftNav.tsx:709 ··· 6329 msgid "on<0><1/><2><3/></2></0>" 6330 msgstr "" 6331 6332 + #: src/screens/Settings/Settings.tsx:406 6333 msgid "Onboarding reset" 6334 msgstr "" 6335 ··· 6431 msgid "Open message options" 6432 msgstr "" 6433 6434 + #: src/screens/Settings/Settings.tsx:471 6435 msgid "Open moderation debug page" 6436 msgstr "" 6437 ··· 6460 msgid "Open starter pack menu" 6461 msgstr "" 6462 6463 + #: src/screens/Settings/Settings.tsx:464 6464 + #: src/screens/Settings/Settings.tsx:478 6465 msgid "Open storybook page" 6466 msgstr "" 6467 6468 + #: src/screens/Settings/Settings.tsx:457 6469 msgid "Open system log" 6470 msgstr "" 6471 ··· 6528 msgid "Opens GIF select dialog" 6529 msgstr "" 6530 6531 + #: src/screens/Settings/Settings.tsx:255 6532 msgid "Opens helpdesk in browser" 6533 msgstr "" 6534 ··· 6985 msgid "Post" 6986 msgstr "" 6987 6988 + #: src/view/screens/Profile.tsx:475 6989 + #: src/view/screens/Profile.tsx:476 6990 msgid "Post a photo" 6991 msgstr "" 6992 6993 + #: src/view/screens/Profile.tsx:501 6994 + #: src/view/screens/Profile.tsx:502 6995 msgid "Post a video" 6996 msgstr "" 6997 ··· 7135 msgid "Privacy" 7136 msgstr "" 7137 7138 + #: src/screens/Settings/Settings.tsx:188 7139 + #: src/screens/Settings/Settings.tsx:191 7140 msgid "Privacy and security" 7141 msgstr "" 7142 ··· 7414 #: src/components/StarterPack/Wizard/WizardListCard.tsx:105 7415 #: src/components/StarterPack/Wizard/WizardListCard.tsx:112 7416 #: src/screens/Bookmarks/index.tsx:266 7417 + #: src/screens/Settings/Settings.tsx:682 7418 #: src/view/com/modals/UserAddRemoveLists.tsx:235 7419 #: src/view/com/posts/PostFeedErrorMessage.tsx:220 7420 msgid "Remove" ··· 7428 msgid "Remove {historyItem}" 7429 msgstr "" 7430 7431 + #: src/screens/Settings/Settings.tsx:661 7432 + #: src/screens/Settings/Settings.tsx:664 7433 msgid "Remove account" 7434 msgstr "" 7435 ··· 7474 msgid "Remove from my feeds" 7475 msgstr "" 7476 7477 + #: src/screens/Settings/Settings.tsx:674 7478 msgid "Remove from quick access?" 7479 msgstr "" 7480 ··· 7518 msgid "Remove subtitle file" 7519 msgstr "" 7520 7521 + #: src/components/contacts/screens/ViewMatches.tsx:497 7522 #: src/screens/Settings/FindContactsSettings.tsx:323 7523 msgid "Remove suggestion" 7524 msgstr "" ··· 7849 msgid "Resend Verification Email" 7850 msgstr "" 7851 7852 + #: src/screens/Settings/Settings.tsx:500 7853 + #: src/screens/Settings/Settings.tsx:502 7854 msgid "Reset activity subscription nudge" 7855 msgstr "" 7856 ··· 7858 msgid "Reset code" 7859 msgstr "" 7860 7861 + #: src/screens/Settings/Settings.tsx:485 7862 + #: src/screens/Settings/Settings.tsx:487 7863 msgid "Reset onboarding state" 7864 msgstr "" 7865 ··· 7935 msgid "Returns to the previous step" 7936 msgstr "" 7937 7938 + #: src/components/dialogs/BirthDateSettings.tsx:203 7939 #: src/components/dialogs/lists/CreateOrEditListDialog.tsx:292 7940 #: src/components/dialogs/lists/CreateOrEditListDialog.tsx:307 7941 #: src/components/dialogs/PostInteractionSettingsDialog.tsx:662 ··· 7961 msgid "Save" 7962 msgstr "" 7963 7964 + #: src/components/dialogs/BirthDateSettings.tsx:196 7965 msgid "Save birthdate" 7966 msgstr "" 7967 ··· 8061 msgid "Search by name or interest" 8062 msgstr "" 8063 8064 + #: src/components/contacts/screens/ViewMatches.tsx:353 8065 msgid "Search contacts" 8066 msgstr "" 8067 ··· 8168 msgid "See jobs at Bluesky" 8169 msgstr "" 8170 8171 + #: src/components/FeedInterstitials.tsx:730 8172 + #: src/components/FeedInterstitials.tsx:793 8173 msgid "See more" 8174 msgstr "" 8175 8176 + #: src/components/FeedInterstitials.tsx:712 8177 msgid "See more suggested profiles" 8178 msgstr "" 8179 ··· 8300 msgid "Select subtitle file (.vtt)" 8301 msgstr "" 8302 8303 + #: src/components/InternationalPhoneCodeSelect.tsx:68 8304 msgid "Select telephone code" 8305 msgstr "" 8306 ··· 8440 msgid "Set who can reply to your post" 8441 msgstr "" 8442 8443 + #: src/ageAssurance/components/NoAccessScreen.tsx:211 8444 msgid "Set your birthdate below and we'll get you back to posting and exploring in no time!" 8445 msgstr "" 8446 ··· 8449 msgstr "" 8450 8451 #: src/Navigation.tsx:215 8452 + #: src/screens/Settings/Settings.tsx:105 8453 #: src/view/shell/desktop/LeftNav.tsx:805 8454 #: src/view/shell/Drawer.tsx:609 8455 msgid "Settings" ··· 8699 msgid "Shows information about when this post was created" 8700 msgstr "" 8701 8702 + #: src/screens/Settings/Settings.tsx:131 8703 msgid "Shows other accounts you can switch to" 8704 msgstr "" 8705 ··· 8760 msgid "Sign in to view post" 8761 msgstr "" 8762 8763 + #: src/screens/Settings/Settings.tsx:272 8764 + #: src/screens/Settings/Settings.tsx:274 8765 + #: src/screens/Settings/Settings.tsx:306 8766 #: src/screens/SignupQueued.tsx:93 8767 #: src/screens/SignupQueued.tsx:96 8768 #: src/screens/Takendown.tsx:93 ··· 8776 msgid "Sign Out" 8777 msgstr "" 8778 8779 + #: src/screens/Settings/Settings.tsx:303 8780 #: src/view/shell/desktop/LeftNav.tsx:209 8781 msgid "Sign out?" 8782 msgstr "" ··· 8791 msgid "Signed in as @{0}" 8792 msgstr "" 8793 8794 + #: src/components/FeedInterstitials.tsx:707 8795 msgid "Similar accounts" 8796 msgstr "" 8797 ··· 8842 msgid "Some of your verifications are invalid." 8843 msgstr "" 8844 8845 + #: src/components/FeedInterstitials.tsx:870 8846 msgid "Some other feeds you might like" 8847 msgstr "" 8848 ··· 8899 msgid "Sorry, we're unable to load account suggestions at this time." 8900 msgstr "" 8901 8902 + #: src/App.native.tsx:126 8903 + #: src/App.web.tsx:99 8904 msgid "Sorry! Your session expired. Please sign in again." 8905 msgstr "" 8906 ··· 8988 msgid "Starter packs let you easily share your favorite feeds and people with your friends." 8989 msgstr "" 8990 8991 + #: src/view/screens/Profile.tsx:553 8992 + msgid "Starter Packs let you share your favorite feeds and people with your friends." 8993 msgstr "" 8994 8995 #: src/screens/Settings/AboutSettings.tsx:100 ··· 9002 msgid "Step {0} of {1}" 9003 msgstr "" 9004 9005 + #: src/screens/Settings/Settings.tsx:411 9006 msgid "Storage cleared, you need to restart the app now." 9007 msgstr "" 9008 ··· 9011 msgstr "" 9012 9013 #: src/Navigation.tsx:308 9014 + #: src/screens/Settings/Settings.tsx:466 9015 msgid "Storybook" 9016 msgstr "" 9017 ··· 9081 msgstr "" 9082 9083 #. Accounts suggested to the user for them to follow 9084 + #: src/components/FeedInterstitials.tsx:705 9085 #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:155 9086 msgid "Suggested for you" 9087 msgstr "" ··· 9111 msgid "Support for this feature in your country has not been enabled yet! Please check back later." 9112 msgstr "" 9113 9114 + #: src/screens/Settings/Settings.tsx:129 9115 + #: src/screens/Settings/Settings.tsx:143 9116 + #: src/screens/Settings/Settings.tsx:624 9117 #: src/view/shell/desktop/LeftNav.tsx:247 9118 msgid "Switch account" 9119 msgstr "" ··· 9141 #: src/screens/Log.tsx:58 9142 #: src/screens/Settings/AboutSettings.tsx:107 9143 #: src/screens/Settings/AboutSettings.tsx:110 9144 + #: src/screens/Settings/Settings.tsx:459 9145 msgid "System log" 9146 msgstr "" 9147 ··· 9212 msgid "Terms" 9213 msgstr "" 9214 9215 + #: src/components/dialogs/BirthDateSettings.tsx:182 9216 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:30 9217 #: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:97 9218 #: src/Navigation.tsx:338 ··· 9241 msgid "Thanks, you have successfully verified your email address. You can close this dialog." 9242 msgstr "" 9243 9244 + #: src/ageAssurance/components/NoAccessScreen.tsx:385 9245 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:113 9246 msgid "Thanks! You're all set." 9247 msgstr "" ··· 9287 msgid "The author of this thread has hidden this reply." 9288 msgstr "" 9289 9290 + #: src/components/dialogs/BirthDateSettings.tsx:169 9291 msgid "The birthdate you've entered means you are under 18 years old. Certain content and features may be unavailable to you." 9292 msgstr "" 9293 ··· 9383 msgid "Theme" 9384 msgstr "" 9385 9386 + #: src/components/dialogs/BirthDateSettings.tsx:104 9387 msgid "There is a limit to how often you can change your birthdate. You may need to wait a day or two before updating it again." 9388 msgstr "" 9389 ··· 9428 msgid "There was an issue fetching your app passwords" 9429 msgstr "" 9430 9431 + #: src/view/com/feeds/ProfileFeedgens.tsx:185 9432 + #: src/view/com/lists/ProfileLists.tsx:184 9433 msgid "There was an issue fetching your lists. Tap here to try again." 9434 msgstr "" 9435 ··· 9607 msgid "This handle is reserved. Please try a different one." 9608 msgstr "" 9609 9610 + #: src/components/dialogs/BirthDateSettings.tsx:55 9611 msgid "This information is private and not shared with other users." 9612 msgstr "" 9613 ··· 9737 msgid "This will delete \"{0}\" from your muted words. You can always add it back later." 9738 msgstr "" 9739 9740 + #: src/screens/Settings/Settings.tsx:676 9741 msgid "This will remove @{0} from the quick access list." 9742 msgstr "" 9743 ··· 9785 msgid "To disable your email 2FA method, please verify your access to <0>{0}</0>" 9786 msgstr "" 9787 9788 + #: src/ageAssurance/components/NoAccessScreen.tsx:233 9789 msgid "To log out, <0>click here</0>." 9790 msgstr "" 9791 ··· 9916 msgid "Unable to delete" 9917 msgstr "" 9918 9919 + #: src/screens/Settings/Settings.tsx:525 9920 msgid "Unapply Pull Request" 9921 msgstr "" 9922 9923 + #: src/screens/Settings/Settings.tsx:527 9924 msgid "Unapply Pull Request {currentChannel}" 9925 msgstr "" 9926 ··· 10000 msgid "Unfortunately, none of your subscribed labelers supports this report type." 10001 msgstr "" 10002 10003 + #: src/ageAssurance/components/NoAccessScreen.tsx:188 10004 msgid "Unfortunately, the birthdate you have saved to your profile makes you too young to access Bluesky." 10005 msgstr "" 10006 ··· 10108 msgid "Unpinned list" 10109 msgstr "" 10110 10111 + #: src/screens/Settings/Settings.tsx:492 10112 + #: src/screens/Settings/Settings.tsx:494 10113 msgid "Unsnooze email reminder" 10114 msgstr "" 10115 ··· 10361 msgid "Verify account" 10362 msgstr "" 10363 10364 + #: src/ageAssurance/components/NoAccessScreen.tsx:322 10365 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:168 10366 msgid "Verify again" 10367 msgstr "" ··· 10388 msgid "Verify email dialog" 10389 msgstr "" 10390 10391 + #: src/ageAssurance/components/NoAccessScreen.tsx:310 10392 + #: src/ageAssurance/components/NoAccessScreen.tsx:324 10393 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:156 10394 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:170 10395 msgid "Verify now" ··· 10728 msgid "We were unable to determine if you are allowed to upload videos. Please try again." 10729 msgstr "" 10730 10731 + #: src/components/dialogs/BirthDateSettings.tsx:67 10732 msgid "We were unable to load your birthdate preferences. Please try again." 10733 msgstr "" 10734 ··· 10787 msgid "We're so excited to have you join us!" 10788 msgstr "" 10789 10790 + #: src/ageAssurance/components/NoAccessScreen.tsx:378 10791 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:106 10792 msgid "We're sorry, but based on your device's location, you are currently located in a region that requires age assurance." 10793 msgstr "" ··· 10935 msgid "Write a message" 10936 msgstr "" 10937 10938 + #: src/view/screens/Profile.tsx:435 10939 + #: src/view/screens/Profile.tsx:436 10940 msgid "Write a post" 10941 msgstr "" 10942 ··· 10995 msgid "You are a trusted verifier" 10996 msgstr "" 10997 10998 + #: src/ageAssurance/components/NoAccessScreen.tsx:173 10999 msgid "You are accessing Bluesky from a region that legally requires us to verify your age before allowing you to access the app." 11000 msgstr "" 11001 ··· 11003 msgid "You are creating an account on" 11004 msgstr "" 11005 11006 + #: src/ageAssurance/components/NoAccessScreen.tsx:292 11007 #: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:126 11008 msgid "You are currently unable to access Bluesky's Age Assurance flow. Please <0>contact our moderation team</0> if you believe this is an error." 11009 msgstr "" ··· 11136 msgid "You don't have any saved feeds." 11137 msgstr "" 11138 11139 + #: src/components/contacts/screens/ViewMatches.tsx:309 11140 msgid "You got here first" 11141 msgstr "" 11142 ··· 11213 msgid "You haven't created a starter pack yet!" 11214 msgstr "" 11215 11216 + #: src/view/com/lists/ProfileLists.tsx:159 11217 + msgid "You haven't created any lists yet." 11218 + msgstr "" 11219 + 11220 + #: src/view/com/feeds/ProfileFeedgens.tsx:160 11221 msgid "You haven't made any custom feeds yet." 11222 msgstr "" 11223 ··· 11262 msgid "You must be 13 years of age or older to create an account." 11263 msgstr "" 11264 11265 + #: src/components/dialogs/BirthDateSettings.tsx:178 11266 msgid "You must be at least 13 years old to use Bluesky. Read our <0>Terms of Service</0> for more information." 11267 msgstr "" 11268 ··· 11295 msgid "You previously deactivated @{0}." 11296 msgstr "" 11297 11298 + #: src/screens/Settings/Settings.tsx:422 11299 msgid "You probably want to restart the app now." 11300 msgstr "" 11301 ··· 11307 msgid "You reacted {0} to {1}" 11308 msgstr "" 11309 11310 + #: src/components/dialogs/BirthDateSettings.tsx:90 11311 + #: src/components/dialogs/BirthDateSettings.tsx:100 11312 msgid "You recently changed your birthdate" 11313 msgstr "" 11314 11315 + #: src/screens/Settings/Settings.tsx:304 11316 #: src/view/shell/desktop/LeftNav.tsx:210 11317 msgid "You will be signed out of all your accounts." 11318 msgstr "" ··· 11479 msgid "Your contact {firstAuthorName} is on Bluesky" 11480 msgstr "" 11481 11482 + #: src/components/contacts/screens/ViewMatches.tsx:451 11483 msgid "Your contact {name}" 11484 msgstr "" 11485
+6
src/logger/metrics.ts
··· 379 | 'Profile' 380 | 'Onboarding' 381 } 382 'profile:unfollow': { 383 logContext: 384 | 'RecommendedFollowsItem'
··· 379 | 'Profile' 380 | 'Onboarding' 381 } 382 + 'suggestedUser:dismiss': { 383 + logContext: 'InterstitialDiscover' | 'InterstitialProfile' 384 + recId?: number 385 + position: number 386 + suggestedDid: string 387 + } 388 'profile:unfollow': { 389 logContext: 390 | 'RecommendedFollowsItem'
+1 -1
src/routes.ts
··· 7 > 8 9 export const router = new Router<AllNavigatableRoutes>({ 10 - Home: '/', 11 Search: '/search', 12 Feeds: '/feeds', 13 Notifications: '/notifications',
··· 7 > 8 9 export const router = new Router<AllNavigatableRoutes>({ 10 + Home: ['/', '/download'], 11 Search: '/search', 12 Feeds: '/feeds', 13 Notifications: '/notifications',
+181 -5
src/screens/Profile/Header/SuggestedFollows.tsx
··· 1 import {AccordionAnimation} from '#/lib/custom-animations/AccordionAnimation' 2 import {isAndroid} from '#/platform/detection' 3 - import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows' 4 import {ProfileGrid} from '#/components/FeedInterstitials' 5 6 export function ProfileHeaderSuggestedFollows({actorDid}: {actorDid: string}) { 7 const {isLoading, data, error} = useSuggestedFollowsByActorQuery({ 8 did: actorDid, 9 }) 10 11 return ( 12 <ProfileGrid 13 isSuggestionsLoading={isLoading} 14 - profiles={data?.suggestions ?? []} 15 recId={data?.recId} 16 error={error} 17 viewContext="profileHeader" 18 /> 19 ) 20 } ··· 26 isExpanded: boolean 27 actorDid: string 28 }) { 29 const {isLoading, data, error} = useSuggestedFollowsByActorQuery({ 30 did: actorDid, 31 }) 32 33 - if (!data?.suggestions?.length) return null 34 35 /* NOTE (caidanw): 36 * Android does not work well with this feature yet. ··· 43 <AccordionAnimation isExpanded={isExpanded}> 44 <ProfileGrid 45 isSuggestionsLoading={isLoading} 46 - profiles={data.suggestions} 47 - recId={data.recId} 48 error={error} 49 viewContext="profileHeader" 50 isVisible={isExpanded} 51 /> 52 </AccordionAnimation>
··· 1 + import React from 'react' 2 + import {type AppBskyActorDefs} from '@atproto/api' 3 + 4 import {AccordionAnimation} from '#/lib/custom-animations/AccordionAnimation' 5 import {isAndroid} from '#/platform/detection' 6 + import {useModerationOpts} from '#/state/preferences/moderation-opts' 7 + import { 8 + useSuggestedFollowsByActorQuery, 9 + useSuggestedFollowsQuery, 10 + } from '#/state/queries/suggested-follows' 11 + import {useBreakpoints} from '#/alf' 12 import {ProfileGrid} from '#/components/FeedInterstitials' 13 + 14 + const DISMISS_ANIMATION_DURATION = 200 15 16 export function ProfileHeaderSuggestedFollows({actorDid}: {actorDid: string}) { 17 + const {gtMobile} = useBreakpoints() 18 + const moderationOpts = useModerationOpts() 19 + const maxLength = gtMobile ? 4 : 12 20 const {isLoading, data, error} = useSuggestedFollowsByActorQuery({ 21 did: actorDid, 22 }) 23 + const { 24 + data: moreSuggestions, 25 + fetchNextPage, 26 + hasNextPage, 27 + isFetchingNextPage, 28 + } = useSuggestedFollowsQuery({limit: 25}) 29 + 30 + const [dismissedDids, setDismissedDids] = React.useState<Set<string>>( 31 + new Set(), 32 + ) 33 + const [dismissingDids, setDismissingDids] = React.useState<Set<string>>( 34 + new Set(), 35 + ) 36 + 37 + const onDismiss = React.useCallback((did: string) => { 38 + // Start the fade animation 39 + setDismissingDids(prev => new Set(prev).add(did)) 40 + // After animation completes, actually remove from list 41 + setTimeout(() => { 42 + setDismissedDids(prev => new Set(prev).add(did)) 43 + setDismissingDids(prev => { 44 + const next = new Set(prev) 45 + next.delete(did) 46 + return next 47 + }) 48 + }, DISMISS_ANIMATION_DURATION) 49 + }, []) 50 + 51 + // Combine profiles from the actor-specific query with fallback suggestions 52 + const allProfiles = React.useMemo(() => { 53 + const actorProfiles = data?.suggestions ?? [] 54 + const fallbackProfiles = 55 + moreSuggestions?.pages.flatMap(page => page.actors) ?? [] 56 + 57 + // Dedupe by did, preferring actor-specific profiles 58 + const seen = new Set<string>() 59 + const combined: AppBskyActorDefs.ProfileView[] = [] 60 + 61 + for (const profile of actorProfiles) { 62 + if (!seen.has(profile.did)) { 63 + seen.add(profile.did) 64 + combined.push(profile) 65 + } 66 + } 67 + 68 + for (const profile of fallbackProfiles) { 69 + if (!seen.has(profile.did) && profile.did !== actorDid) { 70 + seen.add(profile.did) 71 + combined.push(profile) 72 + } 73 + } 74 + 75 + return combined 76 + }, [data?.suggestions, moreSuggestions?.pages, actorDid]) 77 + 78 + const filteredProfiles = React.useMemo(() => { 79 + return allProfiles.filter(p => !dismissedDids.has(p.did)) 80 + }, [allProfiles, dismissedDids]) 81 + 82 + // Fetch more when running low 83 + React.useEffect(() => { 84 + if ( 85 + moderationOpts && 86 + filteredProfiles.length < maxLength && 87 + hasNextPage && 88 + !isFetchingNextPage 89 + ) { 90 + fetchNextPage() 91 + } 92 + }, [ 93 + filteredProfiles.length, 94 + maxLength, 95 + hasNextPage, 96 + isFetchingNextPage, 97 + fetchNextPage, 98 + moderationOpts, 99 + ]) 100 101 return ( 102 <ProfileGrid 103 isSuggestionsLoading={isLoading} 104 + profiles={filteredProfiles} 105 + totalProfileCount={allProfiles.length} 106 recId={data?.recId} 107 error={error} 108 viewContext="profileHeader" 109 + onDismiss={onDismiss} 110 + dismissingDids={dismissingDids} 111 /> 112 ) 113 } ··· 119 isExpanded: boolean 120 actorDid: string 121 }) { 122 + const {gtMobile} = useBreakpoints() 123 + const moderationOpts = useModerationOpts() 124 + const maxLength = gtMobile ? 4 : 12 125 const {isLoading, data, error} = useSuggestedFollowsByActorQuery({ 126 did: actorDid, 127 }) 128 + const { 129 + data: moreSuggestions, 130 + fetchNextPage, 131 + hasNextPage, 132 + isFetchingNextPage, 133 + } = useSuggestedFollowsQuery({limit: 25}) 134 135 + const [dismissedDids, setDismissedDids] = React.useState<Set<string>>( 136 + new Set(), 137 + ) 138 + const [dismissingDids, setDismissingDids] = React.useState<Set<string>>( 139 + new Set(), 140 + ) 141 + 142 + const onDismiss = React.useCallback((did: string) => { 143 + // Start the fade animation 144 + setDismissingDids(prev => new Set(prev).add(did)) 145 + // After animation completes, actually remove from list 146 + setTimeout(() => { 147 + setDismissedDids(prev => new Set(prev).add(did)) 148 + setDismissingDids(prev => { 149 + const next = new Set(prev) 150 + next.delete(did) 151 + return next 152 + }) 153 + }, DISMISS_ANIMATION_DURATION) 154 + }, []) 155 + 156 + // Combine profiles from the actor-specific query with fallback suggestions 157 + const allProfiles = React.useMemo(() => { 158 + const actorProfiles = data?.suggestions ?? [] 159 + const fallbackProfiles = 160 + moreSuggestions?.pages.flatMap(page => page.actors) ?? [] 161 + 162 + // Dedupe by did, preferring actor-specific profiles 163 + const seen = new Set<string>() 164 + const combined: AppBskyActorDefs.ProfileView[] = [] 165 + 166 + for (const profile of actorProfiles) { 167 + if (!seen.has(profile.did)) { 168 + seen.add(profile.did) 169 + combined.push(profile) 170 + } 171 + } 172 + 173 + for (const profile of fallbackProfiles) { 174 + if (!seen.has(profile.did) && profile.did !== actorDid) { 175 + seen.add(profile.did) 176 + combined.push(profile) 177 + } 178 + } 179 + 180 + return combined 181 + }, [data?.suggestions, moreSuggestions?.pages, actorDid]) 182 + 183 + const filteredProfiles = React.useMemo(() => { 184 + return allProfiles.filter(p => !dismissedDids.has(p.did)) 185 + }, [allProfiles, dismissedDids]) 186 + 187 + // Fetch more when running low 188 + React.useEffect(() => { 189 + if ( 190 + moderationOpts && 191 + filteredProfiles.length < maxLength && 192 + hasNextPage && 193 + !isFetchingNextPage 194 + ) { 195 + fetchNextPage() 196 + } 197 + }, [ 198 + filteredProfiles.length, 199 + maxLength, 200 + hasNextPage, 201 + isFetchingNextPage, 202 + fetchNextPage, 203 + moderationOpts, 204 + ]) 205 + 206 + if (!allProfiles.length && !isLoading) return null 207 208 /* NOTE (caidanw): 209 * Android does not work well with this feature yet. ··· 216 <AccordionAnimation isExpanded={isExpanded}> 217 <ProfileGrid 218 isSuggestionsLoading={isLoading} 219 + profiles={filteredProfiles} 220 + totalProfileCount={allProfiles.length} 221 + recId={data?.recId} 222 error={error} 223 viewContext="profileHeader" 224 + onDismiss={onDismiss} 225 + dismissingDids={dismissingDids} 226 isVisible={isExpanded} 227 /> 228 </AccordionAnimation>
+14 -10
src/screens/Settings/Settings.tsx
··· 16 type CommonNavigatorParams, 17 type NavigationProp, 18 } from '#/lib/routes/types' 19 import {sanitizeDisplayName} from '#/lib/strings/display-names' 20 import {sanitizeHandle} from '#/lib/strings/handles' 21 import {isIOS, isNative} from '#/platform/detection' ··· 95 const [showDevOptions, setShowDevOptions] = useState(false) 96 const findContactsEnabled = 97 useIsFindContactsFeatureEnabledBasedOnGeolocation() 98 99 return ( 100 <Layout.Screen> ··· 213 <Trans>Content and media</Trans> 214 </SettingsList.ItemText> 215 </SettingsList.LinkItem> 216 - {isNative && findContactsEnabled && ( 217 - <SettingsList.LinkItem 218 - to="/settings/find-contacts" 219 - label={_(msg`Find friends from contacts`)}> 220 - <SettingsList.ItemIcon icon={ContactsIcon} /> 221 - <SettingsList.ItemText> 222 - <Trans>Find friends from contacts</Trans> 223 - </SettingsList.ItemText> 224 - </SettingsList.LinkItem> 225 - )} 226 <SettingsList.LinkItem 227 to="/settings/appearance" 228 label={_(msg`Appearance`)}>
··· 16 type CommonNavigatorParams, 17 type NavigationProp, 18 } from '#/lib/routes/types' 19 + import {useGate} from '#/lib/statsig/statsig' 20 import {sanitizeDisplayName} from '#/lib/strings/display-names' 21 import {sanitizeHandle} from '#/lib/strings/handles' 22 import {isIOS, isNative} from '#/platform/detection' ··· 96 const [showDevOptions, setShowDevOptions] = useState(false) 97 const findContactsEnabled = 98 useIsFindContactsFeatureEnabledBasedOnGeolocation() 99 + const gate = useGate() 100 101 return ( 102 <Layout.Screen> ··· 215 <Trans>Content and media</Trans> 216 </SettingsList.ItemText> 217 </SettingsList.LinkItem> 218 + {isNative && 219 + findContactsEnabled && 220 + !gate('disable_settings_find_contacts') && ( 221 + <SettingsList.LinkItem 222 + to="/settings/find-contacts" 223 + label={_(msg`Find friends from contacts`)}> 224 + <SettingsList.ItemIcon icon={ContactsIcon} /> 225 + <SettingsList.ItemText> 226 + <Trans>Find friends from contacts</Trans> 227 + </SettingsList.ItemText> 228 + </SettingsList.LinkItem> 229 + )} 230 <SettingsList.LinkItem 231 to="/settings/appearance" 232 label={_(msg`Appearance`)}>
+29 -9
src/view/com/feeds/ProfileFeedgens.tsx
··· 23 import {isIOS, isNative, isWeb} from '#/platform/detection' 24 import {usePreferencesQuery} from '#/state/queries/preferences' 25 import {RQKEY, useProfileFeedgensQuery} from '#/state/queries/profile-feedgens' 26 import {EmptyState} from '#/view/com/util/EmptyState' 27 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 28 import {List, type ListRef} from '#/view/com/util/List' ··· 81 const isEmpty = !isPending && !data?.pages[0]?.feeds.length 82 const {data: preferences} = usePreferencesQuery() 83 const navigation = useNavigation() 84 85 const items = useMemo(() => { 86 let items: any[] = [] ··· 152 <EmptyState 153 style={{width: '100%'}} 154 icon={HashtagWideIcon} 155 - message={_(msg`You haven't made any custom feeds yet.`)} 156 textStyle={[t.atoms.text_contrast_medium, a.font_medium]} 157 - button={{ 158 - label: _(msg`Browse custom feeds`), 159 - text: _(msg`Browse custom feeds`), 160 - onPress: () => navigation.navigate('Feeds' as never), 161 - size: 'small', 162 - color: 'secondary', 163 - }} 164 /> 165 ) 166 } else if (item === ERROR_ITEM) { ··· 194 } 195 return null 196 }, 197 - [_, t, error, refetch, onPressRetryLoadMore, preferences, navigation], 198 ) 199 200 useEffect(() => {
··· 23 import {isIOS, isNative, isWeb} from '#/platform/detection' 24 import {usePreferencesQuery} from '#/state/queries/preferences' 25 import {RQKEY, useProfileFeedgensQuery} from '#/state/queries/profile-feedgens' 26 + import {useSession} from '#/state/session' 27 import {EmptyState} from '#/view/com/util/EmptyState' 28 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 29 import {List, type ListRef} from '#/view/com/util/List' ··· 82 const isEmpty = !isPending && !data?.pages[0]?.feeds.length 83 const {data: preferences} = usePreferencesQuery() 84 const navigation = useNavigation() 85 + const {currentAccount} = useSession() 86 + const isSelf = currentAccount?.did === did 87 88 const items = useMemo(() => { 89 let items: any[] = [] ··· 155 <EmptyState 156 style={{width: '100%'}} 157 icon={HashtagWideIcon} 158 + message={ 159 + isSelf 160 + ? _(msg`You haven't made any custom feeds yet.`) 161 + : _(msg`No custom feeds yet`) 162 + } 163 textStyle={[t.atoms.text_contrast_medium, a.font_medium]} 164 + button={ 165 + isSelf 166 + ? { 167 + label: _(msg`Browse custom feeds`), 168 + text: _(msg`Browse custom feeds`), 169 + onPress: () => navigation.navigate('Feeds' as never), 170 + size: 'small', 171 + color: 'secondary', 172 + } 173 + : undefined 174 + } 175 /> 176 ) 177 } else if (item === ERROR_ITEM) { ··· 205 } 206 return null 207 }, 208 + [ 209 + _, 210 + t, 211 + error, 212 + refetch, 213 + onPressRetryLoadMore, 214 + preferences, 215 + navigation, 216 + isSelf, 217 + ], 218 ) 219 220 useEffect(() => {
+29 -11
src/view/com/lists/ProfileLists.tsx
··· 23 import {isIOS, isNative, isWeb} from '#/platform/detection' 24 import {usePreferencesQuery} from '#/state/queries/preferences' 25 import {RQKEY, useProfileListsQuery} from '#/state/queries/profile-lists' 26 import {EmptyState} from '#/view/com/util/EmptyState' 27 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 28 import {List, type ListRef} from '#/view/com/util/List' ··· 81 const isEmpty = !isPending && !data?.pages[0]?.lists.length 82 const {data: preferences} = usePreferencesQuery() 83 const navigation = useNavigation() 84 85 const items = useMemo(() => { 86 let listItems: any[] = [] ··· 151 return ( 152 <EmptyState 153 icon={ListIcon} 154 - message={_( 155 - msg`Lists allow you to see content from your favorite people.`, 156 - )} 157 textStyle={[t.atoms.text_contrast_medium, a.font_medium]} 158 - button={{ 159 - label: _(msg`Create a list`), 160 - text: _(msg`Create a list`), 161 - onPress: () => navigation.navigate('Lists' as never), 162 - size: 'small', 163 - color: 'primary', 164 - }} 165 /> 166 ) 167 } else if (item === ERROR_ITEM) { ··· 195 } 196 return null 197 }, 198 - [_, t, error, refetch, onPressRetryLoadMore, preferences, navigation], 199 ) 200 201 useEffect(() => {
··· 23 import {isIOS, isNative, isWeb} from '#/platform/detection' 24 import {usePreferencesQuery} from '#/state/queries/preferences' 25 import {RQKEY, useProfileListsQuery} from '#/state/queries/profile-lists' 26 + import {useSession} from '#/state/session' 27 import {EmptyState} from '#/view/com/util/EmptyState' 28 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 29 import {List, type ListRef} from '#/view/com/util/List' ··· 82 const isEmpty = !isPending && !data?.pages[0]?.lists.length 83 const {data: preferences} = usePreferencesQuery() 84 const navigation = useNavigation() 85 + const {currentAccount} = useSession() 86 + const isSelf = currentAccount?.did === did 87 88 const items = useMemo(() => { 89 let listItems: any[] = [] ··· 154 return ( 155 <EmptyState 156 icon={ListIcon} 157 + message={ 158 + isSelf 159 + ? _(msg`You haven't created any lists yet.`) 160 + : _(msg`No lists`) 161 + } 162 textStyle={[t.atoms.text_contrast_medium, a.font_medium]} 163 + button={ 164 + isSelf 165 + ? { 166 + label: _(msg`Create a list`), 167 + text: _(msg`Create a list`), 168 + onPress: () => navigation.navigate('Lists' as never), 169 + size: 'small', 170 + color: 'primary', 171 + } 172 + : undefined 173 + } 174 /> 175 ) 176 } else if (item === ERROR_ITEM) { ··· 204 } 205 return null 206 }, 207 + [ 208 + _, 209 + t, 210 + error, 211 + refetch, 212 + onPressRetryLoadMore, 213 + preferences, 214 + navigation, 215 + isSelf, 216 + ], 217 ) 218 219 useEffect(() => {
+51 -31
src/view/screens/Profile.tsx
··· 429 ignoreFilterFor={profile.did} 430 setScrollViewTag={setScrollViewTag} 431 emptyStateMessage={_(msg`No posts yet`)} 432 - emptyStateButton={{ 433 - label: _(msg`Write a post`), 434 - text: _(msg`Write a post`), 435 - onPress: () => openComposer({}), 436 - size: 'small', 437 - color: 'primary', 438 - }} 439 /> 440 ) 441 : null} ··· 465 ignoreFilterFor={profile.did} 466 setScrollViewTag={setScrollViewTag} 467 emptyStateMessage={_(msg`No media yet`)} 468 - emptyStateButton={{ 469 - label: _(msg`Post a photo`), 470 - text: _(msg`Post a photo`), 471 - onPress: () => openComposer({}), 472 - size: 'small', 473 - color: 'primary', 474 - }} 475 emptyStateIcon={ImageIcon} 476 /> 477 ) ··· 487 ignoreFilterFor={profile.did} 488 setScrollViewTag={setScrollViewTag} 489 emptyStateMessage={_(msg`No video posts yet`)} 490 - emptyStateButton={{ 491 - label: _(msg`Post a video`), 492 - text: _(msg`Post a video`), 493 - onPress: () => openComposer({}), 494 - size: 'small', 495 - color: 'primary', 496 - }} 497 emptyStateIcon={VideoIcon} 498 /> 499 ) ··· 535 headerOffset={headerHeight} 536 enabled={isFocused} 537 setScrollViewTag={setScrollViewTag} 538 - emptyStateMessage={_( 539 - msg`Starter packs let you share your favorite feeds and people with your friends.`, 540 - )} 541 - emptyStateButton={{ 542 - label: _(msg`Create a Starter Pack`), 543 - text: _(msg`Create a Starter Pack`), 544 - onPress: wrappedNavToWizard, 545 - color: 'primary', 546 - size: 'small', 547 - }} 548 emptyStateIcon={CircleAndSquareIcon} 549 /> 550 )
··· 429 ignoreFilterFor={profile.did} 430 setScrollViewTag={setScrollViewTag} 431 emptyStateMessage={_(msg`No posts yet`)} 432 + emptyStateButton={ 433 + isMe 434 + ? { 435 + label: _(msg`Write a post`), 436 + text: _(msg`Write a post`), 437 + onPress: () => openComposer({}), 438 + size: 'small', 439 + color: 'primary', 440 + } 441 + : undefined 442 + } 443 /> 444 ) 445 : null} ··· 469 ignoreFilterFor={profile.did} 470 setScrollViewTag={setScrollViewTag} 471 emptyStateMessage={_(msg`No media yet`)} 472 + emptyStateButton={ 473 + isMe 474 + ? { 475 + label: _(msg`Post a photo`), 476 + text: _(msg`Post a photo`), 477 + onPress: () => openComposer({}), 478 + size: 'small', 479 + color: 'primary', 480 + } 481 + : undefined 482 + } 483 emptyStateIcon={ImageIcon} 484 /> 485 ) ··· 495 ignoreFilterFor={profile.did} 496 setScrollViewTag={setScrollViewTag} 497 emptyStateMessage={_(msg`No video posts yet`)} 498 + emptyStateButton={ 499 + isMe 500 + ? { 501 + label: _(msg`Post a video`), 502 + text: _(msg`Post a video`), 503 + onPress: () => openComposer({}), 504 + size: 'small', 505 + color: 'primary', 506 + } 507 + : undefined 508 + } 509 emptyStateIcon={VideoIcon} 510 /> 511 ) ··· 547 headerOffset={headerHeight} 548 enabled={isFocused} 549 setScrollViewTag={setScrollViewTag} 550 + emptyStateMessage={ 551 + isMe 552 + ? _( 553 + msg`Starter Packs let you share your favorite feeds and people with your friends.`, 554 + ) 555 + : _(msg`No Starter Packs yet`) 556 + } 557 + emptyStateButton={ 558 + isMe 559 + ? { 560 + label: _(msg`Create a Starter Pack`), 561 + text: _(msg`Create a Starter Pack`), 562 + onPress: wrappedNavToWizard, 563 + color: 'primary', 564 + size: 'small', 565 + } 566 + : undefined 567 + } 568 emptyStateIcon={CircleAndSquareIcon} 569 /> 570 )
+44
src/view/screens/Storybook/Forms.tsx
··· 1 import React from 'react' 2 import {type TextInput, View} from 'react-native' 3 4 import {atoms as a} from '#/alf' 5 import {Button, ButtonText} from '#/components/Button' 6 import {DateField, LabelText} from '#/components/forms/DateField' ··· 9 import * as Toggle from '#/components/forms/Toggle' 10 import * as ToggleButton from '#/components/forms/ToggleButton' 11 import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe' 12 import {H1, H3} from '#/components/Typography' 13 14 export function Forms() { ··· 22 23 const [value, setValue] = React.useState('') 24 const [date, setDate] = React.useState('2001-01-01') 25 26 const inputRef = React.useRef<TextInput>(null) 27 28 return ( 29 <View style={[a.gap_4xl, a.align_start]}> 30 <H1>Forms</H1> 31 32 <View style={[a.gap_md, a.align_start, a.w_full]}> 33 <H3>InputText</H3>
··· 1 import React from 'react' 2 import {type TextInput, View} from 'react-native' 3 4 + import {APP_LANGUAGES} from '#/lib/../locale/languages' 5 import {atoms as a} from '#/alf' 6 import {Button, ButtonText} from '#/components/Button' 7 import {DateField, LabelText} from '#/components/forms/DateField' ··· 10 import * as Toggle from '#/components/forms/Toggle' 11 import * as ToggleButton from '#/components/forms/ToggleButton' 12 import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe' 13 + import {InternationalPhoneCodeSelect} from '#/components/InternationalPhoneCodeSelect' 14 + import * as Select from '#/components/Select' 15 import {H1, H3} from '#/components/Typography' 16 17 export function Forms() { ··· 25 26 const [value, setValue] = React.useState('') 27 const [date, setDate] = React.useState('2001-01-01') 28 + const [countryCode, setCountryCode] = React.useState('US') 29 + const [phoneNumber, setPhoneNumber] = React.useState('') 30 + const [lang, setLang] = React.useState('en') 31 32 const inputRef = React.useRef<TextInput>(null) 33 34 return ( 35 <View style={[a.gap_4xl, a.align_start]}> 36 <H1>Forms</H1> 37 + 38 + <Select.Root value={lang} onValueChange={setLang}> 39 + <Select.Trigger label="Select app language"> 40 + <Select.ValueText /> 41 + <Select.Icon /> 42 + </Select.Trigger> 43 + <Select.Content 44 + label="App language" 45 + renderItem={({label, value}) => ( 46 + <Select.Item value={value} label={label}> 47 + <Select.ItemIndicator /> 48 + <Select.ItemText>{label}</Select.ItemText> 49 + </Select.Item> 50 + )} 51 + items={APP_LANGUAGES.map(l => ({ 52 + label: l.name, 53 + value: l.code2, 54 + }))} 55 + /> 56 + </Select.Root> 57 + 58 + <View style={[a.flex_row, a.gap_sm, a.align_center]}> 59 + <View> 60 + <InternationalPhoneCodeSelect 61 + // @ts-ignore 62 + value={countryCode} 63 + onChange={value => setCountryCode(value)} 64 + /> 65 + </View> 66 + 67 + <View style={[a.flex_1]}> 68 + <TextField.Input 69 + label="Phone number" 70 + value={phoneNumber} 71 + onChangeText={setPhoneNumber} 72 + /> 73 + </View> 74 + </View> 75 76 <View style={[a.gap_md, a.align_start, a.w_full]}> 77 <H3>InputText</H3>
+1 -1
src/view/shell/bottom-bar/BottomBar.tsx
··· 425 enableSquareButtons ? a.rounded_sm : a.rounded_full, 426 {backgroundColor: t.palette.primary_500}, 427 ]}> 428 - <Text style={styles.notificationCountLabel}>1</Text> 429 </View> 430 ) : hasNew ? ( 431 <View
··· 425 enableSquareButtons ? a.rounded_sm : a.rounded_full, 426 {backgroundColor: t.palette.primary_500}, 427 ]}> 428 + <Text style={styles.notificationCountLabel}>{notificationCount}</Text> 429 </View> 430 ) : hasNew ? ( 431 <View
+2
src/view/shell/index.tsx
··· 32 import {InAppBrowserConsentDialog} from '#/components/dialogs/InAppBrowserConsent' 33 import {LinkWarningDialog} from '#/components/dialogs/LinkWarning' 34 import {MutedWordsDialog} from '#/components/dialogs/MutedWords' 35 import {SigninDialog} from '#/components/dialogs/Signin' 36 import { 37 Outlet as PolicyUpdateOverlayPortalOutlet, ··· 110 <InAppBrowserConsentDialog /> 111 <LinkWarningDialog /> 112 <Lightbox /> 113 114 {/* Until policy update has been completed by the user, don't render anything that is portaled */} 115 {policyUpdateState.completed && (
··· 32 import {InAppBrowserConsentDialog} from '#/components/dialogs/InAppBrowserConsent' 33 import {LinkWarningDialog} from '#/components/dialogs/LinkWarning' 34 import {MutedWordsDialog} from '#/components/dialogs/MutedWords' 35 + import {NuxDialogs} from '#/components/dialogs/nuxs' 36 import {SigninDialog} from '#/components/dialogs/Signin' 37 import { 38 Outlet as PolicyUpdateOverlayPortalOutlet, ··· 111 <InAppBrowserConsentDialog /> 112 <LinkWarningDialog /> 113 <Lightbox /> 114 + <NuxDialogs /> 115 116 {/* Until policy update has been completed by the user, don't render anything that is portaled */} 117 {policyUpdateState.completed && (
+2
src/view/shell/index.web.tsx
··· 22 import {EmailDialog} from '#/components/dialogs/EmailDialog' 23 import {LinkWarningDialog} from '#/components/dialogs/LinkWarning' 24 import {MutedWordsDialog} from '#/components/dialogs/MutedWords' 25 import {SigninDialog} from '#/components/dialogs/Signin' 26 import {useWelcomeModal} from '#/components/hooks/useWelcomeModal' 27 import { ··· 119 <AgeAssuranceRedirectDialog /> 120 <LinkWarningDialog /> 121 <Lightbox /> 122 123 {welcomeModalControl.isOpen && ( 124 <WelcomeModal control={welcomeModalControl} />
··· 22 import {EmailDialog} from '#/components/dialogs/EmailDialog' 23 import {LinkWarningDialog} from '#/components/dialogs/LinkWarning' 24 import {MutedWordsDialog} from '#/components/dialogs/MutedWords' 25 + import {NuxDialogs} from '#/components/dialogs/nuxs' 26 import {SigninDialog} from '#/components/dialogs/Signin' 27 import {useWelcomeModal} from '#/components/hooks/useWelcomeModal' 28 import { ··· 120 <AgeAssuranceRedirectDialog /> 121 <LinkWarningDialog /> 122 <Lightbox /> 123 + <NuxDialogs /> 124 125 {welcomeModalControl.isOpen && ( 126 <WelcomeModal control={welcomeModalControl} />