mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
refactor(lib,playback): fold utils/cache+themes into lib; playbackScheduleFormat→playback (drains utils/format)
This commit is contained in:
+1
-1
@@ -4,7 +4,7 @@ import { usePlayerStore } from '@/features/playback/store/playerStore';
|
||||
import { useLyricsStore } from './store/lyricsStore';
|
||||
import { useThemeStore } from './store/themeStore';
|
||||
import { useInstalledThemesStore } from './store/installedThemesStore';
|
||||
import { syncInjectedThemes } from './utils/themes/themeInjection';
|
||||
import { syncInjectedThemes } from '@/lib/themes/themeInjection';
|
||||
import { useThemeScheduler } from '@/app/hooks/useThemeScheduler';
|
||||
import { useFontStore } from './store/fontStore';
|
||||
import { getWindowKind } from './app/windowKind';
|
||||
|
||||
@@ -3,9 +3,9 @@ import { configureStartupSplash } from './startupSplash';
|
||||
import { setupMusicNetworkRuntime } from './musicNetworkBridge';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { getWindowKind } from './windowKind';
|
||||
import { migrateThemeSelection } from '../utils/themes/themeMigration';
|
||||
import { migrateThemeSelection } from '@/lib/themes/themeMigration';
|
||||
import { getScheduledTheme, useThemeStore } from '../store/themeStore';
|
||||
import { syncInjectedThemes } from '../utils/themes/themeInjection';
|
||||
import { syncInjectedThemes } from '@/lib/themes/themeInjection';
|
||||
import { useInstalledThemesStore, type InstalledTheme } from '../store/installedThemesStore';
|
||||
|
||||
/** Sync backend HTTP User-Agent from the main webview once at startup. */
|
||||
|
||||
@@ -9,7 +9,7 @@ vi.mock('./windowKind', () => ({
|
||||
getWindowKind: vi.fn(() => 'main'),
|
||||
}));
|
||||
|
||||
vi.mock('../utils/themes/startupThemeAppearance', () => ({
|
||||
vi.mock('@/lib/themes/startupThemeAppearance', () => ({
|
||||
applyStartupSplashThemeFromStorage: vi.fn(() => 'mocha'),
|
||||
}));
|
||||
|
||||
@@ -18,7 +18,7 @@ vi.mock('@tauri-apps/api/webviewWindow', () => ({
|
||||
}));
|
||||
|
||||
import { getWindowKind } from './windowKind';
|
||||
import { applyStartupSplashThemeFromStorage } from '../utils/themes/startupThemeAppearance';
|
||||
import { applyStartupSplashThemeFromStorage } from '@/lib/themes/startupThemeAppearance';
|
||||
|
||||
describe('startupSplash', () => {
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||
import { applyStartupSplashThemeFromStorage } from '../utils/themes/startupThemeAppearance';
|
||||
import { applyStartupSplashThemeFromStorage } from '@/lib/themes/startupThemeAppearance';
|
||||
import { getWindowKind } from './windowKind';
|
||||
|
||||
export const STARTUP_SPLASH_ID = 'app-startup-splash';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ConfirmModal from './ConfirmModal';
|
||||
import { readThemeMigrationNotice, clearThemeMigrationNotice } from '../utils/themes/themeMigration';
|
||||
import { readThemeMigrationNotice, clearThemeMigrationNotice } from '@/lib/themes/themeMigration';
|
||||
|
||||
/**
|
||||
* One-time, dismissible notice shown after the slim-bundle migration reset a
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { getArtistInfoForServer } from '@/lib/api/subsonicArtists';
|
||||
import type { SubsonicArtistInfo, SubsonicOpenArtistRef } from '@/lib/api/subsonicTypes';
|
||||
import { makeCache } from '@/utils/cache/nowPlayingCache';
|
||||
import { makeCache } from '@/lib/cache/nowPlayingCache';
|
||||
|
||||
const artistInfoCache = makeCache<SubsonicArtistInfo | null>();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Moon, Pause, Play, Sunrise } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { usePlayerStore } from '@/features/playback/store/playerStore';
|
||||
import { usePlaybackDelayPress } from '@/features/playback/hooks/usePlaybackDelayPress';
|
||||
import { usePlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
|
||||
import { usePlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
|
||||
import PlaybackDelayModal from '@/features/playback/components/PlaybackDelayModal';
|
||||
import PlaybackScheduleBadge from '@/features/playback/components/PlaybackScheduleBadge';
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import { LyricsPane } from '@/features/lyrics';
|
||||
import { usePlaybackDelayPress } from '@/features/playback/hooks/usePlaybackDelayPress';
|
||||
import PlaybackDelayModal from '@/features/playback/components/PlaybackDelayModal';
|
||||
import PlaybackScheduleBadge from '@/features/playback/components/PlaybackScheduleBadge';
|
||||
import { usePlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
|
||||
import { usePlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
|
||||
|
||||
// ── Color extraction ──────────────────────────────────────────────────────────
|
||||
// Samples a 16×16 canvas to find the most vibrant (highest-saturation,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { resolveNpAlbum, resolveNpDiscography, resolveNpSongMeta, resolveNpTopSo
|
||||
import { fetchBandsintownEvents, type BandsintownEvent } from '@/api/bandsintown';
|
||||
import type { ArtistStats, TrackStats } from '@/music-network';
|
||||
import { getMusicNetworkRuntimeOrNull } from '@/music-network';
|
||||
import { makeCache } from '@/utils/cache/nowPlayingCache';
|
||||
import { makeCache } from '@/lib/cache/nowPlayingCache';
|
||||
import { shouldAttemptSubsonicForServer } from '@/utils/network/subsonicNetworkGuard';
|
||||
import { useConnectionStatus } from '@/hooks/useConnectionStatus';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useAuthStore } from '@/store/authStore';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
import type { TFunction } from 'i18next';
|
||||
import { formatPlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
|
||||
import { formatPlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
|
||||
import { formatClockTime } from '@/lib/format/formatClockTime';
|
||||
import {
|
||||
isValidPlaybackSchedulePreviewTimestamp,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { createPortal } from 'react-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { usePlayerStore } from '@/features/playback/store/playerStore';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { formatPlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
|
||||
import { formatPlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
|
||||
import { useWindowVisibility } from '@/lib/hooks/useWindowVisibility';
|
||||
|
||||
export interface PlaybackScheduleBadgeProps {
|
||||
|
||||
@@ -19,7 +19,7 @@ import { useRadioMetadata } from '@/features/radio';
|
||||
import { useRadioMprisSync } from '@/features/radio';
|
||||
import { usePlaybackDelayPress } from '@/features/playback/hooks/usePlaybackDelayPress';
|
||||
import PlaybackDelayModal from '@/features/playback/components/PlaybackDelayModal';
|
||||
import { usePlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
|
||||
import { usePlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
|
||||
import { usePreviewStore } from '@/features/playback/store/previewStore';
|
||||
import { usePerfProbeFlags } from '@/utils/perf/perfFlags';
|
||||
import { coerceOpenArtistRefs } from '@/lib/api/openArtistRefs';
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useAutodjTransitionUi } from '@/features/playback/store/autodjTransitio
|
||||
import { usePreviewStore } from '@/features/playback/store/previewStore';
|
||||
import PlaybackScheduleBadge from '@/features/playback/components/PlaybackScheduleBadge';
|
||||
import { usePlaybackDelayPress } from '@/features/playback/hooks/usePlaybackDelayPress';
|
||||
import { usePlaybackScheduleRemaining } from '@/utils/format/playbackScheduleFormat';
|
||||
import { usePlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
|
||||
|
||||
type RepeatMode = PlayerState['repeatMode'];
|
||||
type PlayPauseBind = ReturnType<typeof usePlaybackDelayPress>['playPauseBind'];
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import { resolveQueueTrack } from '@/features/playback/store/queueTrackView';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { getMusicNetworkRuntimeOrNull } from '@/music-network';
|
||||
import { setDeferHotCachePrefetch } from '@/utils/cache/hotCacheGate';
|
||||
import { setDeferHotCachePrefetch } from '@/lib/cache/hotCacheGate';
|
||||
import { notifyLibraryPlaybackHint } from '@/features/playback/store/libraryPlaybackHint';
|
||||
import {
|
||||
playListenSessionFinalize,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Track } from '@/lib/media/trackTypes';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { setDeferHotCachePrefetch } from '@/utils/cache/hotCacheGate';
|
||||
import { setDeferHotCachePrefetch } from '@/lib/cache/hotCacheGate';
|
||||
import {
|
||||
getPlaybackIndexKey,
|
||||
playbackCacheKeyForTrack,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { playbackReportStart, playbackReportStopped } from '@/features/playback/store/playbackReportSession';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { getMusicNetworkRuntimeOrNull } from '@/music-network';
|
||||
import { setDeferHotCachePrefetch } from '@/utils/cache/hotCacheGate';
|
||||
import { setDeferHotCachePrefetch } from '@/lib/cache/hotCacheGate';
|
||||
import { orbitBulkGuard, orbitSnapshot } from '@/store/orbitRuntime';
|
||||
import { sameQueueTrackId } from '@/features/playback/utils/playback/queueIdentity';
|
||||
import {
|
||||
|
||||
@@ -38,7 +38,7 @@ const hoisted = vi.hoisted(() => {
|
||||
});
|
||||
|
||||
vi.mock('@tauri-apps/api/core', () => ({ invoke: hoisted.invokeMock }));
|
||||
vi.mock('@/utils/cache/hotCacheGate', () => ({ setDeferHotCachePrefetch: hoisted.setDeferHotCachePrefetchMock }));
|
||||
vi.mock('@/lib/cache/hotCacheGate', () => ({ setDeferHotCachePrefetch: hoisted.setDeferHotCachePrefetchMock }));
|
||||
vi.mock('@/features/playback/utils/playback/resolvePlaybackUrl', () => ({ resolvePlaybackUrl: hoisted.resolvePlaybackUrlMock }));
|
||||
vi.mock('@/features/playback/utils/audio/resolveReplayGainDb', () => ({ resolveReplayGainDb: hoisted.resolveReplayGainDbMock }));
|
||||
vi.mock('@/store/authStore', () => ({ useAuthStore: { getState: () => hoisted.auth } }));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { getSong } from '@/lib/api/subsonicLibrary';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { estimateLivePosition, orbitSnapshot } from '@/store/orbitRuntime';
|
||||
import { setDeferHotCachePrefetch } from '@/utils/cache/hotCacheGate';
|
||||
import { setDeferHotCachePrefetch } from '@/lib/cache/hotCacheGate';
|
||||
import {
|
||||
getPlaybackCacheServerKey,
|
||||
getPlaybackIndexKey,
|
||||
|
||||
@@ -3,13 +3,13 @@ import { Check, RefreshCw, X } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useThemeStore } from '@/store/themeStore';
|
||||
import { useInstalledThemesStore } from '@/store/installedThemesStore';
|
||||
import { uninstallTheme } from '@/utils/themes/uninstallTheme';
|
||||
import { installThemeFromRegistry } from '@/utils/themes/installThemeFromRegistry';
|
||||
import { uninstallTheme } from '@/lib/themes/uninstallTheme';
|
||||
import { installThemeFromRegistry } from '@/lib/themes/installThemeFromRegistry';
|
||||
import { useThemeUpdates } from '@/features/settings/hooks/useThemeUpdates';
|
||||
import { useThemeAnimationRisk } from '@/features/settings/hooks/useThemeAnimationRisk';
|
||||
import { showToast } from '@/utils/ui/toast';
|
||||
import { AnimatedThemeBadge } from '@/features/settings/components/AnimatedThemeBadge';
|
||||
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
|
||||
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
|
||||
|
||||
/** Pull a 3-band swatch (bg / card / accent) out of an installed theme's CSS. */
|
||||
function swatch(css: string): { bg: string; card: string; accent: string } {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import { useInstalledThemesStore } from '@/store/installedThemesStore';
|
||||
import { validateThemePackage, type ValidatedTheme } from '@/utils/themes/validateThemePackage';
|
||||
import { validateThemePackage, type ValidatedTheme } from '@/lib/themes/validateThemePackage';
|
||||
import { showToast } from '@/utils/ui/toast';
|
||||
import ConfirmModal from '@/components/ConfirmModal';
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@ import { screen, waitFor, fireEvent } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { renderWithProviders } from '@/test/helpers/renderWithProviders';
|
||||
import { ThemeStoreSection } from '@/features/settings/components/ThemeStoreSection';
|
||||
import type { FetchRegistryResult, Registry, RegistryTheme } from '@/utils/themes/themeRegistry';
|
||||
import type { FetchRegistryResult, Registry, RegistryTheme } from '@/lib/themes/themeRegistry';
|
||||
|
||||
// Control the registry the store browses so pagination/refresh are deterministic.
|
||||
vi.mock('@/utils/themes/themeRegistry', () => ({
|
||||
vi.mock('@/lib/themes/themeRegistry', () => ({
|
||||
fetchRegistry: vi.fn(),
|
||||
fetchThemeCss: vi.fn(async () => 'css'),
|
||||
assetUrl: (p: string) => `https://raw.example/${p}`,
|
||||
}));
|
||||
|
||||
import { fetchRegistry } from '@/utils/themes/themeRegistry';
|
||||
import { fetchRegistry } from '@/lib/themes/themeRegistry';
|
||||
|
||||
const fetchRegistryMock = vi.mocked(fetchRegistry);
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ import {
|
||||
assetUrl,
|
||||
fetchRegistry,
|
||||
type RegistryTheme,
|
||||
} from '@/utils/themes/themeRegistry';
|
||||
import { installThemeFromRegistry } from '@/utils/themes/installThemeFromRegistry';
|
||||
import { uninstallTheme } from '@/utils/themes/uninstallTheme';
|
||||
} from '@/lib/themes/themeRegistry';
|
||||
import { installThemeFromRegistry } from '@/lib/themes/installThemeFromRegistry';
|
||||
import { uninstallTheme } from '@/lib/themes/uninstallTheme';
|
||||
import { isNewer } from '@/utils/componentHelpers/appUpdaterHelpers';
|
||||
|
||||
type ModeFilter = 'all' | 'dark' | 'light';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useThemeStore } from '@/store/themeStore';
|
||||
import { useInstalledThemesStore } from '@/store/installedThemesStore';
|
||||
import CustomSelect from '@/ui/CustomSelect';
|
||||
import BackToTopButton from '@/ui/BackToTopButton';
|
||||
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
|
||||
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
|
||||
import { InstalledThemes } from '@/features/settings/components/InstalledThemes';
|
||||
import { ThemeImportSection } from '@/features/settings/components/ThemeImportSection';
|
||||
import { ThemeStoreSection } from '@/features/settings/components/ThemeStoreSection';
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
|
||||
vi.mock('@/utils/themes/themeRegistry', () => ({
|
||||
vi.mock('@/lib/themes/themeRegistry', () => ({
|
||||
fetchRegistry: vi.fn(),
|
||||
getCachedRegistry: vi.fn(() => null),
|
||||
}));
|
||||
|
||||
import { fetchRegistry, type Registry } from '@/utils/themes/themeRegistry';
|
||||
import { fetchRegistry, type Registry } from '@/lib/themes/themeRegistry';
|
||||
import { useInstalledThemesStore, type InstalledTheme } from '@/store/installedThemesStore';
|
||||
import { useThemeUpdates, themeUpdateSignature } from '@/features/settings/hooks/useThemeUpdates';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { isNewer } from '@/utils/componentHelpers/appUpdaterHelpers';
|
||||
import { fetchRegistry, getCachedRegistry, type Registry, type RegistryTheme } from '@/utils/themes/themeRegistry';
|
||||
import { fetchRegistry, getCachedRegistry, type Registry, type RegistryTheme } from '@/lib/themes/themeRegistry';
|
||||
import { useInstalledThemesStore } from '@/store/installedThemesStore';
|
||||
|
||||
// Refresh the registry from source once per app launch (not just from the
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
bumpHotCachePreviousTrackGrace,
|
||||
clearHotCachePreviousGrace,
|
||||
getDeferHotCachePrefetch,
|
||||
} from './utils/cache/hotCacheGate';
|
||||
} from '@/lib/cache/hotCacheGate';
|
||||
import {
|
||||
PREFETCH_AHEAD,
|
||||
type PrefetchJob,
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
scheduleAnalysisQueuePruneFromPlaybackQueue,
|
||||
resetAnalysisPruneState,
|
||||
} from './hotCachePrefetch/analysisPrune';
|
||||
import { reconcileEphemeralCache } from './utils/cache/ephemeralTierReconcile';
|
||||
import { reconcileEphemeralCache } from '@/lib/cache/ephemeralTierReconcile';
|
||||
import { hasLocalPersistentPlaybackBytes } from '@/store/localPlaybackResolve';
|
||||
|
||||
/** Periodic index↔disk sync (stale rows + empty dirs); unindexed files evicted only on budget pressure. */
|
||||
|
||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { reconcileEphemeralCache } from './ephemeralTierReconcile';
|
||||
import { useLocalPlaybackStore } from '../../store/localPlaybackStore';
|
||||
import { reconcileEphemeralCache } from '@/lib/cache/ephemeralTierReconcile';
|
||||
import { useLocalPlaybackStore } from '@/store/localPlaybackStore';
|
||||
|
||||
vi.mock('@tauri-apps/api/core', () => ({
|
||||
invoke: vi.fn(),
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { useLocalPlaybackStore } from '../../store/localPlaybackStore';
|
||||
import { parseLocalPlaybackEntryKey } from '../../store/localPlaybackKeys';
|
||||
import { useLocalPlaybackStore } from '@/store/localPlaybackStore';
|
||||
import { parseLocalPlaybackEntryKey } from '@/store/localPlaybackKeys';
|
||||
import { getMediaDir } from '@/lib/media/mediaDir';
|
||||
|
||||
export interface EphemeralReconcileResult {
|
||||
+6
-6
@@ -1,12 +1,12 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
vi.mock('./themeRegistry', () => ({ fetchThemeCss: vi.fn() }));
|
||||
vi.mock('./themeInjection', () => ({ validateThemeCss: vi.fn() }));
|
||||
vi.mock('@/lib/themes/themeRegistry', () => ({ fetchThemeCss: vi.fn() }));
|
||||
vi.mock('@/lib/themes/themeInjection', () => ({ validateThemeCss: vi.fn() }));
|
||||
|
||||
import { fetchThemeCss, type RegistryTheme } from './themeRegistry';
|
||||
import { validateThemeCss } from './themeInjection';
|
||||
import { useInstalledThemesStore } from '../../store/installedThemesStore';
|
||||
import { installThemeFromRegistry } from './installThemeFromRegistry';
|
||||
import { fetchThemeCss, type RegistryTheme } from '@/lib/themes/themeRegistry';
|
||||
import { validateThemeCss } from '@/lib/themes/themeInjection';
|
||||
import { useInstalledThemesStore } from '@/store/installedThemesStore';
|
||||
import { installThemeFromRegistry } from '@/lib/themes/installThemeFromRegistry';
|
||||
|
||||
const fetchCss = vi.mocked(fetchThemeCss);
|
||||
const validate = vi.mocked(validateThemeCss);
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
import { fetchThemeCss, type RegistryTheme } from './themeRegistry';
|
||||
import { validateThemeCss } from './themeInjection';
|
||||
import { useInstalledThemesStore } from '../../store/installedThemesStore';
|
||||
import { fetchThemeCss, type RegistryTheme } from '@/lib/themes/themeRegistry';
|
||||
import { validateThemeCss } from '@/lib/themes/themeInjection';
|
||||
import { useInstalledThemesStore } from '@/store/installedThemesStore';
|
||||
|
||||
export type InstallResult = 'ok' | 'invalid' | 'error';
|
||||
|
||||
+2
-2
@@ -1,13 +1,13 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
import { BUILTIN_SPLASH_PALETTES } from '../../config/startupSplashPalettes';
|
||||
import { BUILTIN_SPLASH_PALETTES } from '@/config/startupSplashPalettes';
|
||||
import {
|
||||
applyStartupSplashPalette,
|
||||
resolveEffectiveThemeId,
|
||||
resolveScheduledThemeId,
|
||||
resolveSplashPalette,
|
||||
} from './startupThemeAppearance';
|
||||
} from '@/lib/themes/startupThemeAppearance';
|
||||
|
||||
describe('startupThemeAppearance', () => {
|
||||
beforeEach(() => {
|
||||
+1
-1
@@ -2,7 +2,7 @@ import {
|
||||
BUILTIN_SPLASH_PALETTES,
|
||||
BUILTIN_THEME_IDS,
|
||||
type StartupSplashPalette,
|
||||
} from '../../config/startupSplashPalettes';
|
||||
} from '@/config/startupSplashPalettes';
|
||||
|
||||
export type PersistedThemeState = {
|
||||
enableThemeScheduler: boolean;
|
||||
@@ -8,8 +8,8 @@ import {
|
||||
validateThemeCss,
|
||||
injectTheme,
|
||||
syncInjectedThemes,
|
||||
} from './themeInjection';
|
||||
import type { InstalledTheme } from '../../store/installedThemesStore';
|
||||
} from '@/lib/themes/themeInjection';
|
||||
import type { InstalledTheme } from '@/store/installedThemesStore';
|
||||
|
||||
const ATTR = 'data-installed-theme';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { InstalledTheme } from '../../store/installedThemesStore';
|
||||
import type { InstalledTheme } from '@/store/installedThemesStore';
|
||||
|
||||
/**
|
||||
* Runtime CSS injection for installed community themes. Built-in themes are
|
||||
@@ -12,8 +12,8 @@ import {
|
||||
migrateThemeSelection,
|
||||
readThemeMigrationNotice,
|
||||
clearThemeMigrationNotice,
|
||||
} from './themeMigration';
|
||||
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
|
||||
} from '@/lib/themes/themeMigration';
|
||||
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
|
||||
|
||||
const THEME_KEY = 'psysonic_theme';
|
||||
const INSTALLED_KEY = 'psysonic_installed_themes';
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
|
||||
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
|
||||
|
||||
/**
|
||||
* Slim-bundle theme migration (C5). Older builds bundled ~80 palettes that now
|
||||
@@ -3,7 +3,7 @@
|
||||
* stale-on-error fallback, and malformed-cache tolerance.
|
||||
*/
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { fetchRegistry, getCachedRegistry } from './themeRegistry';
|
||||
import { fetchRegistry, getCachedRegistry } from '@/lib/themes/themeRegistry';
|
||||
|
||||
const CACHE_KEY = 'psysonic_theme_registry_cache';
|
||||
const NOW = 1_000_000_000;
|
||||
@@ -3,9 +3,9 @@
|
||||
* selection slot that referenced it (active + scheduler day/night).
|
||||
*/
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { uninstallTheme } from './uninstallTheme';
|
||||
import { useInstalledThemesStore, type InstalledTheme } from '../../store/installedThemesStore';
|
||||
import { useThemeStore } from '../../store/themeStore';
|
||||
import { uninstallTheme } from '@/lib/themes/uninstallTheme';
|
||||
import { useInstalledThemesStore, type InstalledTheme } from '@/store/installedThemesStore';
|
||||
import { useThemeStore } from '@/store/themeStore';
|
||||
|
||||
function mk(id: string, mode: 'dark' | 'light' = 'dark'): InstalledTheme {
|
||||
return { id, name: id, author: 'a', version: '1.0.0', description: '', mode, css: `[data-theme='${id}']{--accent:#fff;}`, installedAt: 0 };
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useInstalledThemesStore } from '../../store/installedThemesStore';
|
||||
import { useThemeStore } from '../../store/themeStore';
|
||||
import { useInstalledThemesStore } from '@/store/installedThemesStore';
|
||||
import { useThemeStore } from '@/store/themeStore';
|
||||
|
||||
/**
|
||||
* Uninstall a community theme and repair any theme selection that pointed at it.
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { validateThemePackage } from './validateThemePackage';
|
||||
import { validateThemePackage } from '@/lib/themes/validateThemePackage';
|
||||
|
||||
/** A minimal floor-passing theme.css for `id`. */
|
||||
function css(id = 'my-theme'): string {
|
||||
@@ -1,5 +1,5 @@
|
||||
import { validateThemeCss } from './themeInjection';
|
||||
import { FIXED_THEMES } from '@/utils/themes/fixedThemes';
|
||||
import { validateThemeCss } from '@/lib/themes/themeInjection';
|
||||
import { FIXED_THEMES } from '@/lib/themes/fixedThemes';
|
||||
|
||||
/**
|
||||
* Validation for a locally imported theme package (a .zip holding manifest.json
|
||||
@@ -2,7 +2,7 @@ import type { QueueItemRef } from '@/lib/media/trackTypes';
|
||||
import { create } from 'zustand';
|
||||
import { persist, createJSONStorage } from 'zustand/middleware';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { isHotCachePreviousTrackUnderGrace } from '../utils/cache/hotCacheGate';
|
||||
import { isHotCachePreviousTrackUnderGrace } from '@/lib/cache/hotCacheGate';
|
||||
import { emitAnalysisStorageChanged } from './analysisSync';
|
||||
import { useAuthStore } from './authStore';
|
||||
import { localPlaybackEntryKey, parseLocalPlaybackEntryKey } from './localPlaybackKeys';
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
evictEphemeralOrphansToFit,
|
||||
getEphemeralDiskBytes,
|
||||
reconcileEphemeralCache,
|
||||
} from '../utils/cache/ephemeralTierReconcile';
|
||||
} from '@/lib/cache/ephemeralTierReconcile';
|
||||
|
||||
export type LocalPlaybackTier = 'ephemeral' | 'library' | 'favorite-auto';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user