import { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { InputWithContext } from "@/components/ui/input-with-context"; import { Label } from "@/components/ui/label"; import { Dialog, DialogContent, DialogFooter, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Checkbox } from "@/components/ui/checkbox"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { Settings as SettingsIcon, FolderOpen, Save, RotateCcw, Info, X } from "lucide-react"; import { getSettings, getSettingsWithDefaults, saveSettings, resetToDefaultSettings, applyThemeMode, type Settings as SettingsType } from "@/lib/settings"; import { themes, applyTheme } from "@/lib/themes"; import { SelectFolder } from "../../wailsjs/go/main/App"; // Service Icons const TidalIcon = () => ( ); const DeezerIcon = () => ( ); const QobuzIcon = () => ( ); const AmazonIcon = () => ( ); export function Settings() { const [open, setOpen] = useState(false); const [savedSettings, setSavedSettings] = useState(getSettings()); const [tempSettings, setTempSettings] = useState(savedSettings); const [, setIsLoadingDefaults] = useState(false); const [isDark, setIsDark] = useState(document.documentElement.classList.contains('dark')); // Apply saved settings useEffect(() => { applyThemeMode(savedSettings.themeMode); applyTheme(savedSettings.theme); // Setup listener for system theme changes const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); const handleChange = () => { if (savedSettings.themeMode === "auto") { applyThemeMode("auto"); applyTheme(savedSettings.theme); } }; mediaQuery.addEventListener("change", handleChange); return () => { mediaQuery.removeEventListener("change", handleChange); }; }, [savedSettings.themeMode, savedSettings.theme]); // Apply temp settings for preview when dialog is open useEffect(() => { if (open) { applyThemeMode(tempSettings.themeMode); applyTheme(tempSettings.theme); // Update isDark state after theme is applied setTimeout(() => { setIsDark(document.documentElement.classList.contains('dark')); }, 0); // Setup listener for system theme changes during preview const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); const handleChange = () => { if (tempSettings.themeMode === "auto") { applyThemeMode("auto"); applyTheme(tempSettings.theme); setTimeout(() => { setIsDark(document.documentElement.classList.contains('dark')); }, 0); } }; mediaQuery.addEventListener("change", handleChange); return () => { mediaQuery.removeEventListener("change", handleChange); }; } }, [open, tempSettings.themeMode, tempSettings.theme]); useEffect(() => { // Load settings with defaults from backend on mount const loadDefaults = async () => { if (!savedSettings.downloadPath) { setIsLoadingDefaults(true); const settingsWithDefaults = await getSettingsWithDefaults(); setSavedSettings(settingsWithDefaults); setTempSettings(settingsWithDefaults); setIsLoadingDefaults(false); } }; loadDefaults(); }, []); // Reset temp settings when dialog opens useEffect(() => { if (open) { setTempSettings(savedSettings); } }, [open, savedSettings]); const handleSave = () => { saveSettings(tempSettings); setSavedSettings(tempSettings); setOpen(false); }; const handleReset = async () => { const defaultSettings = await resetToDefaultSettings(); setTempSettings(defaultSettings); setSavedSettings(defaultSettings); // Apply default theme mode and theme applyThemeMode(defaultSettings.themeMode); applyTheme(defaultSettings.theme); }; const handleCancel = () => { // Revert to saved settings applyThemeMode(savedSettings.themeMode); applyTheme(savedSettings.theme); setTempSettings(savedSettings); setOpen(false); }; const handleOpenChange = (newOpen: boolean) => { if (!newOpen) { // Dialog is closing, revert to saved settings applyThemeMode(savedSettings.themeMode); applyTheme(savedSettings.theme); setTempSettings(savedSettings); } setOpen(newOpen); }; const handleDownloadPathChange = (value: string) => { setTempSettings((prev) => ({ ...prev, downloadPath: value })); }; const handleDownloaderChange = (value: "auto" | "deezer" | "tidal" | "qobuz" | "amazon") => { setTempSettings((prev) => ({ ...prev, downloader: value })); }; const handleThemeChange = (value: string) => { setTempSettings((prev) => ({ ...prev, theme: value })); }; const handleThemeModeChange = (value: "auto" | "light" | "dark") => { setTempSettings((prev) => ({ ...prev, themeMode: value })); }; const handleBrowseFolder = async () => { try { // Call backend to open folder selection dialog const selectedPath = await SelectFolder(tempSettings.downloadPath || ""); console.log("Selected path:", selectedPath); if (selectedPath && selectedPath.trim() !== "") { setTempSettings((prev) => ({ ...prev, downloadPath: selectedPath })); } else { console.log("No folder selected or user cancelled"); } } catch (error) { console.error("Error selecting folder:", error); alert(`Error selecting folder: ${error}`); } }; return ( Settings {/* Left Column */} {/* Download Path */} Download Path handleDownloadPathChange(e.target.value)} placeholder="C:\Users\YourUsername\Music" /> Browse {/* Source Selection */} Source Auto Tidal Deezer Qobuz Amazon Music {/* Theme Mode Selection */} Theme Auto Light Dark {/* Theme Color Selection */} Theme Color {themes.map((theme) => ( {theme.label} ))} {/* Right Column */} {/* Filename Format */} Filename Format setTempSettings(prev => ({ ...prev, filenameFormat: value as any }))} > Title - Artist Artist - Title Title {/* Folder Settings */} Folder Settings setTempSettings(prev => ({ ...prev, trackNumber: checked as boolean }))} /> Track Number Adds track numbers to filenames. Uses album track numbers when Album Subfolder is enabled, otherwise uses playlist position setTempSettings(prev => ({ ...prev, artistSubfolder: checked as boolean }))} /> Artist Subfolder Playlist only setTempSettings(prev => ({ ...prev, albumSubfolder: checked as boolean }))} /> Album Subfolder Playlist & Discography Reset to Default Cancel Save Changes ); }
Adds track numbers to filenames. Uses album track numbers when Album Subfolder is enabled, otherwise uses playlist position
Playlist only
Playlist & Discography