mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
feat(linux): add WebKitGTK smooth wheel scroll toggle in settings
Persist preference in auth store, sync from App on Linux, and expose a Tauri command using webkit2gtk to toggle enable-smooth-scrolling at runtime. Default on to match upstream; users may disable for discrete GTK-style line steps. Apply a one-time rehydrate migration so smooth scrolling stays on after updates even if an older build persisted the wrong default.
This commit is contained in:
Generated
+1
@@ -3612,6 +3612,7 @@ dependencies = [
|
|||||||
"thread-priority",
|
"thread-priority",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
|
"webkit2gtk",
|
||||||
"windows 0.58.0",
|
"windows 0.58.0",
|
||||||
"zbus 5.14.0",
|
"zbus 5.14.0",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ libc = "0.2"
|
|||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
zbus = { version = "5.9", default-features = false, features = ["blocking-api"] }
|
zbus = { version = "5.9", default-features = false, features = ["blocking-api"] }
|
||||||
|
# Match wry/tauri’s WebKitGTK stack — used only to turn off kinetic wheel scrolling.
|
||||||
|
webkit2gtk = { version = "2.0", default-features = false, features = ["v2_40"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
windows = { version = "0.58", features = [
|
windows = { version = "0.58", features = [
|
||||||
|
|||||||
@@ -90,6 +90,35 @@ fn set_window_decorations(enabled: bool, app_handle: tauri::AppHandle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// WebKitGTK: `enable-smooth-scrolling` also drives deferred / kinetic wheel scrolling.
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn linux_webkit_apply_smooth_scrolling(win: &tauri::WebviewWindow, enabled: bool) -> Result<(), String> {
|
||||||
|
win.with_webview(move |platform| {
|
||||||
|
use webkit2gtk::{SettingsExt, WebViewExt};
|
||||||
|
if let Some(settings) = platform.inner().settings() {
|
||||||
|
settings.set_enable_smooth_scrolling(enabled);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called from the frontend settings toggle (Linux); no-op on other platforms.
|
||||||
|
#[tauri::command]
|
||||||
|
fn set_linux_webkit_smooth_scrolling(enabled: bool, app_handle: tauri::AppHandle) -> Result<(), String> {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
use tauri::Manager;
|
||||||
|
if let Some(win) = app_handle.get_webview_window("main") {
|
||||||
|
linux_webkit_apply_smooth_scrolling(&win, enabled)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
{
|
||||||
|
let _ = (enabled, app_handle);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Authenticate with Navidrome's own REST API and return a Bearer token.
|
/// Authenticate with Navidrome's own REST API and return a Bearer token.
|
||||||
async fn navidrome_token(server_url: &str, username: &str, password: &str) -> Result<String, String> {
|
async fn navidrome_token(server_url: &str, username: &str, password: &str) -> Result<String, String> {
|
||||||
@@ -2578,6 +2607,7 @@ pub fn run() {
|
|||||||
cli_publish_server_list,
|
cli_publish_server_list,
|
||||||
cli_publish_search_results,
|
cli_publish_search_results,
|
||||||
set_window_decorations,
|
set_window_decorations,
|
||||||
|
set_linux_webkit_smooth_scrolling,
|
||||||
no_compositing_mode,
|
no_compositing_mode,
|
||||||
is_tiling_wm_cmd,
|
is_tiling_wm_cmd,
|
||||||
register_global_shortcut,
|
register_global_shortcut,
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ function AppShell() {
|
|||||||
const activeServerId = useAuthStore(s => s.activeServerId);
|
const activeServerId = useAuthStore(s => s.activeServerId);
|
||||||
const setMusicFolders = useAuthStore(s => s.setMusicFolders);
|
const setMusicFolders = useAuthStore(s => s.setMusicFolders);
|
||||||
const useCustomTitlebar = useAuthStore(s => s.useCustomTitlebar);
|
const useCustomTitlebar = useAuthStore(s => s.useCustomTitlebar);
|
||||||
|
const linuxWebkitKineticScroll = useAuthStore(s => s.linuxWebkitKineticScroll);
|
||||||
const setEntityRatingSupport = useAuthStore(s => s.setEntityRatingSupport);
|
const setEntityRatingSupport = useAuthStore(s => s.setEntityRatingSupport);
|
||||||
const offlineAlbums = useOfflineStore(s => s.albums);
|
const offlineAlbums = useOfflineStore(s => s.albums);
|
||||||
const hasOfflineContent = Object.values(offlineAlbums).some(a => a.serverId === serverId);
|
const hasOfflineContent = Object.values(offlineAlbums).some(a => a.serverId === serverId);
|
||||||
@@ -151,6 +152,11 @@ function AppShell() {
|
|||||||
invoke('set_window_decorations', { enabled }).catch(() => {});
|
invoke('set_window_decorations', { enabled }).catch(() => {});
|
||||||
}, [useCustomTitlebar, isTilingWm]);
|
}, [useCustomTitlebar, isTilingWm]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!IS_LINUX) return;
|
||||||
|
invoke('set_linux_webkit_smooth_scrolling', { enabled: linuxWebkitKineticScroll }).catch(() => {});
|
||||||
|
}, [linuxWebkitKineticScroll]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isLoggedIn || !activeServerId) return;
|
if (!isLoggedIn || !activeServerId) return;
|
||||||
const serverAtStart = activeServerId;
|
const serverAtStart = activeServerId;
|
||||||
|
|||||||
@@ -538,6 +538,8 @@ export const deTranslation = {
|
|||||||
discordRichPresenceDesc: 'Zeigt den aktuell gespielten Titel im Discord-Profil an. Discord muss dafür geöffnet sein.',
|
discordRichPresenceDesc: 'Zeigt den aktuell gespielten Titel im Discord-Profil an. Discord muss dafür geöffnet sein.',
|
||||||
useCustomTitlebar: 'Eigene Titelleiste',
|
useCustomTitlebar: 'Eigene Titelleiste',
|
||||||
useCustomTitlebarDesc: 'Ersetzt die System-Titelleiste durch eine eingebaute, die zum App-Theme passt. Deaktivieren, um die native GNOME/GTK-Titelleiste zu verwenden.',
|
useCustomTitlebarDesc: 'Ersetzt die System-Titelleiste durch eine eingebaute, die zum App-Theme passt. Deaktivieren, um die native GNOME/GTK-Titelleiste zu verwenden.',
|
||||||
|
linuxWebkitSmoothScroll: 'Sanftes Mausrad (Linux)',
|
||||||
|
linuxWebkitSmoothScrollDesc: 'An: mit Nachlauf. Aus: zeilenweise wie in GTK-Apps.',
|
||||||
discordAppleCovers: 'Cover über Apple Music für Discord laden',
|
discordAppleCovers: 'Cover über Apple Music für Discord laden',
|
||||||
discordAppleCoversDesc: 'Sendet Künstler- und Albumname an die Apple-Such-API, um Cover für dein Discord-Profil zu finden. Standardmäßig aus Datenschutzgründen deaktiviert.',
|
discordAppleCoversDesc: 'Sendet Künstler- und Albumname an die Apple-Such-API, um Cover für dein Discord-Profil zu finden. Standardmäßig aus Datenschutzgründen deaktiviert.',
|
||||||
discordOptions: 'Erweiterte Discord-Optionen',
|
discordOptions: 'Erweiterte Discord-Optionen',
|
||||||
|
|||||||
@@ -540,6 +540,8 @@ export const enTranslation = {
|
|||||||
discordRichPresenceDesc: 'Show the currently playing track on your Discord profile. Requires Discord to be running.',
|
discordRichPresenceDesc: 'Show the currently playing track on your Discord profile. Requires Discord to be running.',
|
||||||
useCustomTitlebar: 'Custom title bar',
|
useCustomTitlebar: 'Custom title bar',
|
||||||
useCustomTitlebarDesc: 'Replace the system title bar with a built-in one that matches the app theme. Disable to use the native GNOME/GTK title bar.',
|
useCustomTitlebarDesc: 'Replace the system title bar with a built-in one that matches the app theme. Disable to use the native GNOME/GTK title bar.',
|
||||||
|
linuxWebkitSmoothScroll: 'Smooth wheel (Linux)',
|
||||||
|
linuxWebkitSmoothScrollDesc: 'On: inertial scroll. Off: line-by-line, GTK-style.',
|
||||||
discordAppleCovers: 'Fetch covers from Apple Music for Discord',
|
discordAppleCovers: 'Fetch covers from Apple Music for Discord',
|
||||||
discordAppleCoversDesc: 'Sends the artist and album name to Apple\'s search API to find cover art for your Discord profile. Disabled by default for privacy.',
|
discordAppleCoversDesc: 'Sends the artist and album name to Apple\'s search API to find cover art for your Discord profile. Disabled by default for privacy.',
|
||||||
discordOptions: 'Advanced Discord options',
|
discordOptions: 'Advanced Discord options',
|
||||||
|
|||||||
@@ -541,6 +541,8 @@ export const esTranslation = {
|
|||||||
discordRichPresenceDesc: 'Muestra la pista actual en tu perfil de Discord. Requiere que Discord esté ejecutándose.',
|
discordRichPresenceDesc: 'Muestra la pista actual en tu perfil de Discord. Requiere que Discord esté ejecutándose.',
|
||||||
useCustomTitlebar: 'Barra de título personalizada',
|
useCustomTitlebar: 'Barra de título personalizada',
|
||||||
useCustomTitlebarDesc: 'Reemplaza la barra de título del sistema con una integrada que coincide con el tema de la app. Desactiva para usar la barra nativa de GNOME/GTK.',
|
useCustomTitlebarDesc: 'Reemplaza la barra de título del sistema con una integrada que coincide con el tema de la app. Desactiva para usar la barra nativa de GNOME/GTK.',
|
||||||
|
linuxWebkitSmoothScroll: 'Rueda suave (Linux)',
|
||||||
|
linuxWebkitSmoothScrollDesc: 'Activado: inercia. Desactivado: pasos por línea (estilo GTK).',
|
||||||
discordAppleCovers: 'Obtener portadas de Apple Music para Discord',
|
discordAppleCovers: 'Obtener portadas de Apple Music para Discord',
|
||||||
discordAppleCoversDesc: 'Envía el artista y nombre del álbum a la API de búsqueda de Apple para encontrar portadas para tu perfil de Discord. Desactivado por defecto por privacidad.',
|
discordAppleCoversDesc: 'Envía el artista y nombre del álbum a la API de búsqueda de Apple para encontrar portadas para tu perfil de Discord. Desactivado por defecto por privacidad.',
|
||||||
discordOptions: 'Opciones avanzadas de Discord',
|
discordOptions: 'Opciones avanzadas de Discord',
|
||||||
|
|||||||
@@ -534,6 +534,8 @@ export const frTranslation = {
|
|||||||
showTrayIconDesc: 'Affiche l\'icône Psysonic dans la zone de notification / barre des menus.',
|
showTrayIconDesc: 'Affiche l\'icône Psysonic dans la zone de notification / barre des menus.',
|
||||||
minimizeToTray: 'Réduire dans la barre système',
|
minimizeToTray: 'Réduire dans la barre système',
|
||||||
minimizeToTrayDesc: 'Lors de la fermeture, Psysonic continue de fonctionner dans la barre système au lieu de se fermer.',
|
minimizeToTrayDesc: 'Lors de la fermeture, Psysonic continue de fonctionner dans la barre système au lieu de se fermer.',
|
||||||
|
linuxWebkitSmoothScroll: 'Molette fluide (Linux)',
|
||||||
|
linuxWebkitSmoothScrollDesc: 'Activé : inertie. Désactivé : pas à la ligne, style GTK.',
|
||||||
discordRichPresence: 'Discord Rich Presence',
|
discordRichPresence: 'Discord Rich Presence',
|
||||||
discordRichPresenceDesc: 'Affiche le titre en cours de lecture sur votre profil Discord. Discord doit être ouvert.',
|
discordRichPresenceDesc: 'Affiche le titre en cours de lecture sur votre profil Discord. Discord doit être ouvert.',
|
||||||
discordAppleCovers: 'Récupérer les pochettes via Apple Music pour Discord',
|
discordAppleCovers: 'Récupérer les pochettes via Apple Music pour Discord',
|
||||||
|
|||||||
@@ -533,6 +533,8 @@ export const nbTranslation = {
|
|||||||
showArtistImagesDesc: 'Last inn og vis artistbilder i artistoversikten. Denne er deaktivert som standard, for å redusere disk-I/O og nettverksbelastningen på store biblioteker.',
|
showArtistImagesDesc: 'Last inn og vis artistbilder i artistoversikten. Denne er deaktivert som standard, for å redusere disk-I/O og nettverksbelastningen på store biblioteker.',
|
||||||
minimizeToTray: 'Minimer til oppgavelinjen',
|
minimizeToTray: 'Minimer til oppgavelinjen',
|
||||||
minimizeToTrayDesc: 'Når vinduet lukkes, vil Psysonic bli kjørende i oppgavelinjen fremfor å bli avsluttet.',
|
minimizeToTrayDesc: 'Når vinduet lukkes, vil Psysonic bli kjørende i oppgavelinjen fremfor å bli avsluttet.',
|
||||||
|
linuxWebkitSmoothScroll: 'Mykt musehjul (Linux)',
|
||||||
|
linuxWebkitSmoothScrollDesc: 'På: treg rull med etterslep. Av: trinnvis som i GTK.',
|
||||||
discordRichPresence: 'Discord Rich Presence',
|
discordRichPresence: 'Discord Rich Presence',
|
||||||
discordRichPresenceDesc: 'Vis sporet som spilles i din Discord-profil. Krever at Discord kjører.',
|
discordRichPresenceDesc: 'Vis sporet som spilles i din Discord-profil. Krever at Discord kjører.',
|
||||||
discordAppleCovers: 'Hent covere fra Apple Music til Discord',
|
discordAppleCovers: 'Hent covere fra Apple Music til Discord',
|
||||||
|
|||||||
@@ -533,6 +533,8 @@ export const nlTranslation = {
|
|||||||
showTrayIconDesc: 'Toont het Psysonic-pictogram in het systeemvak / de menubalk.',
|
showTrayIconDesc: 'Toont het Psysonic-pictogram in het systeemvak / de menubalk.',
|
||||||
minimizeToTray: 'Minimaliseren naar systeemvak',
|
minimizeToTray: 'Minimaliseren naar systeemvak',
|
||||||
minimizeToTrayDesc: 'Bij het sluiten van het venster blijft Psysonic actief in het systeemvak in plaats van af te sluiten.',
|
minimizeToTrayDesc: 'Bij het sluiten van het venster blijft Psysonic actief in het systeemvak in plaats van af te sluiten.',
|
||||||
|
linuxWebkitSmoothScroll: 'Vloeiend muiswiel (Linux)',
|
||||||
|
linuxWebkitSmoothScrollDesc: 'Aan: traag naloop. Uit: regel voor regel, GTK-stijl.',
|
||||||
discordRichPresence: 'Discord Rich Presence',
|
discordRichPresence: 'Discord Rich Presence',
|
||||||
discordRichPresenceDesc: 'Toont het huidige nummer op je Discord-profiel. Discord moet daarvoor geopend zijn.',
|
discordRichPresenceDesc: 'Toont het huidige nummer op je Discord-profiel. Discord moet daarvoor geopend zijn.',
|
||||||
discordAppleCovers: 'Hoezen ophalen via Apple Music voor Discord',
|
discordAppleCovers: 'Hoezen ophalen via Apple Music voor Discord',
|
||||||
|
|||||||
@@ -555,6 +555,8 @@ export const ruTranslation = {
|
|||||||
useCustomTitlebar: 'Своя строка заголовка',
|
useCustomTitlebar: 'Своя строка заголовка',
|
||||||
useCustomTitlebarDesc:
|
useCustomTitlebarDesc:
|
||||||
'Заменить системную строку заголовка встроенной, в стиле темы приложения. Отключите, чтобы использовать родную строку GNOME/GTK и т.д.',
|
'Заменить системную строку заголовка встроенной, в стиле темы приложения. Отключите, чтобы использовать родную строку GNOME/GTK и т.д.',
|
||||||
|
linuxWebkitSmoothScroll: 'Плавное колесо (Linux)',
|
||||||
|
linuxWebkitSmoothScrollDesc: 'Вкл — инерция. Выкл — по шагам, как в GTK.',
|
||||||
discordRichPresence: 'Статус в Discord',
|
discordRichPresence: 'Статус в Discord',
|
||||||
discordRichPresenceDesc:
|
discordRichPresenceDesc:
|
||||||
'Показывать текущий трек в профиле и статусе Discord. Нужен запущенный клиент Discord.',
|
'Показывать текущий трек в профиле и статусе Discord. Нужен запущенный клиент Discord.',
|
||||||
|
|||||||
@@ -529,6 +529,8 @@ export const zhTranslation = {
|
|||||||
showTrayIconDesc: '在系统通知区域 / 菜单栏显示 Psysonic 图标。',
|
showTrayIconDesc: '在系统通知区域 / 菜单栏显示 Psysonic 图标。',
|
||||||
minimizeToTray: '最小化到托盘',
|
minimizeToTray: '最小化到托盘',
|
||||||
minimizeToTrayDesc: '关闭窗口时,Psysonic 将继续在系统托盘中运行,而不是退出。',
|
minimizeToTrayDesc: '关闭窗口时,Psysonic 将继续在系统托盘中运行,而不是退出。',
|
||||||
|
linuxWebkitSmoothScroll: '滚轮平滑(Linux)',
|
||||||
|
linuxWebkitSmoothScrollDesc: '开:惯性滚动。关:逐行,类似 GTK。',
|
||||||
discordRichPresence: 'Discord Rich Presence',
|
discordRichPresence: 'Discord Rich Presence',
|
||||||
discordRichPresenceDesc: '在 Discord 个人资料上显示当前播放的曲目。需要 Discord 处于运行状态。',
|
discordRichPresenceDesc: '在 Discord 个人资料上显示当前播放的曲目。需要 Discord 处于运行状态。',
|
||||||
discordAppleCovers: '通过 Apple Music 为 Discord 获取封面',
|
discordAppleCovers: '通过 Apple Music 为 Discord 获取封面',
|
||||||
|
|||||||
@@ -1136,6 +1136,25 @@ export default function Settings() {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{IS_LINUX && (
|
||||||
|
<>
|
||||||
|
<div className="settings-section-divider" />
|
||||||
|
<div className="settings-toggle-row">
|
||||||
|
<div>
|
||||||
|
<div style={{ fontWeight: 500 }}>{t('settings.linuxWebkitSmoothScroll')}</div>
|
||||||
|
<div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{t('settings.linuxWebkitSmoothScrollDesc')}</div>
|
||||||
|
</div>
|
||||||
|
<label className="toggle-switch" aria-label={t('settings.linuxWebkitSmoothScroll')}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={auth.linuxWebkitKineticScroll}
|
||||||
|
onChange={e => auth.setLinuxWebkitKineticScroll(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span className="toggle-track" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="settings-section-divider" />
|
<div className="settings-section-divider" />
|
||||||
<div className="settings-toggle-row">
|
<div className="settings-toggle-row">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ interface AuthState {
|
|||||||
discordTemplateState: string;
|
discordTemplateState: string;
|
||||||
discordTemplateLargeText: string;
|
discordTemplateLargeText: string;
|
||||||
useCustomTitlebar: boolean;
|
useCustomTitlebar: boolean;
|
||||||
|
/** Linux WebKitGTK: smooth wheel on when true; off only after explicit opt-out in Settings. */
|
||||||
|
linuxWebkitKineticScroll: boolean;
|
||||||
nowPlayingEnabled: boolean;
|
nowPlayingEnabled: boolean;
|
||||||
lyricsServerFirst: boolean;
|
lyricsServerFirst: boolean;
|
||||||
enableNeteaselyrics: boolean;
|
enableNeteaselyrics: boolean;
|
||||||
@@ -209,6 +211,7 @@ interface AuthState {
|
|||||||
setDiscordTemplateState: (v: string) => void;
|
setDiscordTemplateState: (v: string) => void;
|
||||||
setDiscordTemplateLargeText: (v: string) => void;
|
setDiscordTemplateLargeText: (v: string) => void;
|
||||||
setUseCustomTitlebar: (v: boolean) => void;
|
setUseCustomTitlebar: (v: boolean) => void;
|
||||||
|
setLinuxWebkitKineticScroll: (v: boolean) => void;
|
||||||
setNowPlayingEnabled: (v: boolean) => void;
|
setNowPlayingEnabled: (v: boolean) => void;
|
||||||
setLyricsServerFirst: (v: boolean) => void;
|
setLyricsServerFirst: (v: boolean) => void;
|
||||||
setEnableNeteaselyrics: (v: boolean) => void;
|
setEnableNeteaselyrics: (v: boolean) => void;
|
||||||
@@ -314,6 +317,7 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
discordTemplateState: '{album}',
|
discordTemplateState: '{album}',
|
||||||
discordTemplateLargeText: '{album}',
|
discordTemplateLargeText: '{album}',
|
||||||
useCustomTitlebar: false,
|
useCustomTitlebar: false,
|
||||||
|
linuxWebkitKineticScroll: true,
|
||||||
nowPlayingEnabled: false,
|
nowPlayingEnabled: false,
|
||||||
lyricsServerFirst: true,
|
lyricsServerFirst: true,
|
||||||
enableNeteaselyrics: false,
|
enableNeteaselyrics: false,
|
||||||
@@ -443,6 +447,7 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
setDiscordTemplateState: (v) => set({ discordTemplateState: v }),
|
setDiscordTemplateState: (v) => set({ discordTemplateState: v }),
|
||||||
setDiscordTemplateLargeText: (v) => set({ discordTemplateLargeText: v }),
|
setDiscordTemplateLargeText: (v) => set({ discordTemplateLargeText: v }),
|
||||||
setUseCustomTitlebar: (v) => set({ useCustomTitlebar: v }),
|
setUseCustomTitlebar: (v) => set({ useCustomTitlebar: v }),
|
||||||
|
setLinuxWebkitKineticScroll: (v) => set({ linuxWebkitKineticScroll: v }),
|
||||||
setNowPlayingEnabled: (v) => set({ nowPlayingEnabled: v }),
|
setNowPlayingEnabled: (v) => set({ nowPlayingEnabled: v }),
|
||||||
setLyricsServerFirst: (v: boolean) => set({ lyricsServerFirst: v }),
|
setLyricsServerFirst: (v: boolean) => set({ lyricsServerFirst: v }),
|
||||||
setEnableNeteaselyrics: (v: boolean) => set({ enableNeteaselyrics: v }),
|
setEnableNeteaselyrics: (v: boolean) => set({ enableNeteaselyrics: v }),
|
||||||
@@ -630,6 +635,18 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
}
|
}
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
|
|
||||||
|
// One-time: older builds could persist smooth=false as the default. Force smooth on once
|
||||||
|
// so updates do not leave users on discrete scrolling; after this flag exists, only an
|
||||||
|
// explicit toggle in Settings may turn it off (persisted in psysonic-auth).
|
||||||
|
const wheelSmoothMigrationKey = 'psysonic-linux-webkit-smooth-v1';
|
||||||
|
let wheelSmoothOneTime: { linuxWebkitKineticScroll?: boolean } = {};
|
||||||
|
try {
|
||||||
|
if (!localStorage.getItem(wheelSmoothMigrationKey)) {
|
||||||
|
wheelSmoothOneTime = { linuxWebkitKineticScroll: true };
|
||||||
|
localStorage.setItem(wheelSmoothMigrationKey, '1');
|
||||||
|
}
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
|
||||||
useAuthStore.setState({
|
useAuthStore.setState({
|
||||||
mixMinRatingSong: clampMixFilterMinStars(state.mixMinRatingSong as number),
|
mixMinRatingSong: clampMixFilterMinStars(state.mixMinRatingSong as number),
|
||||||
mixMinRatingAlbum: clampMixFilterMinStars(state.mixMinRatingAlbum as number),
|
mixMinRatingAlbum: clampMixFilterMinStars(state.mixMinRatingAlbum as number),
|
||||||
@@ -639,6 +656,7 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
),
|
),
|
||||||
...conflictingLegacyState,
|
...conflictingLegacyState,
|
||||||
...lyricsSourcesMigrated,
|
...lyricsSourcesMigrated,
|
||||||
|
...wheelSmoothOneTime,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user