Skip to content

Commit

Permalink
[C-4031, C-4039] Fix add to collection, Add fuzzy search (#7887)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjeffers authored Mar 20, 2024
1 parent 05a0bb3 commit c876ae7
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 66 deletions.
2 changes: 1 addition & 1 deletion packages/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"ios:device:stage": "ENVFILE=.env.stage turbo run ios -- --scheme 'Staging' --mode Staging.Debug --device",
"ios:prod": "ENVFILE=.env.prod turbo run ios -- --scheme 'AudiusReactNative' --simulator \"iPhone 15 Pro\"",
"ios:release": "turbo run ios -- --simulator \"iPhone 15 Pro\" --mode Release",
"ios:stage": "ENVFILE=.env.stage turbo run ios -- --scheme 'Staging' --mode Staging.Debug --simulator \"iPhone SE (3rd generation)\"",
"ios:stage": "ENVFILE=.env.stage turbo run ios -- --scheme 'Staging' --mode Staging.Debug --simulator \"iPhone 15 Pro\"",
"ios:update-signing-cert": "cd ios && fastlane match development -a co.audius.audiusmusic,co.audius.audiusmusic.staging && cd ..",
"ios:version-patch": "fastlane run increment_version_number xcodeproj:\"ios/AudiusReactNative.xcodeproj\"",
"ios": "react-native run-ios",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useCallback, useMemo } from 'react'
import { useCallback, useMemo, useState } from 'react'

import type { Collection } from '@audius/common/models'
import { CreatePlaylistSource, SquareSizes } from '@audius/common/models'
import type { CommonState } from '@audius/common/store'
import {
accountSelectors,
cacheCollectionsActions,
collectionPageSelectors,
addToCollectionUISelectors,
duplicateAddConfirmationModalUIActions
} from '@audius/common/store'
Expand All @@ -21,10 +21,11 @@ import { AppDrawer, useDrawerState } from 'app/components/drawer'
import { CollectionImage } from 'app/components/image/CollectionImage'
import { useToast } from 'app/hooks/useToast'
import { makeStyles, shadow } from 'app/styles'
import { fuzzySearch } from 'app/utils/fuzzySearch'

import { CollectionList } from '../collection-list'
import { AddCollectionCard } from '../collection-list/AddCollectionCard'
const { getCollectionId } = collectionPageSelectors
import { FilterInput } from '../filter-input'

const { addTrackToPlaylist, createAlbum, createPlaylist } =
cacheCollectionsActions
Expand All @@ -34,11 +35,25 @@ const { getAccountWithNameSortedPlaylistsAndAlbums } = accountSelectors
const { requestOpen: openDuplicateAddConfirmation } =
duplicateAddConfirmationModalUIActions

const selectCollectionsToAddTo = (state: CommonState) => {
const collectionType = getCollectionType(state)
const account = getAccountWithNameSortedPlaylistsAndAlbums(state)
if (!account) return []
const { albums, playlists, user_id } = account
const collections = collectionType === 'album' ? albums : playlists

return collections.filter(
(collection) => collection.playlist_owner_id === user_id
)
}

const getMessages = (collectionType: 'album' | 'playlist') => ({
title: `Add To ${capitalize(collectionType)}`,
addedToast: `Added To ${capitalize(collectionType)}!`,
newCollection: `New ${capitalize(collectionType)}`,
hiddenAdd: `You cannot add hidden tracks to a public ${collectionType}.`
hiddenAdd: `You cannot add hidden tracks to a public ${collectionType}.`,
tracks: (count: number) => `${count} track${count === 1 ? '' : 's'}`,
filterPlaceholder: 'Find one of your playlists'
})

const useStyles = makeStyles(() => ({
Expand Down Expand Up @@ -66,53 +81,28 @@ export const AddToCollectionDrawer = () => {
const trackId = useSelector(getTrackId)
const trackTitle = useSelector(getTrackTitle)
const isTrackUnlisted = useSelector(getTrackIsUnlisted)
const account = useSelector(getAccountWithNameSortedPlaylistsAndAlbums)
const currentCollectionId = useSelector(getCollectionId)
const [filter, setFilter] = useState('')

const messages = getMessages(collectionType)

useEffectOnce(() => {
dispatch(fetchAccountCollections())
})

const renderImage = useCallback(
(item) => (props?: ImageProps) =>
(
<CollectionImage
collection={item}
size={SquareSizes.SIZE_480_BY_480}
{...props}
/>
),
[]
)
const collectionsToAddTo = useSelector(selectCollectionsToAddTo)

const filteredCollections = useMemo(() => {
return ((isAlbumType ? account?.albums : account?.playlists) ?? []).filter(
(collection: Collection) =>
// Don't allow adding to this collection if already on this collection's page.
collection.playlist_id !== currentCollectionId &&
collection.playlist_owner_id === account?.user_id
)
}, [
isAlbumType,
account?.albums,
account?.playlists,
account?.user_id,
currentCollectionId
])
const filteredCollectionsToAddTo = useMemo(() => {
return filter
? fuzzySearch(
filter,
collectionsToAddTo,
3,
(collection) => collection.playlist_name
)
: collectionsToAddTo
}, [collectionsToAddTo, filter])

const collectionTrackIdMap = useMemo(() => {
const collections =
(isAlbumType ? account?.albums : account?.playlists) ?? []
return collections.reduce((acc, playlist) => {
const trackIds = playlist.playlist_contents.track_ids.map((t) => t.track)
acc[playlist.playlist_id] = trackIds
return acc
}, {})
}, [account?.albums, account?.playlists, isAlbumType])

const addToNewCollection = useCallback(() => {
const handleAddToNewCollection = useCallback(() => {
const metadata = {
playlist_name: trackTitle ?? messages.newCollection
}
Expand Down Expand Up @@ -140,7 +130,7 @@ export const AddToCollectionDrawer = () => {
<AddCollectionCard
source={CreatePlaylistSource.FROM_TRACK}
sourceTrackId={trackId}
onCreate={addToNewCollection}
onCreate={handleAddToNewCollection}
collectionType={collectionType}
/>
) : (
Expand All @@ -150,7 +140,9 @@ export const AddToCollectionDrawer = () => {
type='collection'
id={item.playlist_id}
primaryText={item.playlist_name}
secondaryText={account?.name}
secondaryText={messages.tracks(
item.playlist_contents.track_ids.length
)}
onPress={() => {
if (!trackId) return

Expand All @@ -161,7 +153,9 @@ export const AddToCollectionDrawer = () => {
}

const doesCollectionContainTrack =
collectionTrackIdMap[item.playlist_id]?.includes(trackId)
item.playlist_contents.track_ids.some(
(track) => track.track === trackId
)

if (doesCollectionContainTrack) {
dispatch(
Expand All @@ -176,26 +170,28 @@ export const AddToCollectionDrawer = () => {
}
onClose()
}}
renderImage={renderImage(item)}
renderImage={(props?: ImageProps) => (
<CollectionImage
collection={item}
size={SquareSizes.SIZE_480_BY_480}
{...props}
/>
)}
/>
),
[
trackId,
addToNewCollection,
handleAddToNewCollection,
collectionType,
isTrackUnlisted,
account?.name,
renderImage,
collectionTrackIdMap,
messages,
onClose,
toast,
messages.hiddenAdd,
messages.addedToast,
dispatch
]
)

if (!account || !trackId || !trackTitle) {
if (!trackId || !trackTitle) {
return null
}

Expand All @@ -208,8 +204,14 @@ export const AddToCollectionDrawer = () => {
>
<View>
<CollectionList
ListHeaderComponent={
<FilterInput
placeholder={messages.filterPlaceholder}
onChangeText={setFilter}
/>
}
contentContainerStyle={styles.cardList}
collection={filteredCollections}
collection={filteredCollectionsToAddTo}
showCreatePlaylistTile
renderItem={renderCard}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ import { FilterInput } from 'app/components/filter-input'
import { useNavigation } from 'app/hooks/useNavigation'
import { remoteConfigInstance } from 'app/services/remote-config/remote-config-instance'

import { fuzzySearch } from '../../utils/fuzzySearch'
import { TopBarIconButton } from '../app-screen'
import { useAppScreenOptions } from '../app-screen/useAppScreenOptions'
import { SettingsRowLabel } from '../settings-screen/SettingRowLabel'
import { SettingsRow } from '../settings-screen/SettingsRow'
import { SettingsRowContent } from '../settings-screen/SettingsRowContent'

import { fuzzySearch } from './fuzzySearch'

const flags = Object.keys(FeatureFlags) as FeatureFlags[]

const Stack = createNativeStackNavigator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,16 @@ function levenshteinDistance(str1: string, str2: string): number {
return dp[m][n]
}

export function fuzzySearch<Data extends string>(
export function fuzzySearch<Data>(
query: string,
dataset: Data[],
threshold: number
threshold: number,
dataToString: (data: Data) => string = (data) => data as string
) {
const results: Array<{ item: Data; distance: number }> = []

for (const item of dataset) {
const lowercaseItem = item.toLowerCase()
const lowercaseItem = dataToString(item).toLowerCase()
if (lowercaseItem.includes(query.toLowerCase())) {
results.push({ item, distance: 0 })
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
import {
accountSelectors,
cacheCollectionsActions,
collectionPageSelectors,
addToCollectionUISelectors,
duplicateAddConfirmationModalUIActions,
toastActions
Expand All @@ -28,7 +27,6 @@ import { collectionPage } from 'utils/route'
import styles from './AddToCollectionModal.module.css'
const { getCollectionType, getTrackId, getTrackTitle, getTrackIsUnlisted } =
addToCollectionUISelectors
const { getCollectionId } = collectionPageSelectors
const { addTrackToPlaylist, createAlbum, createPlaylist } =
cacheCollectionsActions
const { getAccountWithNameSortedPlaylistsAndAlbums } = accountSelectors
Expand All @@ -54,7 +52,6 @@ const AddToCollectionModal = () => {
const trackId = useSelector(getTrackId)
const trackTitle = useSelector(getTrackTitle)
const isTrackUnlisted = useSelector(getTrackIsUnlisted)
const currentCollectionId = useSelector(getCollectionId)
const isAlbumType = collectionType === 'album'
const account = useSelector(getAccountWithNameSortedPlaylistsAndAlbums)
const [searchValue, setSearchValue] = useState('')
Expand All @@ -64,8 +61,6 @@ const AddToCollectionModal = () => {
const filteredCollections = useMemo(() => {
return ((isAlbumType ? account?.albums : account?.playlists) ?? []).filter(
(collection: Collection) =>
// Don't allow adding to this collection if already on this collection's page.
collection.playlist_id !== currentCollectionId &&
collection.playlist_owner_id === account?.user_id &&
(searchValue
? collection.playlist_name
Expand All @@ -78,7 +73,6 @@ const AddToCollectionModal = () => {
account?.albums,
account?.playlists,
account?.user_id,
currentCollectionId,
searchValue
])

Expand Down

0 comments on commit c876ae7

Please sign in to comment.