From 0fe3b5c66350583d1035059b6e0eb1b9ad9018af Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Apr 2026 21:59:52 +0000 Subject: [PATCH 1/3] Randomize locked text post placeholder and add gradient to mobile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace hardcoded placeholder text with a deterministic pseudo-random generator (5–25 words per post) so each locked post looks visually distinct. Update mobile locked text post UI to show blurred placeholder text with a gradient overlay and unlock button, matching the web implementation, instead of a simple lock icon. https://claude.ai/code/session_019N9dxngkS7FAaf3nHYrkRy --- .../components/TextPostCard.tsx | 77 +++++++++++++++---- .../components/TextPostCard.tsx | 24 +++++- 2 files changed, 83 insertions(+), 18 deletions(-) diff --git a/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx b/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx index 76c9ee6acd0..274b839d0e0 100644 --- a/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx +++ b/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx @@ -1,8 +1,11 @@ import { useComment } from '@audius/common/api' import type { ID } from '@audius/common/models' import { getLargestTimeUnitText } from '@audius/common/utils' +import { View } from 'react-native' +import LinearGradient from 'react-native-linear-gradient' import { + Button, Flex, IconLock, Paper, @@ -14,7 +17,29 @@ import { ProfilePicture } from 'app/components/core' import { UserLink } from 'app/components/user-link' const messages = { - locked: 'Hold this coin to unlock' + unlock: 'Unlock', + membersOnly: 'Members Only' +} + +/** + * Generate a deterministic pseudo-random placeholder string for locked posts + * so each post looks visually distinct behind the blur. + */ +const generatePlaceholder = (commentId: ID) => { + const seed = + typeof commentId === 'string' ? commentId.length : Number(commentId) + const wordCount = 5 + (seed % 21) // 5–25 words + const words = [] + const pool = 'abcdefghijklmnopqrstuvwxyz' + for (let i = 0; i < wordCount; i++) { + const len = 3 + ((seed * (i + 1) * 7) % 8) // 3–10 chars per word + let word = '' + for (let j = 0; j < len; j++) { + word += pool[(seed * (i + 1) * (j + 1) * 13) % pool.length] + } + words.push(word) + } + return words.join(' ') } type TextPostCardProps = { @@ -76,20 +101,42 @@ export const TextPostCard = ({ commentId }: TextPostCardProps) => { {isLocked ? ( - - - - {messages.locked} - + + + + {generatePlaceholder(commentId)} + + + + + + + + + {messages.membersOnly} + + + ) : ( diff --git a/packages/web/src/pages/fan-club-detail-page/components/TextPostCard.tsx b/packages/web/src/pages/fan-club-detail-page/components/TextPostCard.tsx index df545db7db5..7ac18820085 100644 --- a/packages/web/src/pages/fan-club-detail-page/components/TextPostCard.tsx +++ b/packages/web/src/pages/fan-club-detail-page/components/TextPostCard.tsx @@ -39,8 +39,26 @@ const messages = { edited: '(edited)' } -const LOCKED_PLACEHOLDER_TEXT = - 'This content is exclusively available for coin holders. Purchase coins to unlock access to this post and other exclusive content.' +/** + * Generate a deterministic pseudo-random placeholder string for locked posts + * so each post looks visually distinct behind the blur. + */ +const generatePlaceholder = (commentId: ID) => { + // Simple hash from commentId to get a stable length between 5 and 25 words + const seed = typeof commentId === 'string' ? commentId.length : Number(commentId) + const wordCount = 5 + (seed % 21) // 5–25 words + const words = [] + const pool = 'abcdefghijklmnopqrstuvwxyz' + for (let i = 0; i < wordCount; i++) { + const len = 3 + ((seed * (i + 1) * 7) % 8) // 3–10 chars per word + let word = '' + for (let j = 0; j < len; j++) { + word += pool[(seed * (i + 1) * (j + 1) * 13) % pool.length] + } + words.push(word) + } + return words.join(' ') +} type TextPostCardProps = { commentId: ID @@ -165,7 +183,7 @@ export const TextPostCard = ({ commentId, mint }: TextPostCardProps) => { pointerEvents: 'none' }} > - {LOCKED_PLACEHOLDER_TEXT} + {generatePlaceholder(commentId)} Date: Thu, 2 Apr 2026 23:19:17 +0000 Subject: [PATCH 2/3] Fix typecheck: remove string branch for ID type ID is always a number, so the typeof === 'string' check produced a 'never' type error on .length. Simplified to Number(commentId) directly. https://claude.ai/code/session_019N9dxngkS7FAaf3nHYrkRy --- .../screens/coin-details-screen/components/TextPostCard.tsx | 3 +-- .../src/pages/fan-club-detail-page/components/TextPostCard.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx b/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx index 274b839d0e0..8ac243f647d 100644 --- a/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx +++ b/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx @@ -26,8 +26,7 @@ const messages = { * so each post looks visually distinct behind the blur. */ const generatePlaceholder = (commentId: ID) => { - const seed = - typeof commentId === 'string' ? commentId.length : Number(commentId) + const seed = Number(commentId) const wordCount = 5 + (seed % 21) // 5–25 words const words = [] const pool = 'abcdefghijklmnopqrstuvwxyz' diff --git a/packages/web/src/pages/fan-club-detail-page/components/TextPostCard.tsx b/packages/web/src/pages/fan-club-detail-page/components/TextPostCard.tsx index 7ac18820085..d90cad695e2 100644 --- a/packages/web/src/pages/fan-club-detail-page/components/TextPostCard.tsx +++ b/packages/web/src/pages/fan-club-detail-page/components/TextPostCard.tsx @@ -44,8 +44,7 @@ const messages = { * so each post looks visually distinct behind the blur. */ const generatePlaceholder = (commentId: ID) => { - // Simple hash from commentId to get a stable length between 5 and 25 words - const seed = typeof commentId === 'string' ? commentId.length : Number(commentId) + const seed = Number(commentId) const wordCount = 5 + (seed % 21) // 5–25 words const words = [] const pool = 'abcdefghijklmnopqrstuvwxyz' From 5c69b7faaa01d12cef5f0a36587727425dc2f8cd Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Thu, 2 Apr 2026 16:25:32 -0700 Subject: [PATCH 3/3] Finalize --- .../components/TextPostCard.tsx | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx b/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx index 8ac243f647d..d8037376ae5 100644 --- a/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx +++ b/packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx @@ -28,7 +28,7 @@ const messages = { const generatePlaceholder = (commentId: ID) => { const seed = Number(commentId) const wordCount = 5 + (seed % 21) // 5–25 words - const words = [] + const words: string[] = [] const pool = 'abcdefghijklmnopqrstuvwxyz' for (let i = 0; i < wordCount; i++) { const len = 3 + ((seed * (i + 1) * 7) % 8) // 3–10 chars per word @@ -47,7 +47,7 @@ type TextPostCardProps = { export const TextPostCard = ({ commentId }: TextPostCardProps) => { const { data: comment, isPending } = useComment(commentId) - const { color, spacing, cornerRadius } = useTheme() + const { color } = useTheme() if (isPending) { return ( @@ -102,18 +102,11 @@ export const TextPostCard = ({ commentId }: TextPostCardProps) => { {isLocked ? ( - + {generatePlaceholder(commentId)}