feat: add first version of TougliGui with same features as on google sheet
This commit is contained in:
142
src/store.ts
Normal file
142
src/store.ts
Normal file
@ -0,0 +1,142 @@
|
||||
import { create } from "zustand";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { Profile, GuideListItem, GuideData, SyncResult } from "./types";
|
||||
|
||||
interface AppState {
|
||||
profiles: Profile[];
|
||||
activeProfileId: string | null;
|
||||
guides: GuideListItem[];
|
||||
activeGuideGid: string | null;
|
||||
activeGuideData: GuideData | null;
|
||||
completedQuests: Set<string>;
|
||||
alwaysOnTop: boolean;
|
||||
syncing: boolean;
|
||||
syncProgress: { current: number; total: number; label: string } | null;
|
||||
view: "home" | "guide";
|
||||
|
||||
loadProfiles: () => Promise<void>;
|
||||
setActiveProfile: (id: string) => Promise<void>;
|
||||
createProfile: (name: string) => Promise<void>;
|
||||
deleteProfile: (id: string) => Promise<void>;
|
||||
|
||||
loadGuides: () => Promise<void>;
|
||||
openGuide: (gid: string) => Promise<void>;
|
||||
closeGuide: () => void;
|
||||
|
||||
toggleQuest: (questName: string) => Promise<void>;
|
||||
|
||||
syncGuides: () => Promise<SyncResult>;
|
||||
syncSingleGuide: (gid: string, name: string) => Promise<void>;
|
||||
toggleAlwaysOnTop: () => Promise<void>;
|
||||
}
|
||||
|
||||
export const useStore = create<AppState>((set, get) => ({
|
||||
profiles: [],
|
||||
activeProfileId: null,
|
||||
guides: [],
|
||||
activeGuideGid: null,
|
||||
activeGuideData: null,
|
||||
completedQuests: new Set(),
|
||||
alwaysOnTop: true,
|
||||
syncing: false,
|
||||
syncProgress: null,
|
||||
view: "home",
|
||||
|
||||
loadProfiles: async () => {
|
||||
const profiles = await invoke<Profile[]>("get_profiles");
|
||||
const saved = await invoke<string | null>("get_setting", { key: "active_profile" });
|
||||
const activeId = saved && profiles.find(p => p.id === saved) ? saved : profiles[0]?.id ?? null;
|
||||
set({ profiles, activeProfileId: activeId });
|
||||
if (activeId) {
|
||||
const completed = await invoke<string[]>("get_completed_quests", { profileId: activeId });
|
||||
set({ completedQuests: new Set(completed) });
|
||||
}
|
||||
},
|
||||
|
||||
setActiveProfile: async (id) => {
|
||||
await invoke("set_setting", { key: "active_profile", value: id });
|
||||
const completed = await invoke<string[]>("get_completed_quests", { profileId: id });
|
||||
set({ activeProfileId: id, completedQuests: new Set(completed) });
|
||||
await get().loadGuides();
|
||||
},
|
||||
|
||||
createProfile: async (name) => {
|
||||
const profile = await invoke<Profile>("create_profile", { name });
|
||||
set(state => ({ profiles: [...state.profiles, profile] }));
|
||||
await get().setActiveProfile(profile.id);
|
||||
},
|
||||
|
||||
deleteProfile: async (id) => {
|
||||
await invoke("delete_profile", { profileId: id });
|
||||
const { profiles, activeProfileId } = get();
|
||||
const remaining = profiles.filter(p => p.id !== id);
|
||||
const newActive = activeProfileId === id ? remaining[0]?.id ?? null : activeProfileId;
|
||||
set({ profiles: remaining, activeProfileId: newActive });
|
||||
if (newActive) await get().setActiveProfile(newActive);
|
||||
},
|
||||
|
||||
loadGuides: async () => {
|
||||
const { activeProfileId } = get();
|
||||
if (!activeProfileId) return;
|
||||
const guides = await invoke<GuideListItem[]>("get_guides_list", { profileId: activeProfileId });
|
||||
set({ guides });
|
||||
},
|
||||
|
||||
openGuide: async (gid) => {
|
||||
const data = await invoke<GuideData>("get_guide", { gid });
|
||||
set({ activeGuideGid: gid, activeGuideData: data, view: "guide" });
|
||||
},
|
||||
|
||||
closeGuide: () => {
|
||||
set({ activeGuideGid: null, activeGuideData: null, view: "home" });
|
||||
},
|
||||
|
||||
toggleQuest: async (questName) => {
|
||||
const { activeProfileId, completedQuests } = get();
|
||||
if (!activeProfileId) return;
|
||||
const isNowCompleted = await invoke<boolean>("toggle_quest", {
|
||||
profileId: activeProfileId,
|
||||
questName,
|
||||
});
|
||||
const next = new Set(completedQuests);
|
||||
if (isNowCompleted) next.add(questName);
|
||||
else next.delete(questName);
|
||||
set({ completedQuests: next });
|
||||
|
||||
// Refresh guide list progress counts
|
||||
await get().loadGuides();
|
||||
},
|
||||
|
||||
syncGuides: async () => {
|
||||
const tabs = await invoke<{ gid: string; name: string }[]>("get_tabs_list");
|
||||
const total = tabs.length;
|
||||
const errors: string[] = [];
|
||||
let synced = 0;
|
||||
|
||||
set({ syncing: true, syncProgress: { current: 0, total, label: "Démarrage…" } });
|
||||
|
||||
for (const tab of tabs) {
|
||||
set({ syncProgress: { current: synced, total, label: tab.name } });
|
||||
try {
|
||||
await invoke("sync_single_guide", { gid: tab.gid, name: tab.name });
|
||||
synced++;
|
||||
} catch (e) {
|
||||
errors.push(`${tab.name}: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
set({ syncing: false, syncProgress: null });
|
||||
await get().loadGuides();
|
||||
return { synced, errors };
|
||||
},
|
||||
|
||||
syncSingleGuide: async (gid, name) => {
|
||||
await invoke("sync_single_guide", { gid, name });
|
||||
},
|
||||
|
||||
toggleAlwaysOnTop: async () => {
|
||||
const next = !get().alwaysOnTop;
|
||||
await invoke("set_always_on_top", { value: next });
|
||||
set({ alwaysOnTop: next });
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user