diff --git a/packages/mobile/src/components/notification-reminder/NotificationReminder.tsx b/packages/mobile/src/components/notification-reminder/NotificationReminder.tsx
index 8b00134c85d..013fa424ab0 100644
--- a/packages/mobile/src/components/notification-reminder/NotificationReminder.tsx
+++ b/packages/mobile/src/components/notification-reminder/NotificationReminder.tsx
@@ -53,7 +53,6 @@ const NotificationReminderInternal = () => {
dispatch(
setVisibility({ drawer: 'EnablePushNotifications', visible: true })
)
- return
}
} catch (error) {
// Not sure what happened, but swallow the error. Not worth blocking on.
diff --git a/packages/mobile/src/harmony-native/components/input/SelectablePill/SelectablePill.tsx b/packages/mobile/src/harmony-native/components/input/SelectablePill/SelectablePill.tsx
index ae265b940ca..6acfc64f2c9 100644
--- a/packages/mobile/src/harmony-native/components/input/SelectablePill/SelectablePill.tsx
+++ b/packages/mobile/src/harmony-native/components/input/SelectablePill/SelectablePill.tsx
@@ -4,7 +4,6 @@ import { useControlled } from '@audius/harmony/src/hooks/useControlled'
import { css } from '@emotion/native'
import { Pressable } from 'react-native'
import type { GestureResponderEvent } from 'react-native'
-import { Gesture, GestureDetector, State } from 'react-native-gesture-handler'
import Animated, {
interpolate,
interpolateColor,
@@ -35,7 +34,7 @@ export const SelectablePill = (props: SelectablePillProps) => {
value,
style: styleProp,
fullWidth,
- isControlled,
+ disableUnselectAnimation,
...other
} = props
const { color, motion, cornerRadius, typography } = useTheme()
@@ -50,8 +49,20 @@ export const SelectablePill = (props: SelectablePillProps) => {
const selected = useSharedValue(isSelected ? 1 : 0)
const handlePressIn = useCallback(() => {
+ pressed.value = withTiming(1, motion.press)
+ if (!isSelected) {
+ selected.value = withTiming(1, motion.press)
+ }
setIsPressing(true)
- }, [])
+ }, [pressed, motion.press, selected, setIsPressing, isSelected])
+
+ const handleTouchCancel = useCallback(() => {
+ pressed.value = withTiming(0, motion.press)
+ if (!isSelected) {
+ selected.value = withTiming(0, motion.press)
+ }
+ setIsPressing(false)
+ }, [pressed, motion.press, selected, setIsPressing, isSelected])
const handlePress = useCallback(
(e: GestureResponderEvent) => {
@@ -65,28 +76,22 @@ export const SelectablePill = (props: SelectablePillProps) => {
[onChange, onPress, value, isSelected, setIsSelected]
)
- const tap = Gesture.Tap()
- .shouldCancelWhenOutside(true)
- .onBegin(() => {
- pressed.value = withTiming(1, motion.press)
- if (!isSelected) {
- selected.value = withTiming(1, motion.press)
- }
- })
- .onFinalize((event) => {
- pressed.value = withTiming(0, motion.press)
- const isDeselect =
- event.state === State.END && isSelected && !isControlled
- const isCancel = event.state !== State.END && !isSelected
- if (isDeselect || isCancel) {
- selected.value = withTiming(0, motion.press)
- }
- })
-
useEffect(() => {
setIsSelected(isSelectedProp)
- selected.value = withTiming(isSelectedProp ? 1 : 0, motion.press)
- }, [isSelectedProp, motion.press, selected, setIsSelected])
+ if (isSelectedProp) {
+ selected.value = withTiming(1, motion.press)
+ } else {
+ selected.value = disableUnselectAnimation
+ ? 0
+ : withTiming(0, motion.press)
+ }
+ }, [
+ isSelectedProp,
+ motion.press,
+ selected,
+ setIsSelected,
+ disableUnselectAnimation
+ ])
const animatedRootStyles = useAnimatedStyle(() => ({
opacity: withTiming(disabled ? 0.45 : 1, motion.press),
@@ -112,56 +117,49 @@ export const SelectablePill = (props: SelectablePillProps) => {
}))
return (
-
-
+
-
+ ) : null}
+
- {size !== 'small' && Icon ? (
-
- ) : null}
-
- {label}
-
-
-
-
+ {label}
+
+
+
)
}
diff --git a/packages/mobile/src/harmony-native/components/input/SelectablePill/types.ts b/packages/mobile/src/harmony-native/components/input/SelectablePill/types.ts
index bd0df681f58..4822b707edb 100644
--- a/packages/mobile/src/harmony-native/components/input/SelectablePill/types.ts
+++ b/packages/mobile/src/harmony-native/components/input/SelectablePill/types.ts
@@ -12,5 +12,6 @@ export type SelectablePillProps = {
icon?: IconComponent
onChange?: (value: string, isSelected?: boolean) => void
fullWidth?: boolean
+ disableUnselectAnimation?: boolean
} & Pick &
ViewProps
diff --git a/packages/mobile/src/screens/search-screen-v2/SearchCategoriesAndFilters.tsx b/packages/mobile/src/screens/search-screen-v2/SearchCategoriesAndFilters.tsx
index f6c23b25960..1ade2511549 100644
--- a/packages/mobile/src/screens/search-screen-v2/SearchCategoriesAndFilters.tsx
+++ b/packages/mobile/src/screens/search-screen-v2/SearchCategoriesAndFilters.tsx
@@ -50,6 +50,9 @@ const SearchCategory = (props: SearchCategoryProps) => {
setCategory(isSelected ? (value as SearchCategoryType) : 'all')
}}
icon={isSelected ? IconCloseAlt : undefined}
+ // Disable unselect animation when the category is selected
+ // to avoid a flash of purple as the pills rearrange
+ disableUnselectAnimation
/>
)
}
diff --git a/packages/web/src/components/edit/fields/AdvancedField.tsx b/packages/web/src/components/edit/fields/AdvancedField.tsx
index 12001cb3dd4..2d94a1c4ae9 100644
--- a/packages/web/src/components/edit/fields/AdvancedField.tsx
+++ b/packages/web/src/components/edit/fields/AdvancedField.tsx
@@ -491,8 +491,7 @@ const AdvancedModalFields = ({ isUpload }: { isUpload?: boolean }) => {
const input = e.nativeEvent.target as HTMLInputElement
input.value = input.value.slice(0, input.maxLength)
}}
- label={messages.bpm.header}
- placeholder={messages.bpm.label}
+ label={messages.bpm.label}
autoComplete='off'
/>
diff --git a/packages/web/src/components/lineup/LineupProvider.tsx b/packages/web/src/components/lineup/LineupProvider.tsx
index 413a4dd7062..c2c22c18bcb 100644
--- a/packages/web/src/components/lineup/LineupProvider.tsx
+++ b/packages/web/src/components/lineup/LineupProvider.tsx
@@ -510,12 +510,14 @@ class LineupProvider extends PureComponent {
let tileSize: TrackTileSize
let lineupStyle = {}
let containerClassName: string
+ let statSize = 'large'
if (variant === LineupVariant.MAIN || variant === LineupVariant.PLAYLIST) {
tileSize = TrackTileSize.LARGE
lineupStyle = styles.main
} else if (variant === LineupVariant.SECTION) {
tileSize = TrackTileSize.SMALL
lineupStyle = styles.section
+ statSize = 'small'
containerClassName = styles.searchTrackTileContainer
} else if (variant === LineupVariant.CONDENSED) {
tileSize = TrackTileSize.SMALL
@@ -539,6 +541,7 @@ class LineupProvider extends PureComponent {
ordered,
togglePlay: this.togglePlay,
size: tileSize,
+ statSize,
containerClassName,
uid: entry.uid,
showArtistPick: showLeadingElementArtistPick && !!leadingElementId,
diff --git a/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx b/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx
index c49f1870b1e..bf2136d3dae 100644
--- a/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx
+++ b/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx
@@ -64,6 +64,7 @@ type OwnProps = {
order: number
containerClassName?: string
size: TrackTileSize
+ statSize: 'small' | 'large'
showArtistPick: boolean
ordered: boolean
togglePlay: (uid: UID, id: ID) => void
@@ -106,7 +107,8 @@ const ConnectedTrackTile = ({
isTrending,
isFeed = false,
showRankIcon,
- onClick
+ onClick,
+ statSize = 'large'
}: ConnectedTrackTileProps) => {
const trackWithFallback = getTrackWithFallback(track)
const {
@@ -246,7 +248,6 @@ const ConnectedTrackTile = ({
const renderStats = () => {
const contentTitle = 'track' // undefined, playlist or album - undefined is track
- const statSize = 'large'
return (
{
return (