mirror of
https://github.com/Boof2015/astra-mobile.git
synced 2026-08-19 04:06:43 +02:00
optimize further
This commit is contained in:
@@ -11,14 +11,16 @@ import {
|
||||
spacing,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles } from '@/theme/themed';
|
||||
import { SCROLL_PRESS_DELAY, useRipple } from '@/theme/ripple';
|
||||
import { albumArtworkSource } from '@/library/artwork';
|
||||
import type { Album } from '@/types/library';
|
||||
|
||||
export function AlbumGridItem({ album, onPress }: { album: Album; onPress: () => void }) {
|
||||
const styles = useStyles();
|
||||
const ripple = useRipple();
|
||||
const artUri = albumArtworkSource(album);
|
||||
return (
|
||||
<Pressable style={styles.item} onPress={onPress} accessibilityRole="button">
|
||||
<Pressable android_ripple={ripple.tile} unstable_pressDelay={SCROLL_PRESS_DELAY} style={styles.item} onPress={onPress} accessibilityRole="button">
|
||||
<View style={styles.art}>
|
||||
{artUri ? (
|
||||
<Image
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
spacing,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { SCROLL_PRESS_DELAY, useRipple } from '@/theme/ripple';
|
||||
import { albumArtworkSource } from '@/library/artwork';
|
||||
import type { Album } from '@/types/library';
|
||||
|
||||
@@ -18,9 +19,10 @@ import type { Album } from '@/types/library';
|
||||
export function AlbumRow({ album, onPress }: { album: Album; onPress: () => void }) {
|
||||
const styles = useStyles();
|
||||
const colors = useColors();
|
||||
const ripple = useRipple();
|
||||
const artUri = albumArtworkSource(album);
|
||||
return (
|
||||
<Pressable style={styles.row} onPress={onPress} accessibilityRole="button">
|
||||
<Pressable android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY} style={styles.row} onPress={onPress} accessibilityRole="button">
|
||||
<View style={styles.art}>
|
||||
{artUri ? (
|
||||
<Image
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
radius,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { SCROLL_PRESS_DELAY, useRipple } from '@/theme/ripple';
|
||||
import { artworkUri } from '@/library/artwork';
|
||||
import type { Artist } from '@/types/library';
|
||||
|
||||
@@ -18,6 +19,7 @@ import type { Artist } from '@/types/library';
|
||||
export function ArtistGridItem({ artist, onPress }: { artist: Artist; onPress: () => void }) {
|
||||
const styles = useStyles();
|
||||
const colors = useColors();
|
||||
const ripple = useRipple();
|
||||
const useMosaic = artist.artwork_hashes.length >= 4;
|
||||
const hashes = useMosaic ? artist.artwork_hashes.slice(0, 4) : artist.artwork_hashes.slice(0, 1);
|
||||
|
||||
@@ -25,7 +27,7 @@ export function ArtistGridItem({ artist, onPress }: { artist: Artist; onPress: (
|
||||
const tracks = `${artist.track_count} ${artist.track_count === 1 ? 'track' : 'tracks'}`;
|
||||
|
||||
return (
|
||||
<Pressable style={styles.item} onPress={onPress} accessibilityRole="button">
|
||||
<Pressable android_ripple={ripple.tile} unstable_pressDelay={SCROLL_PRESS_DELAY} style={styles.item} onPress={onPress} accessibilityRole="button">
|
||||
<View style={styles.art}>
|
||||
{hashes.length === 0 ? (
|
||||
<Ionicons name="person" size={44} color={colors.textTertiary} />
|
||||
|
||||
@@ -11,14 +11,16 @@ import {
|
||||
spacing,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { SCROLL_PRESS_DELAY, useRipple } from '@/theme/ripple';
|
||||
import { artworkUri } from '@/library/artwork';
|
||||
import type { Artist } from '@/types/library';
|
||||
|
||||
export function ArtistRow({ artist, onPress }: { artist: Artist; onPress: () => void }) {
|
||||
const styles = useStyles();
|
||||
const colors = useColors();
|
||||
const ripple = useRipple();
|
||||
return (
|
||||
<Pressable style={styles.row} onPress={onPress} accessibilityRole="button">
|
||||
<Pressable android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY} style={styles.row} onPress={onPress} accessibilityRole="button">
|
||||
<View style={styles.art}>
|
||||
{artist.artwork_hash ? (
|
||||
<Image
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
spacing,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { SCROLL_PRESS_DELAY, useRipple } from '@/theme/ripple';
|
||||
|
||||
// Collapsing detail header. An absolute container whose height shrinks with the
|
||||
// scroll and clips its faded content, so the track list (padded to the expanded
|
||||
@@ -155,6 +156,7 @@ export function CollapsingHeader({
|
||||
onHeroBlockLayout: (e: LayoutChangeEvent) => void;
|
||||
}) {
|
||||
const styles = useStyles();
|
||||
const ripple = useRipple();
|
||||
const colors = useColors();
|
||||
const insets = useSafeAreaInsets();
|
||||
const { width: W } = useWindowDimensions();
|
||||
@@ -246,7 +248,7 @@ export function CollapsingHeader({
|
||||
{heroMeta}
|
||||
{heroExtra}
|
||||
<Animated.View style={[styles.actionRow, heroButtonsStyle]}>
|
||||
<Pressable
|
||||
<Pressable android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={[styles.actionButton, styles.primaryAction, disabled && styles.disabledAction]}
|
||||
onPress={onPlay}
|
||||
disabled={disabled}
|
||||
@@ -257,7 +259,7 @@ export function CollapsingHeader({
|
||||
Play
|
||||
</Text>
|
||||
</Pressable>
|
||||
<Pressable
|
||||
<Pressable android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={[styles.actionButton, styles.secondaryAction, disabled && styles.disabledAction]}
|
||||
onPress={onShuffle}
|
||||
disabled={disabled}
|
||||
@@ -271,7 +273,7 @@ export function CollapsingHeader({
|
||||
</Animated.View>
|
||||
</Animated.View>
|
||||
|
||||
<Pressable
|
||||
<Pressable android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
onPress={onBack}
|
||||
hitSlop={8}
|
||||
style={[styles.chevron, { top: barCenterY - 12, left: spacing.md }]}
|
||||
@@ -299,16 +301,16 @@ export function CollapsingHeader({
|
||||
style={[styles.barIcons, { top: barCenterY - 16, right: onMore ? spacing.md + 40 : spacing.md }, barIconsStyle]}
|
||||
pointerEvents={collapsed ? 'auto' : 'none'}
|
||||
>
|
||||
<Pressable onPress={onPlay} disabled={disabled} hitSlop={6} style={styles.iconBtn}>
|
||||
<Pressable android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY} onPress={onPlay} disabled={disabled} hitSlop={6} style={styles.iconBtn}>
|
||||
<Ionicons name="play" size={20} color={colors.accent} />
|
||||
</Pressable>
|
||||
<Pressable onPress={onShuffle} disabled={disabled} hitSlop={6} style={styles.iconBtn}>
|
||||
<Pressable android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY} onPress={onShuffle} disabled={disabled} hitSlop={6} style={styles.iconBtn}>
|
||||
<Ionicons name="shuffle" size={20} color={colors.accent} />
|
||||
</Pressable>
|
||||
</Animated.View>
|
||||
|
||||
{onMore ? (
|
||||
<Pressable
|
||||
<Pressable android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
onPress={onMore}
|
||||
hitSlop={8}
|
||||
style={[styles.moreButton, { top: barCenterY - 16, right: spacing.md }]}
|
||||
|
||||
@@ -10,9 +10,11 @@ import {
|
||||
spacing,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { useRipple } from '@/theme/ripple';
|
||||
|
||||
export function EmptyLibrary() {
|
||||
const styles = useStyles();
|
||||
const ripple = useRipple();
|
||||
const colors = useColors();
|
||||
const router = useRouter();
|
||||
|
||||
@@ -25,7 +27,7 @@ export function EmptyLibrary() {
|
||||
<Text variant="body" color={colors.textSecondary} style={styles.body}>
|
||||
Pick a folder on this device and Astra will scan it into your library.
|
||||
</Text>
|
||||
<Pressable style={styles.cta} onPress={() => router.push('/settings')} accessibilityRole="button">
|
||||
<Pressable android_ripple={ripple.bounded} style={styles.cta} onPress={() => router.push('/settings')} accessibilityRole="button">
|
||||
<Ionicons name="folder-open-outline" size={18} color={colors.bgPrimary} />
|
||||
<Text variant="body" style={styles.ctaLabel}>
|
||||
Folder settings
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
spacing,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { SCROLL_PRESS_DELAY, useRipple } from '@/theme/ripple';
|
||||
import { useLibraryStore } from '@/stores/libraryStore';
|
||||
import { usePlayerStore } from '@/stores/playerStore';
|
||||
import type { DbTrack } from '@/types/library';
|
||||
@@ -60,6 +61,7 @@ function FolderRow({
|
||||
}) {
|
||||
const styles = useStyles();
|
||||
const colors = useColors();
|
||||
const ripple = useRipple();
|
||||
const { node, depth, isExpanded } = row;
|
||||
|
||||
const play = (event: GestureResponderEvent) => {
|
||||
@@ -73,7 +75,8 @@ function FolderRow({
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={({ pressed }) => [styles.folderRow, pressed && styles.rowPressed]}
|
||||
android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={styles.folderRow}
|
||||
onPress={() => onToggle(node.id)}
|
||||
onLongPress={() => onOpenActions(node)}
|
||||
accessibilityRole="button"
|
||||
@@ -104,7 +107,8 @@ function FolderRow({
|
||||
{node.totalTrackCount}
|
||||
</Text>
|
||||
<Pressable
|
||||
style={({ pressed }) => [styles.folderButton, pressed && styles.folderButtonPressed]}
|
||||
android_ripple={ripple.icon(20)} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={styles.folderButton}
|
||||
onPress={play}
|
||||
hitSlop={6}
|
||||
accessibilityRole="button"
|
||||
@@ -113,7 +117,8 @@ function FolderRow({
|
||||
<Ionicons name="play" size={16} color={colors.accent} />
|
||||
</Pressable>
|
||||
<Pressable
|
||||
style={({ pressed }) => [styles.folderButton, pressed && styles.folderButtonPressed]}
|
||||
android_ripple={ripple.icon(20)} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={styles.folderButton}
|
||||
onPress={shuffle}
|
||||
hitSlop={6}
|
||||
accessibilityRole="button"
|
||||
@@ -136,6 +141,7 @@ function FolderTrackRow({
|
||||
}) {
|
||||
const styles = useStyles();
|
||||
const colors = useColors();
|
||||
const ripple = useRipple();
|
||||
const index = row.folderTracks.findIndex((track) => track.path === row.track.path);
|
||||
|
||||
const playFolderTrack = () => {
|
||||
@@ -148,11 +154,8 @@ function FolderTrackRow({
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={({ pressed }) => [
|
||||
styles.trackRow,
|
||||
active && styles.trackRowActive,
|
||||
pressed && styles.rowPressed,
|
||||
]}
|
||||
android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={[styles.trackRow, active && styles.trackRowActive]}
|
||||
onPress={playFolderTrack}
|
||||
onLongPress={onOpenActions}
|
||||
accessibilityRole="button"
|
||||
@@ -171,7 +174,8 @@ function FolderTrackRow({
|
||||
{formatDuration(row.track.duration)}
|
||||
</Text>
|
||||
<Pressable
|
||||
style={({ pressed }) => [styles.actionsButton, pressed && styles.actionsButtonPressed]}
|
||||
android_ripple={ripple.icon(21)} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={styles.actionsButton}
|
||||
onPress={openActions}
|
||||
hitSlop={8}
|
||||
accessibilityRole="button"
|
||||
@@ -347,9 +351,6 @@ const useStyles = createThemedStyles((colors) => ({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
folderButtonPressed: {
|
||||
backgroundColor: colors.glassBg,
|
||||
},
|
||||
trackRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
@@ -362,9 +363,6 @@ const useStyles = createThemedStyles((colors) => ({
|
||||
trackRowActive: {
|
||||
backgroundColor: colors.accentGlow,
|
||||
},
|
||||
rowPressed: {
|
||||
opacity: 0.72,
|
||||
},
|
||||
trackMeta: {
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
@@ -390,9 +388,6 @@ const useStyles = createThemedStyles((colors) => ({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
actionsButtonPressed: {
|
||||
backgroundColor: colors.glassBg,
|
||||
},
|
||||
empty: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
spacing,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { SCROLL_PRESS_DELAY, useRipple } from '@/theme/ripple';
|
||||
import { artworkUri } from '@/library/artwork';
|
||||
|
||||
export function PlaylistRow({
|
||||
@@ -39,8 +40,10 @@ export function PlaylistRow({
|
||||
}) {
|
||||
const styles = useStyles();
|
||||
const colors = useColors();
|
||||
const ripple = useRipple();
|
||||
return (
|
||||
<Pressable
|
||||
android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={styles.row}
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
spacing,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { SCROLL_PRESS_DELAY, useRipple } from '@/theme/ripple';
|
||||
import { usePlaylistStore } from '@/stores/playlistStore';
|
||||
import type { Playlist } from '@/types/playlist';
|
||||
|
||||
@@ -47,6 +48,7 @@ export function PlaylistsView({
|
||||
scrollEventThrottle?: number;
|
||||
}) {
|
||||
const styles = useStyles();
|
||||
const ripple = useRipple();
|
||||
const colors = useColors();
|
||||
const router = useRouter();
|
||||
const playlists = usePlaylistStore((s) => s.playlists);
|
||||
@@ -205,7 +207,7 @@ export function PlaylistsView({
|
||||
/>
|
||||
|
||||
<View style={styles.addBar}>
|
||||
<Pressable
|
||||
<Pressable android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={styles.addButton}
|
||||
onPress={() => setAddSheetOpen(true)}
|
||||
accessibilityRole="button"
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Ionicons } from '@expo/vector-icons';
|
||||
import { Text } from '@/components/Text';
|
||||
import { spacing } from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { useRipple } from '@/theme/ripple';
|
||||
|
||||
interface SelectionActionBarProps {
|
||||
count: number;
|
||||
@@ -66,13 +67,11 @@ function BarButton({
|
||||
}) {
|
||||
const styles = useStyles();
|
||||
const colors = useColors();
|
||||
const ripple = useRipple();
|
||||
return (
|
||||
<Pressable
|
||||
style={({ pressed }) => [
|
||||
styles.button,
|
||||
pressed && styles.buttonPressed,
|
||||
disabled && styles.buttonDisabled,
|
||||
]}
|
||||
android_ripple={ripple.bounded}
|
||||
style={[styles.button, disabled && styles.buttonDisabled]}
|
||||
onPress={onPress}
|
||||
disabled={disabled}
|
||||
accessibilityRole="button"
|
||||
@@ -101,9 +100,6 @@ const useStyles = createThemedStyles((colors) => ({
|
||||
gap: spacing.xs,
|
||||
paddingVertical: spacing.md,
|
||||
},
|
||||
buttonPressed: {
|
||||
opacity: 0.7,
|
||||
},
|
||||
buttonDisabled: {
|
||||
opacity: 0.4,
|
||||
},
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
spacing,
|
||||
} from '@/theme';
|
||||
import { createThemedStyles, useColors } from '@/theme/themed';
|
||||
import { SCROLL_PRESS_DELAY, useRipple } from '@/theme/ripple';
|
||||
import { formatDuration } from '@/lib/format';
|
||||
import { trackArtworkThumbSource } from '@/library/artwork';
|
||||
import { dbTrackToTrack } from '@/library/trackAdapter';
|
||||
@@ -60,6 +61,7 @@ export function TrackRow({
|
||||
}) {
|
||||
const styles = useStyles();
|
||||
const colors = useColors();
|
||||
const ripple = useRipple();
|
||||
// Key the artwork by hash (local) or identity path (remote) so the error fallback
|
||||
// and FlashList recycling work for both.
|
||||
const artKey = track.source_type !== 'local' ? track.path : track.artwork_hash;
|
||||
@@ -74,6 +76,7 @@ export function TrackRow({
|
||||
|
||||
const row = (
|
||||
<Pressable
|
||||
android_ripple={ripple.bounded} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={[styles.row, selectionMode && selected && styles.rowSelected]}
|
||||
onPress={selectionMode ? onToggleSelect : onPress}
|
||||
onLongPress={selectionMode ? onToggleSelect : (onLongPress ?? onOpenActions)}
|
||||
@@ -143,7 +146,8 @@ export function TrackRow({
|
||||
|
||||
{onOpenActions && !selectionMode ? (
|
||||
<Pressable
|
||||
style={({ pressed }) => [styles.actionsButton, pressed && styles.actionsButtonPressed]}
|
||||
android_ripple={ripple.icon(ACTIONS_BUTTON / 2 + 4)} unstable_pressDelay={SCROLL_PRESS_DELAY}
|
||||
style={styles.actionsButton}
|
||||
onPress={openActions}
|
||||
hitSlop={8}
|
||||
accessibilityRole="button"
|
||||
@@ -257,7 +261,4 @@ const useStyles = createThemedStyles((colors) => ({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
actionsButtonPressed: {
|
||||
backgroundColor: colors.glassBg,
|
||||
},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user