Skip to content

Commit

Permalink
[C-3447] Add select-artist native screen (#6955)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjeffers authored Dec 19, 2023
1 parent b6c7aae commit a9d2924
Show file tree
Hide file tree
Showing 31 changed files with 583 additions and 197 deletions.
1 change: 1 addition & 0 deletions packages/common/src/audius-query/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './AudiusQueryContext'
export * from './createApi'
export * from './hooks'
export * from './types'
9 changes: 9 additions & 0 deletions packages/common/src/messages/sign-on/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ export const selectGenresPageMessages = {
continue: 'Continue'
}

export const selectArtstsPageMessages = {
header: 'Follow At Least 3 Artists',
description:
'Curate your feed with tracks uploaded or reposted by anyone you follow. Click the artist’s photo to preview their music.',
genresLabel: 'Genre',
pickArtists: (genre: string) => `Pick ${genre} Artists`,
selected: 'Selected'
}

export const welcomeModalMessages = {
welcome: 'Welcome to Audius! 🎉',
startListening: 'Start Listening',
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './sign-on/passwordSchema'
export * from './sign-on/pickHandleSchema'
export * from './sign-on/finishProfileSchema'
export * from './sign-on/selectGenresSchema'
export * from './sign-on/selectArtistsSchema'
5 changes: 5 additions & 0 deletions packages/common/src/schemas/sign-on/selectArtistsSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { z } from 'zod'

export const selectArtistsSchema = z.object({
selectedArtists: z.array(z.string()).min(3)
})
3 changes: 2 additions & 1 deletion packages/harmony/src/components/avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export const Avatar = (props: AvatarProps) => {
const sizeMap = {
auto: '100%',
small: '24px',
large: '40px',
medium: '40px',
large: '72px',
xl: '80px'
}

Expand Down
2 changes: 1 addition & 1 deletion packages/harmony/src/components/avatar/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type AvatarProps = PropsWithChildren<{
* Size
* @default auto
*/
size?: 'auto' | 'small' | 'large' | 'xl'
size?: 'auto' | 'small' | 'medium' | 'large' | 'xl'

/**
* Stroke Width
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { useSelector } from 'react-redux'

import { makeStyles } from 'app/styles'

import { IconAudioBadge } from '../core/IconAudioBadge'
import { AppDrawer } from '../drawer/AppDrawer'

import { IconAudioBadge } from './IconAudioBadge'
import { TierText } from './TierText'
const { getProfileUserId } = profilePageSelectors

Expand Down
2 changes: 1 addition & 1 deletion packages/mobile/src/components/audio-rewards/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './IconAudioBadge'
export * from '../core/IconAudioBadge'
export * from './TiersExplainerDrawer'
export * from './RewardsBanner'
export * from './TierText'
8 changes: 2 additions & 6 deletions packages/mobile/src/components/core/CardList.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import type { ComponentType } from 'react'
import { useMemo, useCallback, useRef } from 'react'

import type {
FlatListProps,
ListRenderItem,
ListRenderItemInfo
} from 'react-native'
import type { ListRenderItem, ListRenderItemInfo } from 'react-native'
import { View } from 'react-native'

import { useScrollToTop } from 'app/hooks/useScrollToTop'
import { makeStyles } from 'app/styles'

import type { FlatListT } from './FlatList'
import type { FlatListT, FlatListProps } from './FlatList'
import { FlatList } from './FlatList'

export type CardListProps<ItemT> = Omit<FlatListProps<ItemT>, 'data'> & {
Expand Down
24 changes: 17 additions & 7 deletions packages/mobile/src/components/core/FlatList.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { MutableRefObject, Ref } from 'react'
import { forwardRef, useContext, useRef } from 'react'

import type { FlatListProps, FlatList as RNFlatList } from 'react-native'
import type {
FlatListProps as RNFlatListProps,
FlatList as RNFlatList
} from 'react-native'
import { Animated, Platform, RefreshControl, View } from 'react-native'
import { useCollapsibleScene } from 'react-native-collapsible-tab-view'

Expand All @@ -17,7 +20,7 @@ export type AnimatedFlatListT<ItemT> = Animated.FlatList<ItemT>

type CollapsibleFlatListProps<ItemT> = {
sceneName: string
} & Animated.AnimatedProps<FlatListProps<ItemT>>
} & Animated.AnimatedProps<RNFlatListProps<ItemT>>

function CollapsibleFlatList<ItemT>(props: CollapsibleFlatListProps<ItemT>) {
const { sceneName, onScroll, ...other } = props
Expand Down Expand Up @@ -48,7 +51,7 @@ function CollapsibleFlatList<ItemT>(props: CollapsibleFlatListProps<ItemT>) {
}

const AnimatedFlatList = forwardRef(function AnimatedFlatList<ItemT>(
props: Animated.AnimatedProps<FlatListProps<ItemT>>,
props: Animated.AnimatedProps<RNFlatListProps<ItemT>>,
ref: MutableRefObject<Animated.FlatList<ItemT> | null>
) {
const { refreshing, onRefresh, onScroll, ...other } = props
Expand Down Expand Up @@ -102,6 +105,10 @@ const AnimatedFlatList = forwardRef(function AnimatedFlatList<ItemT>(
)
})

export type FlatListProps<ItemT> = RNFlatListProps<ItemT> & {
sceneName?: string
}

/**
* Provides either a FlatList or an animated FlatList
* depending on whether or not the list is found in a "collapsible" header tab
Expand All @@ -110,8 +117,11 @@ export const FlatList = forwardRef(function FlatList<ItemT>(
props: FlatListProps<ItemT>,
ref: Ref<FlatListT<ItemT>>
) {
const { ListFooterComponent, ...other } = props
const { sceneName } = useContext(CollapsibleTabNavigatorContext)
const { ListFooterComponent, sceneName: sceneNameProp, ...other } = props
const { sceneName: sceneNameContext } = useContext(
CollapsibleTabNavigatorContext
)
const sceneName = sceneNameProp ?? sceneNameContext
const FooterComponent = ListFooterComponent ? (
<>
{ListFooterComponent}
Expand All @@ -130,14 +140,14 @@ export const FlatList = forwardRef(function FlatList<ItemT>(
return (
<CollapsibleFlatList
sceneName={sceneName}
{...(flatListProps as Animated.AnimatedProps<FlatListProps<ItemT>>)}
{...(flatListProps as Animated.AnimatedProps<RNFlatListProps<ItemT>>)}
/>
)
}
return (
<AnimatedFlatList
ref={ref as Ref<AnimatedFlatListT<ItemT>>}
{...(flatListProps as Animated.AnimatedProps<FlatListProps<ItemT>>)}
{...(flatListProps as Animated.AnimatedProps<RNFlatListProps<ItemT>>)}
/>
)
})
36 changes: 36 additions & 0 deletions packages/mobile/src/components/core/ProfilePicture.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { SquareSizes, type ID, cacheUsersSelectors } from '@audius/common'
import { useSelector } from 'react-redux'

import type { AvatarProps } from '@audius/harmony-native'
import { Avatar } from '@audius/harmony-native'

import { useProfilePicture } from '../image/UserImage'
const { getUser } = cacheUsersSelectors

type ProfilePictureProps = Omit<
AvatarProps,
'source' | 'accessibilityLabel'
> & {
userId: ID
}

export const ProfilePicture = (props: ProfilePictureProps) => {
const { userId, ...other } = props

const userName = useSelector((state) => getUser(state, { id: userId })?.name)
const accessibilityLabel = `Profile picture for ${userName}`

const { source, handleError } = useProfilePicture(
userId,
SquareSizes.SIZE_150_BY_150
)

return (
<Avatar
source={source}
onError={handleError}
accessibilityLabel={accessibilityLabel}
{...other}
/>
)
}
25 changes: 25 additions & 0 deletions packages/mobile/src/components/core/UserCoverPhoto.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { ID } from '@audius/common'

import type { CoverPhotoProps } from '@audius/harmony-native'
import { CoverPhoto } from '@audius/harmony-native'

import { useCoverPhoto } from '../image/CoverPhoto'

type UserCoverPhotoProps = {
userId: ID
} & Pick<CoverPhotoProps, 'style' | 'topCornerRadius'>

export const UserCoverPhoto = (props: UserCoverPhotoProps) => {
const { userId, ...other } = props

const { source, handleError, shouldBlur } = useCoverPhoto(userId)

return (
<CoverPhoto
coverPhoto={shouldBlur ? undefined : source}
profilePicture={shouldBlur ? source : undefined}
onError={handleError}
{...other}
/>
)
}
42 changes: 42 additions & 0 deletions packages/mobile/src/components/core/UserDisplayName.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useSelectTierInfo, type ID, cacheUsersSelectors } from '@audius/common'
import { useSelector } from 'react-redux'

import type { TextProps } from '@audius/harmony-native'
import {
Flex,
IconVerified,
Text,
useTheme,
variantStylesMap
} from '@audius/harmony-native'

import { IconAudioBadge } from './IconAudioBadge'

const { getUser } = cacheUsersSelectors

type UserDisplayProps = TextProps & {
userId: ID
}

export const UserDisplayName = (props: UserDisplayProps) => {
const { userId, variant = 'title', size = 's', style, ...other } = props
const { tier, isVerified } = useSelectTierInfo(userId)
const displayName = useSelector(
(state) => getUser(state, { id: userId })?.name
)
const { typography } = useTheme()
const fontSize = typography.size[variantStylesMap[variant].fontSize[size]]
const badgeSize = fontSize - 2

return (
<Flex direction='row' gap='xs' alignItems='center' style={style}>
<Text variant={variant} size={size} {...other}>
{displayName}
</Text>
{isVerified ? (
<IconVerified height={badgeSize} width={badgeSize} />
) : null}
<IconAudioBadge tier={tier} height={fontSize} width={fontSize} />
</Flex>
)
}
3 changes: 3 additions & 0 deletions packages/mobile/src/components/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ export * from './InputErrorMessage'
export * from './DogEar'
export * from './LockedStatusBadge'
export * from './ModalScreen'
export * from './ProfilePicture'
export * from './UserCoverPhoto'
export * from './UserDisplayName'
4 changes: 4 additions & 0 deletions packages/mobile/src/components/user/ProfilePicture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export type ProfilePictureProps = Partial<FastImageProps> &
}
)

/**
* @deprecated
* Use image/ProfilePicture instead
*/
export const ProfilePicture = (props: ProfilePictureProps) => {
const { style: styleProp, ...other } = props
const userId = 'userId' in other ? other.userId : other.profile.user_id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export type AvatarProps = Omit<HarmonyAvatarProps, 'src'> &
const sizeMap = {
auto: '100%',
small: 24,
large: 40,
medium: 40,
large: 72,
xl: 80
}

Expand All @@ -28,7 +29,7 @@ export const Avatar = (props: AvatarProps) => {
const {
children,
source,
size = 'auto',
size = 'medium',
strokeWidth = 'default',
variant = 'default',
style,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useMemo, useState } from 'react'
import type { ChangeEvent } from 'react'
import { useCallback, useEffect, useState } from 'react'

import { css } from '@emotion/native'
import { Pressable } from 'react-native'
Expand All @@ -20,6 +21,8 @@ export const FollowButton = (props: FollowButtonProps) => {
onUnfollow,
onFollow,
size = 'default',
value,
onChange,
...other
} = props
const { disabled } = other
Expand All @@ -30,18 +33,19 @@ export const FollowButton = (props: FollowButtonProps) => {
setFollowing(isFollowing)
}, [isFollowing])

const Icon = useMemo(() => {
return following ? IconUserFollowing : IconUserFollow
}, [following])
const Icon = following ? IconUserFollowing : IconUserFollow

const handlePress = useCallback(() => {
if (following) {
onUnfollow?.()
} else {
onFollow?.()
}
onChange?.({
target: { value, checked: true, type: 'checkbox' }
} as ChangeEvent<HTMLInputElement>)
setFollowing(!following)
}, [following, onUnfollow, onFollow])
}, [following, onChange, value, onUnfollow, onFollow])

return (
<Pressable onPress={handlePress} {...other}>
Expand All @@ -52,12 +56,11 @@ export const FollowButton = (props: FollowButtonProps) => {
justifyContent='center'
gap='xs'
pv='s'
border='default'
style={css({
opacity: disabled ? 0.45 : 1,
borderRadius:
variant === 'pill' ? cornerRadius['2xl'] : cornerRadius.s,
borderWidth: 1,
borderStyle: 'solid',
borderColor: color.primary.primary,
backgroundColor: following
? color.primary.primary
Expand All @@ -67,7 +70,7 @@ export const FollowButton = (props: FollowButtonProps) => {
<Icon
height={18}
width={18}
fill={following ? color.text.staticWhite : color.primary.primary}
fill={following ? color.icon.staticWhite : color.primary.primary}
/>
</Flex>
</Pressable>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { ChangeEvent } from 'react'

import type { PressableProps } from 'react-native/types'

export type FollowButtonProps = {
Expand Down Expand Up @@ -27,4 +29,7 @@ export type FollowButtonProps = {
* Callback for when an unfollow is triggered.
*/
onUnfollow?: () => void
value?: any
onChange?: (e: ChangeEvent<HTMLInputElement>) => void
// onChange?: (e: { target: { value: any; checked: boolean } }) => void
} & Pick<PressableProps, 'onPress' | 'disabled'>
Loading

0 comments on commit a9d2924

Please sign in to comment.