feat: implement settings engine with directory picker and aria2 configuration sync

This commit is contained in:
NimBold
2026-06-16 15:10:29 +03:30
parent 275eb6e5c4
commit 85cdabd72b
5 changed files with 140 additions and 5 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ function App() {
const doneCount = downloads.filter(download => download.status === 'completed').length;
const schedulerRunning = useSettingsStore(state => state.schedulerRunning);
const globalSpeedLimit = useSettingsStore(state => state.globalSpeedLimit);
const previousSpeedLimit = useRef(globalSpeedLimit);
const previousSpeedLimit = useRef<string | null>(null);
const maxConcurrentDownloads = useSettingsStore(state => state.maxConcurrentDownloads);
const startSidebarResize = (event: React.PointerEvent<HTMLDivElement>) => {
+26
View File
@@ -5,6 +5,7 @@ import {
SettingsTab,
useSettingsStore
} from '../store/useSettingsStore';
import { useDirectoryPicker } from '../hooks/useDirectoryPicker';
import {
Download, Palette, Globe, Folder, Key,
Moon, Terminal, Puzzle, Info, Plus, Trash2, Copy, RefreshCw, Code
@@ -29,6 +30,7 @@ const settingsTabs: { type: SettingsTab; label: string; icon: typeof Download }[
export default function SettingsView() {
const settings = useSettingsStore();
const { pickDirectory } = useDirectoryPicker();
const activeTab = settings.activeSettingsTab;
// Local state for versions
@@ -537,6 +539,30 @@ export default function SettingsView() {
{/* Locations Pane */}
{activeTab === 'locations' && (
<div className="settings-pane max-w-[760px]">
<div className="mac-settings-group">
<div className="mac-settings-row">
<span className="text-[13px] font-semibold text-text-primary">Default Download Path</span>
<div className="flex gap-2">
<input
type="text"
value={settings.defaultDownloadPath || ''}
onChange={(e) => settings.setDefaultDownloadPath(e.target.value)}
className="app-control w-64 text-[11px] px-2"
placeholder="~/Downloads"
/>
<button
onClick={async () => {
const path = await pickDirectory(settings.defaultDownloadPath);
if (path) settings.setDefaultDownloadPath(path);
}}
className="app-button px-3 text-xs text-text-secondary hover:bg-item-hover"
>
Browse
</button>
</div>
</div>
</div>
<div className="mac-settings-group">
<label className="mac-settings-row cursor-default">
<span className="text-[13px] text-text-primary">Ask where to save each file</span>
+22
View File
@@ -0,0 +1,22 @@
import { open } from '@tauri-apps/plugin-dialog';
export const useDirectoryPicker = () => {
const pickDirectory = async (defaultPath?: string): Promise<string | null> => {
try {
const selected = await open({
directory: true,
multiple: false,
defaultPath: defaultPath,
});
if (selected && typeof selected === 'string') {
return selected;
}
return null;
} catch (e) {
console.error('Failed to pick directory:', e);
return null;
}
};
return { pickDirectory };
};
+66
View File
@@ -0,0 +1,66 @@
import { create } from 'zustand';
import { persist, createJSONStorage, StateStorage } from 'zustand/middleware';
import { LazyStore } from '@tauri-apps/plugin-store';
export const tauriStore = new LazyStore('store.bin');
const tauriStorage: StateStorage = {
getItem: async (name: string): Promise<string | null> => {
if (name === 'firelink-engine-settings') {
try {
const data = await tauriStore.get<string>('engine_settings');
return data || null;
} catch (e) {
console.error("Failed to load engine settings from DB", e);
return null;
}
}
return null;
},
setItem: async (name: string, value: string): Promise<void> => {
if (name === 'firelink-engine-settings') {
try {
await tauriStore.set('engine_settings', value);
await tauriStore.save();
} catch (e) {
console.error("Failed to save engine settings to DB", e);
}
}
},
removeItem: async (_name: string): Promise<void> => {
// no-op for now
},
};
export interface SettingsState {
defaultDownloadPath: string;
globalSpeedLimit: number;
concurrentDownloads: number;
setDefaultDownloadPath: (path: string) => void;
setGlobalSpeedLimit: (limit: number) => void;
setConcurrentDownloads: (count: number) => void;
}
export const useSettingsStore = create<SettingsState>()(
persist(
(set) => ({
defaultDownloadPath: '~/Downloads',
globalSpeedLimit: 0,
concurrentDownloads: 3,
setDefaultDownloadPath: (path) => set({ defaultDownloadPath: path }),
setGlobalSpeedLimit: (limit) => set({ globalSpeedLimit: limit }),
setConcurrentDownloads: (count) => set({ concurrentDownloads: count }),
}),
{
name: 'firelink-engine-settings',
storage: createJSONStorage(() => tauriStorage),
partialize: (state) => ({
defaultDownloadPath: state.defaultDownloadPath,
globalSpeedLimit: state.globalSpeedLimit,
concurrentDownloads: state.concurrentDownloads,
}),
}
)
);