add enjoy app
This commit is contained in:
70
enjoy/src/renderer/context/ai-settings-provider.tsx
Normal file
70
enjoy/src/renderer/context/ai-settings-provider.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import { createContext, useEffect, useState, useContext } from "react";
|
||||
import { AppSettingsProviderContext } from "@renderer/context";
|
||||
|
||||
type AISettingsProviderState = {
|
||||
openai?: LlmProviderType;
|
||||
setOpenai?: (config: LlmProviderType) => void;
|
||||
googleGenerativeAi?: LlmProviderType;
|
||||
setGoogleGenerativeAi?: (config: LlmProviderType) => void;
|
||||
};
|
||||
|
||||
const initialState: AISettingsProviderState = {};
|
||||
|
||||
export const AISettingsProviderContext =
|
||||
createContext<AISettingsProviderState>(initialState);
|
||||
|
||||
export const AISettingsProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const [openai, setOpenai] = useState<LlmProviderType>(null);
|
||||
const [googleGenerativeAi, setGoogleGenerativeAi] =
|
||||
useState<LlmProviderType>(null);
|
||||
const { EnjoyApp } = useContext(AppSettingsProviderContext);
|
||||
|
||||
useEffect(() => {
|
||||
fetchSettings();
|
||||
}, []);
|
||||
|
||||
const fetchSettings = async () => {
|
||||
const _openai = await EnjoyApp.settings.getLlm("openai");
|
||||
if (_openai) setOpenai(_openai);
|
||||
|
||||
const _googleGenerativeAi = await EnjoyApp.settings.getLlm(
|
||||
"googleGenerativeAi"
|
||||
);
|
||||
if (_googleGenerativeAi) setGoogleGenerativeAi(_googleGenerativeAi);
|
||||
};
|
||||
|
||||
const handleSetLlm = async (
|
||||
name: SupportedLlmProviderType,
|
||||
config: LlmProviderType
|
||||
) => {
|
||||
await EnjoyApp.settings.setLlm(name, config);
|
||||
const _config = await EnjoyApp.settings.getLlm(name);
|
||||
|
||||
switch (name) {
|
||||
case "openai":
|
||||
setOpenai(_config);
|
||||
break;
|
||||
case "googleGenerativeAi":
|
||||
setGoogleGenerativeAi(_config);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AISettingsProviderContext.Provider
|
||||
value={{
|
||||
openai,
|
||||
setOpenai: (config: LlmProviderType) => handleSetLlm("openai", config),
|
||||
googleGenerativeAi,
|
||||
setGoogleGenerativeAi: (config: LlmProviderType) =>
|
||||
handleSetLlm("googleGenerativeAi", config),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AISettingsProviderContext.Provider>
|
||||
);
|
||||
};
|
||||
142
enjoy/src/renderer/context/app-settings-provider.tsx
Normal file
142
enjoy/src/renderer/context/app-settings-provider.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
import { createContext, useEffect, useState } from "react";
|
||||
|
||||
type AppSettingsProviderState = {
|
||||
user: UserType | null;
|
||||
initialized: boolean;
|
||||
version?: string;
|
||||
libraryPath?: string;
|
||||
whisperModelsPath?: string;
|
||||
whisperModel?: string;
|
||||
login?: (user: UserType) => void;
|
||||
logout?: () => void;
|
||||
setLibraryPath?: (path: string) => Promise<void>;
|
||||
setWhisperModel?: (name: string) => void;
|
||||
ffmpegConfg?: FfmpegConfigType;
|
||||
setFfmegConfig?: (config: FfmpegConfigType) => void;
|
||||
EnjoyApp?: EnjoyAppType;
|
||||
};
|
||||
|
||||
const initialState: AppSettingsProviderState = {
|
||||
user: null,
|
||||
initialized: false,
|
||||
};
|
||||
|
||||
export const AppSettingsProviderContext =
|
||||
createContext<AppSettingsProviderState>(initialState);
|
||||
|
||||
export const AppSettingsProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const [initialized, setInitialized] = useState<boolean>(false);
|
||||
const [version, setVersion] = useState<string>("");
|
||||
const [user, setUser] = useState<UserType | null>(null);
|
||||
const [libraryPath, setLibraryPath] = useState("");
|
||||
const [whisperModelsPath, setWhisperModelsPath] = useState<string>("");
|
||||
const [whisperModel, setWhisperModel] = useState<string>(null);
|
||||
const [ffmpegConfg, setFfmegConfig] = useState<FfmpegConfigType>(null);
|
||||
const EnjoyApp = window.__ENJOY_APP__;
|
||||
|
||||
useEffect(() => {
|
||||
fetchVersion();
|
||||
fetchUser();
|
||||
fetchLibraryPath();
|
||||
fetchModel();
|
||||
fetchFfmpegConfig();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
updatePaths();
|
||||
}, [libraryPath]);
|
||||
|
||||
useEffect(() => {
|
||||
validate();
|
||||
}, [user, libraryPath, whisperModel, ffmpegConfg]);
|
||||
|
||||
const fetchFfmpegConfig = async () => {
|
||||
const config = await EnjoyApp.settings.getFfmpegConfig();
|
||||
setFfmegConfig(config);
|
||||
};
|
||||
|
||||
const fetchVersion = async () => {
|
||||
const version = EnjoyApp.app.version;
|
||||
setVersion(version);
|
||||
};
|
||||
|
||||
const fetchUser = async () => {
|
||||
const currentUser = await EnjoyApp.settings.getUser();
|
||||
if (!currentUser) return;
|
||||
|
||||
EnjoyApp.webApi.me().then((user) => {
|
||||
if (user?.id) {
|
||||
login(currentUser);
|
||||
} else {
|
||||
logout();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const login = (user: UserType) => {
|
||||
setUser(user);
|
||||
EnjoyApp.settings.setUser(user);
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
setUser(null);
|
||||
EnjoyApp.settings.setUser(null);
|
||||
};
|
||||
|
||||
const fetchLibraryPath = async () => {
|
||||
const dir = await EnjoyApp.settings.getLibrary();
|
||||
setLibraryPath(dir);
|
||||
};
|
||||
|
||||
const setLibraryPathHandler = async (dir: string) => {
|
||||
await EnjoyApp.settings.setLibrary(dir);
|
||||
setLibraryPath(dir);
|
||||
};
|
||||
|
||||
const updatePaths = async () => {
|
||||
const _path = await EnjoyApp.settings.getWhisperModelsPath();
|
||||
setWhisperModelsPath(_path);
|
||||
};
|
||||
|
||||
const fetchModel = async () => {
|
||||
const whisperModel = await EnjoyApp.settings.getWhisperModel();
|
||||
setWhisperModel(whisperModel);
|
||||
};
|
||||
|
||||
const setModelHandler = async (name: string) => {
|
||||
await EnjoyApp.settings.setWhisperModel(name);
|
||||
setWhisperModel(name);
|
||||
};
|
||||
|
||||
const validate = async () => {
|
||||
setInitialized(
|
||||
!!(user && libraryPath && whisperModel && ffmpegConfg?.ready)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<AppSettingsProviderContext.Provider
|
||||
value={{
|
||||
EnjoyApp,
|
||||
version,
|
||||
user,
|
||||
login,
|
||||
logout,
|
||||
libraryPath,
|
||||
setLibraryPath: setLibraryPathHandler,
|
||||
whisperModelsPath,
|
||||
whisperModel,
|
||||
setWhisperModel: setModelHandler,
|
||||
ffmpegConfg,
|
||||
setFfmegConfig,
|
||||
initialized,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AppSettingsProviderContext.Provider>
|
||||
);
|
||||
};
|
||||
79
enjoy/src/renderer/context/db-provider.tsx
Normal file
79
enjoy/src/renderer/context/db-provider.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { createContext, useState, useEffect, useContext } from "react";
|
||||
import { AppSettingsProviderContext } from "./app-settings-provider";
|
||||
import log from "electron-log/renderer";
|
||||
|
||||
type DbStateEnum = "connected" | "connecting" | "error" | "disconnected";
|
||||
type DbState = {
|
||||
state: DbStateEnum;
|
||||
path?: string;
|
||||
error?: string;
|
||||
connect?: () => void;
|
||||
addDblistener?: (callback: (event: CustomEvent) => void) => void;
|
||||
removeDbListener?: (callback: (event: CustomEvent) => void) => void;
|
||||
};
|
||||
type DbProviderState = DbState & {
|
||||
connect?: () => void;
|
||||
};
|
||||
|
||||
const initialState: DbProviderState = {
|
||||
state: "disconnected",
|
||||
};
|
||||
|
||||
export const DbProviderContext = createContext<DbProviderState>(initialState);
|
||||
|
||||
export const DbProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const [state, setState] = useState<DbStateEnum>("disconnected");
|
||||
const [path, setPath] = useState();
|
||||
const [error, setError] = useState();
|
||||
const { EnjoyApp } = useContext(AppSettingsProviderContext);
|
||||
|
||||
const connect = async () => {
|
||||
if (["connected", "connecting"].includes(state)) return;
|
||||
|
||||
setState("connecting");
|
||||
|
||||
const _db = await EnjoyApp.db.init();
|
||||
|
||||
setState(_db.state);
|
||||
setPath(_db.path);
|
||||
setError(_db.error);
|
||||
};
|
||||
|
||||
const addDblistener = (callback: (event: CustomEvent) => void) => {
|
||||
document.addEventListener("db-on-transaction", callback);
|
||||
};
|
||||
|
||||
const removeDbListener = (callback: (event: CustomEvent) => void) => {
|
||||
document.removeEventListener("db-on-transaction", callback);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (state !== "connected") return;
|
||||
|
||||
EnjoyApp.db.onTransaction((_event, state) => {
|
||||
log.debug("db-on-transaction", state);
|
||||
|
||||
const event = new CustomEvent("db-on-transaction", { detail: state });
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
|
||||
return () => {
|
||||
EnjoyApp.db.removeListeners();
|
||||
};
|
||||
}, [state]);
|
||||
|
||||
return (
|
||||
<DbProviderContext.Provider
|
||||
value={{
|
||||
state,
|
||||
path,
|
||||
error,
|
||||
connect,
|
||||
addDblistener,
|
||||
removeDbListener,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</DbProviderContext.Provider>
|
||||
);
|
||||
};
|
||||
4
enjoy/src/renderer/context/index.ts
Normal file
4
enjoy/src/renderer/context/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./ai-settings-provider";
|
||||
export * from "./app-settings-provider";
|
||||
export * from "./db-provider";
|
||||
export * from "./theme-provider";
|
||||
73
enjoy/src/renderer/context/theme-provider.tsx
Normal file
73
enjoy/src/renderer/context/theme-provider.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { createContext, useContext, useEffect, useState } from "react";
|
||||
|
||||
type Theme = "dark" | "light" | "system";
|
||||
|
||||
type ThemeProviderProps = {
|
||||
children: React.ReactNode;
|
||||
defaultTheme?: Theme;
|
||||
storageKey?: string;
|
||||
};
|
||||
|
||||
type ThemeProviderState = {
|
||||
theme: Theme;
|
||||
setTheme: (theme: Theme) => void;
|
||||
};
|
||||
|
||||
const initialState: ThemeProviderState = {
|
||||
theme: "system",
|
||||
setTheme: () => null,
|
||||
};
|
||||
|
||||
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
defaultTheme = "system",
|
||||
storageKey = "vite-ui-theme",
|
||||
...props
|
||||
}: ThemeProviderProps) {
|
||||
const [theme, setTheme] = useState<Theme>(
|
||||
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const root = window.document.documentElement;
|
||||
|
||||
root.classList.remove("light", "dark");
|
||||
|
||||
if (theme === "system") {
|
||||
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
||||
.matches
|
||||
? "dark"
|
||||
: "light";
|
||||
|
||||
root.classList.add(systemTheme);
|
||||
return;
|
||||
}
|
||||
|
||||
root.classList.add(theme);
|
||||
}, [theme]);
|
||||
|
||||
const value = {
|
||||
theme,
|
||||
setTheme: (theme: Theme) => {
|
||||
localStorage.setItem(storageKey, theme);
|
||||
setTheme(theme);
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProviderContext.Provider {...props} value={value}>
|
||||
{children}
|
||||
</ThemeProviderContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useTheme = () => {
|
||||
const context = useContext(ThemeProviderContext);
|
||||
|
||||
if (context === undefined)
|
||||
throw new Error("useTheme must be used within a ThemeProvider");
|
||||
|
||||
return context;
|
||||
};
|
||||
Reference in New Issue
Block a user