mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-26 20:18:37 +00:00
feat: implement settings engine with directory picker and aria2 configuration sync
This commit is contained in:
+25
-4
@@ -1435,10 +1435,26 @@ pub fn run() {
|
||||
}
|
||||
crate::scheduler::spawn_scheduler(app.handle().clone());
|
||||
|
||||
let mut global_speed_limit = String::new();
|
||||
{
|
||||
use tauri_plugin_store::StoreExt;
|
||||
if let Ok(store) = app.handle().store("store.bin") {
|
||||
if let Some(settings_val) = store.get("settings") {
|
||||
if let Some(settings_str) = settings_val.as_str() {
|
||||
if let Ok(settings_json) = serde_json::from_str::<serde_json::Value>(settings_str) {
|
||||
if let Some(limit) = settings_json.get("globalSpeedLimit").and_then(|v| v.as_str()) {
|
||||
global_speed_limit = limit.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
let aria2_process = match app.handle().shell().sidecar("aria2c") {
|
||||
Ok(cmd) => {
|
||||
cmd.arg("--enable-rpc=true")
|
||||
Ok(mut cmd) => {
|
||||
cmd = cmd.arg("--enable-rpc=true")
|
||||
.arg(format!("--rpc-listen-port={}", aria2_port))
|
||||
.arg(format!("--rpc-secret={}", aria2_secret))
|
||||
.arg("--rpc-listen-all=false")
|
||||
@@ -1447,8 +1463,13 @@ pub fn run() {
|
||||
.arg("--summary-interval=1")
|
||||
.arg("--console-log-level=warn")
|
||||
.arg("--download-result=hide")
|
||||
.arg("--check-certificate=true")
|
||||
.spawn()
|
||||
.arg("--check-certificate=true");
|
||||
|
||||
if !global_speed_limit.is_empty() {
|
||||
cmd = cmd.arg(format!("--max-overall-download-limit={}", global_speed_limit));
|
||||
}
|
||||
|
||||
cmd.spawn()
|
||||
.map(|(_, child)| child)
|
||||
.ok()
|
||||
}
|
||||
|
||||
+1
-1
@@ -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>) => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 };
|
||||
};
|
||||
@@ -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,
|
||||
}),
|
||||
}
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user