smoothing

This commit is contained in:
Boof2015
2026-07-01 19:08:32 -04:00
parent 2016a0037d
commit cab67fbc05
7 changed files with 85 additions and 26 deletions
+5 -1
View File
@@ -5,17 +5,21 @@ import { Easing } from 'react-native';
import { TabBar, type TabItem } from '@/components/TabBar';
import { colors } from '@/theme';
const TAB_TRANSITION_MS = 160;
export default function TabsLayout() {
return (
<Tabs
detachInactiveScreens
screenOptions={{
headerShown: false,
freezeOnBlur: true,
sceneStyle: { backgroundColor: colors.bgPrimary },
// Directional slide + cross-fade between tabs, following tab order.
animation: 'shift',
transitionSpec: {
animation: 'timing',
config: { duration: 200, easing: Easing.out(Easing.cubic) },
config: { duration: TAB_TRANSITION_MS, easing: Easing.out(Easing.cubic) },
},
}}
tabBar={({ state, navigation }) => {
+6 -3
View File
@@ -1,5 +1,5 @@
import { useCallback, useState } from 'react';
import { Pressable, StyleSheet, View, useWindowDimensions } from 'react-native';
import { InteractionManager, Pressable, StyleSheet, View, useWindowDimensions } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useFocusEffect } from 'expo-router';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -56,9 +56,12 @@ export default function EQScreen() {
// Gate the post-EQ tap to while this screen is visible.
useFocusEffect(
useCallback(() => {
setFocused(true);
setActivePostEqNative(true);
const task = InteractionManager.runAfterInteractions(() => {
setFocused(true);
setActivePostEqNative(true);
});
return () => {
task.cancel();
setFocused(false);
setActivePostEqNative(false);
};
+15 -12
View File
@@ -358,16 +358,7 @@ export default function HomeScreen() {
const [randomAlbumKey, setRandomAlbumKey] = useState<string | null>(null);
const [randomSeed] = useState(() => Math.random());
const scrollTop = useScrollTopGate();
const tracksByAlbum = useMemo(() => {
const map = new Map<string, DbTrack[]>();
for (const track of tracks) {
const list = map.get(track.album_identity_key) ?? [];
list.push(track);
map.set(track.album_identity_key, list);
}
return map;
}, [tracks]);
const hasLibrary = tracks.length > 0;
const recentlyAddedAlbums = useMemo(
() => [...albums].sort((a, b) => b.latest_added_at - a.latest_added_at).slice(0, RECENT_ALBUM_LIMIT),
@@ -394,10 +385,21 @@ export default function HomeScreen() {
if (selected) return selected;
return albums[Math.floor(randomSeed * albums.length) % albums.length];
}, [albums, randomAlbumKey, randomSeed]);
const randomTracks = randomAlbum ? (tracksByAlbum.get(randomAlbum.identity_key) ?? []) : [];
const randomAlbumNeedsTracks = hasLibrary && !currentTrack && randomAlbum != null;
const tracksByAlbum = useMemo(() => {
if (!randomAlbumNeedsTracks) return null;
const map = new Map<string, DbTrack[]>();
for (const track of tracks) {
const list = map.get(track.album_identity_key) ?? [];
list.push(track);
map.set(track.album_identity_key, list);
}
return map;
}, [randomAlbumNeedsTracks, tracks]);
const randomTracks =
randomAlbum && tracksByAlbum ? (tracksByAlbum.get(randomAlbum.identity_key) ?? []) : [];
const recentTracks = recentlyPlayedTracks.slice(0, RECENT_TRACK_LIMIT);
const canExpandRecentTracks = recentlyPlayedTracks.length > RECENT_TRACK_LIMIT;
const hasLibrary = tracks.length > 0;
const openAlbum = (album: Album) => {
router.push({
@@ -412,6 +414,7 @@ export default function HomeScreen() {
};
const playAlbum = (album: Album, shuffled = false) => {
if (!tracksByAlbum) return;
const albumTracks = tracksByAlbum.get(album.identity_key) ?? [];
if (albumTracks.length === 0) return;
if (shuffled) {
+4 -1
View File
@@ -52,7 +52,10 @@ export default function LibraryScreen() {
const isEmpty = tracks.length === 0 && folders.length === 0 && !isScanning;
const sortedTracks = useMemo(() => sortTracks(tracks, trackSort), [tracks, trackSort]);
const sortedTracks = useMemo(
() => (viewMode === 'tracks' ? sortTracks(tracks, trackSort) : []),
[trackSort, tracks, viewMode]
);
// Tap index is within sortedTracks so the tapped row is the track that plays.
const playAllFrom = (index: number) => {
+13 -2
View File
@@ -1,5 +1,13 @@
import { useEffect } from 'react';
import { Alert, View, Pressable, ScrollView, StyleSheet, Switch } from 'react-native';
import {
Alert,
InteractionManager,
View,
Pressable,
ScrollView,
StyleSheet,
Switch,
} from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useRouter } from 'expo-router';
import { Screen } from '@/components/Screen';
@@ -237,7 +245,10 @@ export default function SettingsScreen() {
const setReplayGainMode = useAudioSettingsStore((s) => s.setReplayGainMode);
useEffect(() => {
void initDesktopRemote();
const task = InteractionManager.runAfterInteractions(() => {
void initDesktopRemote();
});
return () => task.cancel();
}, [initDesktopRemote]);
const desktopRemoteSubtitle = desktopRemoteConnection