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 (