Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 27 additions & 22 deletions packages/mobile/src/screens/contest-screen/ContestStemsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { UserLink } from 'app/components/user-link'

const messages = {
heading: 'STEMS & DOWNLOADS',
downloadHeading: 'DOWNLOAD',
publicFree: 'Public Free',
download: 'Download',
downloadAll: 'Download All',
Expand Down Expand Up @@ -88,6 +89,7 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
? (source as { uri?: string }).uri
: undefined
const stemsCount = stems.length
const hasStems = stemsCount > 0

const { data: fileSizes } = useFileSizes(
{
Expand All @@ -104,7 +106,8 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
const STEMS_COLLAPSE_THRESHOLD = 5
const stemsBelowThreshold = stemsCount <= STEMS_COLLAPSE_THRESHOLD
const [expandedOverride, setExpandedOverride] = useState<boolean | null>(null)
const expanded = expandedOverride ?? stemsBelowThreshold
const expanded = hasStems && (expandedOverride ?? stemsBelowThreshold)
const heading = hasStems ? messages.heading : messages.downloadHeading
const setExpanded = (next: boolean | ((prev: boolean) => boolean)) => {
setExpandedOverride((prev) => {
const current = prev ?? stemsBelowThreshold
Expand Down Expand Up @@ -186,7 +189,7 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
return (
<Paper direction='column' p='l' gap='m' borderRadius='m' shadow='flat'>
<Text variant='label' size='m' color='subdued'>
{messages.heading}
{heading}
</Text>

{/* Inner bordered container — separates the source-track +
Expand Down Expand Up @@ -219,27 +222,29 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
</Text>
<UserLink userId={artist.user_id} size='s' />
</Flex>
<Pressable
onPress={() => setExpanded((v) => !v)}
accessibilityRole='button'
accessibilityLabel={expanded ? 'Collapse stems' : 'Expand stems'}
style={{
padding: 4,
alignItems: 'center',
justifyContent: 'center'
}}
>
<View
{hasStems ? (
<Pressable
onPress={() => setExpanded((v) => !v)}
accessibilityRole='button'
accessibilityLabel={expanded ? 'Collapse stems' : 'Expand stems'}
style={{
// Rotate the caret via transform — react-native
// doesn't support CSS transitions, so this is a
// discrete flip rather than an animated rotation.
transform: [{ rotate: expanded ? '180deg' : '0deg' }]
padding: 4,
alignItems: 'center',
justifyContent: 'center'
}}
>
<IconCaretDown size='m' color='default' />
</View>
</Pressable>
<View
style={{
// Rotate the caret via transform — react-native
// doesn't support CSS transitions, so this is a
// discrete flip rather than an animated rotation.
transform: [{ rotate: expanded ? '180deg' : '0deg' }]
}}
>
<IconCaretDown size='m' color='default' />
</View>
</Pressable>
) : null}
</Flex>

{/* Footer row: N Stems outlined pill + Download All text. */}
Expand All @@ -251,7 +256,7 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
justifyContent='space-between'
gap='m'
>
{stemsCount > 0 ? (
{hasStems ? (
<Flex
ph='m'
pv='2xs'
Expand All @@ -270,7 +275,7 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
<Pressable onPress={handleDownloadAll}>
<Flex direction='row' gap='xs' alignItems='center'>
<Text variant='label' size='s' strength='strong'>
{stemsCount > 0 ? messages.downloadAll : messages.download}
{hasStems ? messages.downloadAll : messages.download}
</Text>
<IconReceive size='s' color='default' />
</Flex>
Expand Down
16 changes: 11 additions & 5 deletions packages/mobile/src/screens/track-screen/DownloadSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const STEM_INDEX_OFFSET_WITH_ORIGINAL_TRACK = 2

const messages = {
title: 'Stems & Downloads',
downloadTitle: 'Download',
// TODO: When upgrading react native to >0.74, we need to remove the $ here
// and also update android to include jsc+intl
// https://github.com/facebook/hermes/issues/23
Expand Down Expand Up @@ -152,7 +153,10 @@ export const DownloadSection = ({ trackId }: { trackId: ID }) => {
])

const hasStems = stemTracks.length > 0
const sectionTitle = hasStems ? messages.title : messages.downloadTitle
const downloadButtonText = hasStems ? messages.downloadAll : messages.download
const isSingleTrackDownload = !!track?.is_downloadable && !hasStems
const isDownloadsExpanded = !isSingleTrackDownload && isExpanded

const handleDownloadButtonPress = useCallback(() => {
if (hasStems) {
Expand All @@ -164,15 +168,17 @@ export const DownloadSection = ({ trackId }: { trackId: ID }) => {

const renderHeader = () => {
return (
<Flex gap='l' column pb={isExpanded ? 'l' : undefined}>
<Flex gap='l' column pb={isDownloadsExpanded ? 'l' : undefined}>
<Flex row justifyContent='space-between' alignItems='center'>
<Flex row alignItems='center' gap='s'>
<IconReceive color='default' />
<Text variant='label' size='l' strength='strong'>
{messages.title}
{sectionTitle}
</Text>
</Flex>
<ExpandableArrowIcon expanded={isExpanded} />
{isSingleTrackDownload ? null : (
<ExpandableArrowIcon expanded={isDownloadsExpanded} />
)}
</Flex>
{shouldDisplayPremiumDownloadLocked && formattedPrice !== undefined ? (
<Button
Expand Down Expand Up @@ -232,8 +238,8 @@ export const DownloadSection = ({ trackId }: { trackId: ID }) => {
return (
<Expandable
renderHeader={renderHeader}
expanded={isExpanded}
onToggleExpand={onToggleExpand}
expanded={isDownloadsExpanded}
onToggleExpand={isSingleTrackDownload ? undefined : onToggleExpand}
>
<Flex gap='m'>
{track?.is_downloadable ? (
Expand Down
15 changes: 10 additions & 5 deletions packages/web/src/components/track/DownloadSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const STEM_INDEX_OFFSET_WITH_ORIGINAL_TRACK = 2

const messages = {
title: 'Stems & Downloads',
downloadTitle: 'Download',
unlockAll: (price: string) => `Unlock All ${price}`,
purchased: 'purchased',
followToDownload: 'Must follow artist to download.',
Expand Down Expand Up @@ -190,12 +191,14 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => {
)

const hasStems = stemTracks.length > 0 || isUploadingStems
const sectionTitle = hasStems ? messages.title : messages.downloadTitle
const downloadButtonText = hasStems ? messages.downloadAll : messages.download

// No caret / no expandable list when there's a single downloadable track
// (download original ON, no stems). Tapping the row's download button
// should be the entire interaction — there's nothing to expand.
const isSingleTrackDownload = !!is_downloadable && !hasStems
const isExpanded = !isSingleTrackDownload && expanded

const handleDownloadButtonClick = useRequiresAccountCallback(
(e: MouseEvent) => {
Expand Down Expand Up @@ -254,8 +257,10 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => {
cursor: isSingleTrackDownload ? 'default' : 'pointer'
}}
role={isSingleTrackDownload ? undefined : 'button'}
aria-expanded={isSingleTrackDownload ? undefined : expanded}
aria-controls={isSingleTrackDownload ? undefined : 'download-section'}
aria-expanded={isSingleTrackDownload ? undefined : isExpanded}
aria-controls={
isSingleTrackDownload ? undefined : 'downloads-section'
}
>
<Flex
justifyContent='space-between'
Expand All @@ -266,7 +271,7 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => {
<Flex row alignItems='center' gap='s'>
<IconReceive size='l' color='default' />
<Text variant='label' size='l' strength='strong'>
{messages.title}
{sectionTitle}
</Text>
</Flex>
<Flex gap='l' alignItems='center'>
Expand Down Expand Up @@ -325,7 +330,7 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => {
<IconCaretDown
css={{
transition: 'transform var(--harmony-expressive)',
transform: expanded ? 'rotate(-180deg)' : undefined
transform: isExpanded ? 'rotate(-180deg)' : undefined
}}
size='m'
color='default'
Expand All @@ -339,7 +344,7 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => {
</Text>
</Flex>
) : null}
<Expandable expanded={expanded} id='downloads-section'>
<Expandable expanded={isExpanded} id='downloads-section'>
<Box>
{is_downloadable ? (
<DownloadRow
Expand Down
45 changes: 25 additions & 20 deletions packages/web/src/pages/contest-page/components/ContestStemsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { useTrackCoverArt } from 'hooks/useTrackCoverArt'

const messages = {
heading: 'STEMS & DOWNLOADS',
downloadHeading: 'DOWNLOAD',
publicFree: 'Public Free',
unlockAll: (price: string) => `Unlock All ${price}`,
download: 'Download',
Expand Down Expand Up @@ -118,6 +119,7 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
}, [contestEventId, currentUserId, followState?.isFollowed, followEvent])

const stemsCount = stems.length
const hasStems = stemsCount > 0
// Default to expanded for short lists so users can see the stems
// without an extra click; collapse when there are more than
// STEMS_COLLAPSE_THRESHOLD entries so a long list doesn't push the
Expand All @@ -126,7 +128,8 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
const STEMS_COLLAPSE_THRESHOLD = 5
const stemsBelowThreshold = stemsCount <= STEMS_COLLAPSE_THRESHOLD
const [expandedOverride, setExpandedOverride] = useState<boolean | null>(null)
const expanded = expandedOverride ?? stemsBelowThreshold
const expanded = hasStems && (expandedOverride ?? stemsBelowThreshold)
const heading = hasStems ? messages.heading : messages.downloadHeading
const setExpanded = (next: boolean | ((prev: boolean) => boolean)) => {
setExpandedOverride((prev) => {
const current = prev ?? stemsBelowThreshold
Expand Down Expand Up @@ -250,7 +253,7 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
COMMENTS tiles. */}
<Box pt='l' ph='l'>
<Text variant='label' size='m' color='subdued'>
{messages.heading}
{heading}
</Text>
</Box>

Expand Down Expand Up @@ -299,22 +302,24 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
<UserLink userId={artist.user_id} popover size='s' />
</Flex>
</Flex>
<IconCaretDown
size='m'
color='default'
css={{
transition: 'transform var(--harmony-expressive)',
transform: expanded ? 'rotate(-180deg)' : undefined,
cursor: 'pointer'
}}
onClick={(e) => {
e.stopPropagation()
setExpanded((v) => !v)
}}
aria-expanded={expanded}
aria-label={expanded ? 'Collapse stems' : 'Expand stems'}
role='button'
/>
{hasStems ? (
<IconCaretDown
size='m'
color='default'
css={{
transition: 'transform var(--harmony-expressive)',
transform: expanded ? 'rotate(-180deg)' : undefined,
cursor: 'pointer'
}}
onClick={(e) => {
e.stopPropagation()
setExpanded((v) => !v)
}}
aria-expanded={expanded}
aria-label={expanded ? 'Collapse stems' : 'Expand stems'}
role='button'
/>
) : null}
</Flex>

{/* Secondary action row: stems pill + Download All / Unlock
Expand All @@ -327,7 +332,7 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
alignItems='center'
onClick={(e) => e.stopPropagation()}
>
{stemsCount > 0 ? <StemCountPill count={stemsCount} /> : <Box />}
{hasStems ? <StemCountPill count={stemsCount} /> : <Box />}
{shouldDisplayPremiumDownloadLocked && formattedPrice ? (
<Button
size='small'
Expand All @@ -343,7 +348,7 @@ export const ContestStemsCard = ({ trackId }: ContestStemsCardProps) => {
iconRight={IconReceive}
onClick={handleDownloadAll}
>
{stemsCount > 0 ? messages.downloadAll : messages.download}
{hasStems ? messages.downloadAll : messages.download}
</PlainButton>
)}
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const STEM_INDEX_OFFSET_WITH_ORIGINAL_TRACK = 2

const messages = {
title: 'Stems & Downloads',
downloadTitle: 'Download',
unlockAll: (price: string) => `Unlock All ${price}`,
purchased: 'purchased',
followToDownload: 'Must follow artist to download.',
Expand Down Expand Up @@ -174,7 +175,10 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => {
)

const hasStems = stemTracks.length > 0
const sectionTitle = hasStems ? messages.title : messages.downloadTitle
const downloadButtonText = hasStems ? messages.downloadAll : messages.download
const isSingleTrackDownload = !!is_downloadable && !hasStems
const isExpanded = !isSingleTrackDownload && expanded

const handleDownloadButtonClick = useRequiresAccountCallback(
(e) => {
Expand All @@ -194,33 +198,37 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => {
<Flex
gap='m'
pt='l'
pb={expanded ? 'l' : undefined}
pb={isExpanded ? 'l' : undefined}
w='100%'
column
justifyContent='space-between'
alignItems='flex-start'
backgroundColor='white'
role='button'
aria-expanded={expanded}
aria-controls='download-section'
onClick={onToggleExpand}
role={isSingleTrackDownload ? undefined : 'button'}
aria-expanded={isSingleTrackDownload ? undefined : isExpanded}
aria-controls={
isSingleTrackDownload ? undefined : 'downloads-section'
}
onClick={isSingleTrackDownload ? undefined : onToggleExpand}
borderTop='default'
>
<Flex justifyContent='space-between' row wrap='wrap' gap='m' w='100%'>
<Flex row alignItems='center' gap='s'>
<IconReceive size='l' color='default' />
<Text variant='label' size='l' strength='strong'>
{messages.title}
{sectionTitle}
</Text>
</Flex>
<IconCaretDown
css={{
transition: 'transform var(--harmony-expressive)',
transform: expanded ? 'rotate(-180deg)' : undefined
}}
size='m'
color='default'
/>
{isSingleTrackDownload ? null : (
<IconCaretDown
css={{
transition: 'transform var(--harmony-expressive)',
transform: isExpanded ? 'rotate(-180deg)' : undefined
}}
size='m'
color='default'
/>
)}
{shouldDisplayPremiumDownloadLocked &&
formattedPrice !== undefined ? (
<Button
Expand Down Expand Up @@ -271,7 +279,7 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => {
</Text>
</Flex>
) : null}
<Expandable expanded={expanded} id='downloads-section'>
<Expandable expanded={isExpanded} id='downloads-section'>
<Flex column gap='l'>
{is_downloadable ? (
<Flex column gap='l'>
Expand Down
Loading