diff --git a/src/components/PostControls/RepostButton.tsx b/src/components/PostControls/RepostButton.tsx
index 522e80dd3f..d4a3960a7f 100644
--- a/src/components/PostControls/RepostButton.tsx
+++ b/src/components/PostControls/RepostButton.tsx
@@ -10,7 +10,7 @@ import {Button, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {CloseQuote_Stroke2_Corner1_Rounded as Quote} from '#/components/icons/Quote'
import {Repost_Stroke2_Corner3_Rounded as Repost} from '#/components/icons/Repost'
-import {formatPostStatCount} from '#/components/PostControls/util'
+import {useFormatPostStatCount} from '#/components/PostControls/util'
import {Text} from '#/components/Typography'
import {
PostControlButton,
@@ -25,7 +25,6 @@ interface Props {
onQuote: () => void
big?: boolean
embeddingDisabled: boolean
- compactCount?: boolean
}
let RepostButton = ({
@@ -35,12 +34,12 @@ let RepostButton = ({
onQuote,
big,
embeddingDisabled,
- compactCount,
}: Props): React.ReactNode => {
const t = useTheme()
- const {_, i18n} = useLingui()
+ const {_} = useLingui()
const requireAuth = useRequireAuth()
const dialogControl = Dialog.useDialogControl()
+ const formatPostStatCount = useFormatPostStatCount()
const onPress = () => requireAuth(() => dialogControl.open())
@@ -88,7 +87,7 @@ let RepostButton = ({
{typeof repostCount !== 'undefined' && repostCount > 0 && (
- {formatPostStatCount(i18n, repostCount, {compact: compactCount})}
+ {formatPostStatCount(repostCount)}
)}
diff --git a/src/components/PostControls/index.tsx b/src/components/PostControls/index.tsx
index 834ad8e7dc..f91bcd8a5d 100644
--- a/src/components/PostControls/index.tsx
+++ b/src/components/PostControls/index.tsx
@@ -27,7 +27,7 @@ import {
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, flatten, useBreakpoints} from '#/alf'
import {Reply as Bubble} from '#/components/icons/Reply'
-import {formatPostStatCount} from '#/components/PostControls/util'
+import {useFormatPostStatCount} from '#/components/PostControls/util'
import {BookmarkButton} from './BookmarkButton'
import {
PostControlButton,
@@ -69,7 +69,7 @@ let PostControls = ({
viaRepost?: {uri: string; cid: string}
variant?: 'compact' | 'normal' | 'large'
}): React.ReactNode => {
- const {_, i18n} = useLingui()
+ const {_} = useLingui()
const {openComposer} = useOpenComposer()
const {feedDescriptor} = useFeedFeedbackContext()
const [queueLike, queueUnlike] = usePostLikeMutationQueue(
@@ -95,6 +95,7 @@ let PostControls = ({
)
const replyDisabled = post.viewer?.replyDisabled
const {gtPhone} = useBreakpoints()
+ const formatPostStatCount = useFormatPostStatCount()
const [hasLikeIconBeenToggled, setHasLikeIconBeenToggled] = useState(false)
@@ -232,9 +233,7 @@ let PostControls = ({
{typeof post.replyCount !== 'undefined' && post.replyCount > 0 && (
- {formatPostStatCount(i18n, post.replyCount, {
- compact: variant === 'compact',
- })}
+ {formatPostStatCount(post.replyCount)}
)}
@@ -247,7 +246,6 @@ let PostControls = ({
onQuote={onQuote}
big={big}
embeddingDisabled={Boolean(post.viewer?.embeddingDisabled)}
- compactCount={variant === 'compact'}
/>
@@ -288,7 +286,6 @@ let PostControls = ({
big={big}
isLiked={Boolean(post.viewer?.like)}
hasBeenToggled={hasLikeIconBeenToggled}
- compactCount={variant === 'compact'}
/>
diff --git a/src/components/PostControls/util.ts b/src/components/PostControls/util.ts
index 5d3ea74e49..b8050a85ad 100644
--- a/src/components/PostControls/util.ts
+++ b/src/components/PostControls/util.ts
@@ -1,24 +1,48 @@
-import {type I18n} from '@lingui/core'
+import {useCallback} from 'react'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
/**
* This matches `formatCount` from `view/com/util/numeric/format.ts`, but has
* additional truncation logic for large numbers. `roundingMode` should always
* match the original impl, regardless of if we add more formatting here.
*/
-export function formatPostStatCount(
- i18n: I18n,
- count: number,
- {
- compact = false,
- }: {
- compact?: boolean
- } = {},
-): string {
- const isOver10k = count >= 10_000
- return i18n.number(count, {
- notation: 'compact',
- maximumFractionDigits: isOver10k || compact ? 0 : 1,
- // @ts-expect-error - roundingMode not in the types
- roundingMode: 'trunc',
- })
+export function useFormatPostStatCount() {
+ const {i18n} = useLingui()
+
+ return useCallback(
+ (postStatCount: number) => {
+ const isOver1k = postStatCount >= 1_000
+ const isOver10k = postStatCount >= 10_000
+ const isOver1M = postStatCount >= 1_000_000
+ const formatted = i18n.number(postStatCount, {
+ notation: 'compact',
+ maximumFractionDigits: isOver10k ? 0 : 1,
+ // @ts-expect-error - roundingMode not in the types
+ roundingMode: 'trunc',
+ })
+ const count = formatted.replace(/\D+$/g, '')
+
+ if (isOver1M) {
+ return i18n._(
+ msg({
+ message: `${count}M`,
+ comment:
+ 'For post statistics. Indicates a number in the millions. Please use the shortest format appropriate for your language.',
+ }),
+ )
+ } else if (isOver1k) {
+ return i18n._(
+ msg({
+ message: `${count}K`,
+ comment:
+ 'For post statistics. Indicates a number in the thousands. Please use the shortest format appropriate for your language.',
+ }),
+ )
+ } else {
+ return count
+ }
+ },
+ [i18n],
+ )
}
diff --git a/src/components/StarterPack/ProfileStarterPacks.tsx b/src/components/StarterPack/ProfileStarterPacks.tsx
index 73aee28f4e..bbe0bc52b2 100644
--- a/src/components/StarterPack/ProfileStarterPacks.tsx
+++ b/src/components/StarterPack/ProfileStarterPacks.tsx
@@ -214,7 +214,7 @@ function Empty() {
onError: e => {
logger.error('Failed to generate starter pack', {safeMessage: e})
setIsGenerating(false)
- if (e.name === 'NOT_ENOUGH_FOLLOWERS') {
+ if (e.message.includes('NOT_ENOUGH_FOLLOWERS')) {
followersDialogControl.open()
} else {
errorDialogControl.open()
diff --git a/src/components/ageAssurance/AgeRestrictedScreen.tsx b/src/components/ageAssurance/AgeRestrictedScreen.tsx
index b47cc5b0c9..1430aaaff9 100644
--- a/src/components/ageAssurance/AgeRestrictedScreen.tsx
+++ b/src/components/ageAssurance/AgeRestrictedScreen.tsx
@@ -18,10 +18,12 @@ export function AgeRestrictedScreen({
children,
screenTitle,
infoText,
+ rightHeaderSlot,
}: {
children: React.ReactNode
screenTitle?: string
infoText?: string
+ rightHeaderSlot?: React.ReactNode
}) {
const {_} = useLingui()
const copy = useAgeAssuranceCopy()
@@ -46,12 +48,12 @@ export function AgeRestrictedScreen({
-
+
{screenTitle ?? Unavailable}
-
+ {rightHeaderSlot ?? }
diff --git a/src/components/dialogs/nuxs/BookmarksAnnouncement.tsx b/src/components/dialogs/nuxs/BookmarksAnnouncement.tsx
index c635583345..266e226a66 100644
--- a/src/components/dialogs/nuxs/BookmarksAnnouncement.tsx
+++ b/src/components/dialogs/nuxs/BookmarksAnnouncement.tsx
@@ -117,7 +117,11 @@ export function BookmarksAnnouncement() {
},
]}
alt={_(
- msg`A screenshot of a post with a new button next to the share button that allows you to save the post to your bookmarks. The post is from @jcsalterego.bsky.social and reads "inventing a saturday that immediately follows monday".`,
+ msg({
+ message: `A screenshot of a post with a new button next to the share button that allows you to save the post to your bookmarks. The post is from @jcsalterego.bsky.social and reads "inventing a saturday that immediately follows monday".`,
+ comment:
+ 'Contains a post that originally appeared in English. Consider translating the post text if it makes sense in your language, and noting that the post was translated from English.',
+ }),
)}
/>
diff --git a/src/lib/custom-animations/CountWheel.tsx b/src/lib/custom-animations/CountWheel.tsx
index 6db22554e1..b8763827a7 100644
--- a/src/lib/custom-animations/CountWheel.tsx
+++ b/src/lib/custom-animations/CountWheel.tsx
@@ -6,13 +6,12 @@ import Animated, {
useReducedMotion,
withTiming,
} from 'react-native-reanimated'
-import {i18n} from '@lingui/core'
import {decideShouldRoll} from '#/lib/custom-animations/util'
import {s} from '#/lib/styles'
import {Text} from '#/view/com/util/text/Text'
import {atoms as a, useTheme} from '#/alf'
-import {formatPostStatCount} from '#/components/PostControls/util'
+import {useFormatPostStatCount} from '#/components/PostControls/util'
const animationConfig = {
duration: 400,
@@ -92,13 +91,11 @@ export function CountWheel({
big,
isLiked,
hasBeenToggled,
- compactCount,
}: {
likeCount: number
big?: boolean
isLiked: boolean
hasBeenToggled: boolean
- compactCount?: boolean
}) {
const t = useTheme()
const shouldAnimate = !useReducedMotion() && hasBeenToggled
@@ -111,12 +108,9 @@ export function CountWheel({
const [key, setKey] = React.useState(0)
const [prevCount, setPrevCount] = React.useState(likeCount)
const prevIsLiked = React.useRef(isLiked)
- const formattedCount = formatPostStatCount(i18n, likeCount, {
- compact: compactCount,
- })
- const formattedPrevCount = formatPostStatCount(i18n, prevCount, {
- compact: compactCount,
- })
+ const formatPostStatCount = useFormatPostStatCount()
+ const formattedCount = formatPostStatCount(likeCount)
+ const formattedPrevCount = formatPostStatCount(prevCount)
React.useEffect(() => {
if (isLiked === prevIsLiked.current) {
diff --git a/src/lib/custom-animations/CountWheel.web.tsx b/src/lib/custom-animations/CountWheel.web.tsx
index fc2505eadf..be48e19d79 100644
--- a/src/lib/custom-animations/CountWheel.web.tsx
+++ b/src/lib/custom-animations/CountWheel.web.tsx
@@ -1,13 +1,12 @@
import React from 'react'
import {View} from 'react-native'
import {useReducedMotion} from 'react-native-reanimated'
-import {i18n} from '@lingui/core'
import {decideShouldRoll} from '#/lib/custom-animations/util'
import {s} from '#/lib/styles'
-import {formatCount} from '#/view/com/util/numeric/format'
import {Text} from '#/view/com/util/text/Text'
import {atoms as a, useTheme} from '#/alf'
+import {useFormatPostStatCount} from '#/components/PostControls/util'
const animationConfig = {
duration: 400,
@@ -55,8 +54,9 @@ export function CountWheel({
const [prevCount, setPrevCount] = React.useState(likeCount)
const prevIsLiked = React.useRef(isLiked)
- const formattedCount = formatCount(i18n, likeCount)
- const formattedPrevCount = formatCount(i18n, prevCount)
+ const formatPostStatCount = useFormatPostStatCount()
+ const formattedCount = formatPostStatCount(likeCount)
+ const formattedPrevCount = formatPostStatCount(prevCount)
React.useEffect(() => {
if (isLiked === prevIsLiked.current) {
diff --git a/src/lib/notifications/notifications.ts b/src/lib/notifications/notifications.ts
index 67a38a52ce..03dc4726f6 100644
--- a/src/lib/notifications/notifications.ts
+++ b/src/lib/notifications/notifications.ts
@@ -11,6 +11,7 @@ import {isNative} from '#/platform/detection'
import {useAgeAssuranceContext} from '#/state/ageAssurance'
import {type SessionAccount, useAgent, useSession} from '#/state/session'
import BackgroundNotificationHandler from '#/../modules/expo-background-notification-handler'
+import {IS_DEV} from '#/env'
/**
* @private
@@ -129,7 +130,7 @@ export function useGetAndRegisterPushToken() {
}: {
isAgeRestricted?: boolean
} = {}) => {
- if (!isNative) return
+ if (!isNative || IS_DEV) return
/**
* This will also fire the listener added via `addPushTokenListener`. That
diff --git a/src/screens/Messages/ChatList.tsx b/src/screens/Messages/ChatList.tsx
index 3454464648..cb8598e79c 100644
--- a/src/screens/Messages/ChatList.tsx
+++ b/src/screens/Messages/ChatList.tsx
@@ -74,7 +74,18 @@ export function MessagesScreen(props: Props) {
return (
+ infoText={aaCopy.chatsInfoText}
+ rightHeaderSlot={
+
+
+ Chat settings
+
+
+ }>
)
diff --git a/src/screens/Messages/Settings.tsx b/src/screens/Messages/Settings.tsx
index 6015c07cd5..b4b84aafea 100644
--- a/src/screens/Messages/Settings.tsx
+++ b/src/screens/Messages/Settings.tsx
@@ -12,8 +12,6 @@ import {useSession} from '#/state/session'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a} from '#/alf'
import {Admonition} from '#/components/Admonition'
-import {AgeRestrictedScreen} from '#/components/ageAssurance/AgeRestrictedScreen'
-import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy'
import {Divider} from '#/components/Divider'
import * as Toggle from '#/components/forms/Toggle'
import * as Layout from '#/components/Layout'
@@ -25,16 +23,7 @@ type AllowIncoming = 'all' | 'none' | 'following'
type Props = NativeStackScreenProps
export function MessagesSettingsScreen(props: Props) {
- const {_} = useLingui()
- const aaCopy = useAgeAssuranceCopy()
-
- return (
-
-
-
- )
+ return
}
export function MessagesSettingsScreenInner({}: Props) {
diff --git a/src/screens/PostThread/components/ThreadItemAnchor.tsx b/src/screens/PostThread/components/ThreadItemAnchor.tsx
index 08dd272f76..66ef962006 100644
--- a/src/screens/PostThread/components/ThreadItemAnchor.tsx
+++ b/src/screens/PostThread/components/ThreadItemAnchor.tsx
@@ -52,7 +52,7 @@ import {PostAlerts} from '#/components/moderation/PostAlerts'
import {type AppModerationCause} from '#/components/Pills'
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
import {PostControls} from '#/components/PostControls'
-import {formatPostStatCount} from '#/components/PostControls/util'
+import {useFormatPostStatCount} from '#/components/PostControls/util'
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
import * as Prompt from '#/components/Prompt'
import {RichText} from '#/components/RichText'
@@ -176,11 +176,12 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
postSource?: PostSource
}) {
const t = useTheme()
- const {_, i18n} = useLingui()
+ const {_} = useLingui()
const {openComposer} = useOpenComposer()
const {currentAccount, hasSession} = useSession()
const {gtTablet} = useBreakpoints()
const feedFeedback = useFeedFeedback(postSource?.feedSourceInfo, hasSession)
+ const formatPostStatCount = useFormatPostStatCount()
const post = postShadow
const record = item.value.post.record
@@ -439,7 +440,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
testID="repostCount-expanded"
style={[a.text_md, t.atoms.text_contrast_medium]}>
- {formatPostStatCount(i18n, post.repostCount)}
+ {formatPostStatCount(post.repostCount)}
{' '}
- {formatPostStatCount(i18n, post.quoteCount)}
+ {formatPostStatCount(post.quoteCount)}
{' '}
- {formatPostStatCount(i18n, post.likeCount)}
+ {formatPostStatCount(post.likeCount)}
{' '}
@@ -485,7 +486,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
testID="bookmarkCount-expanded"
style={[a.text_md, t.atoms.text_contrast_medium]}>
- {formatPostStatCount(i18n, post.bookmarkCount)}
+ {formatPostStatCount(post.bookmarkCount)}
{' '}