From 71d79a4a15927c7140bb37114f4c8c1a5eb1676e Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Thu, 20 Jun 2024 13:22:12 +0100 Subject: [PATCH 1/3] feat: adding auth window --- src/main/events/auth/open-auth-window.ts | 7 ++++ src/main/events/index.ts | 1 + src/main/index.ts | 7 +--- src/main/services/hydra-api.ts | 4 +-- src/main/services/window-manager.ts | 36 +++++++++++++++++++ src/preload/index.ts | 1 + src/renderer/src/app.tsx | 2 +- .../components/sidebar/sidebar-profile.tsx | 2 +- src/renderer/src/declaration.d.ts | 1 + 9 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 src/main/events/auth/open-auth-window.ts diff --git a/src/main/events/auth/open-auth-window.ts b/src/main/events/auth/open-auth-window.ts new file mode 100644 index 00000000..e93a5a42 --- /dev/null +++ b/src/main/events/auth/open-auth-window.ts @@ -0,0 +1,7 @@ +import { registerEvent } from "../register-event"; +import { WindowManager } from "@main/services"; + +const openAuthWindow = async (_event: Electron.IpcMainInvokeEvent) => + WindowManager.openAuthWindow(); + +registerEvent("openAuthWindow", openAuthWindow); diff --git a/src/main/events/index.ts b/src/main/events/index.ts index 548106e0..32c9243c 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -41,6 +41,7 @@ import "./download-sources/add-download-source"; import "./download-sources/remove-download-source"; import "./download-sources/sync-download-sources"; import "./auth/signout"; +import "./auth/open-auth-window"; import "./user/get-user"; import "./profile/get-me"; import "./profile/update-profile"; diff --git a/src/main/index.ts b/src/main/index.ts index 10399beb..6b51f978 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -8,7 +8,6 @@ import { DownloadManager, logger, WindowManager } from "@main/services"; import { dataSource } from "@main/data-source"; import * as resources from "@locales"; import { userPreferencesRepository } from "@main/repository"; -import { HydraApi } from "./services/hydra-api"; const { autoUpdater } = updater; @@ -87,11 +86,7 @@ app.on("second-instance", (_event, commandLine) => { const [, path] = commandLine.pop()?.split("://") ?? []; if (path) { - if (path.startsWith("auth")) { - HydraApi.handleExternalAuth(path); - } else { - WindowManager.redirect(path); - } + WindowManager.redirect(path); } }); diff --git a/src/main/services/hydra-api.ts b/src/main/services/hydra-api.ts index 8e50e646..e6e042db 100644 --- a/src/main/services/hydra-api.ts +++ b/src/main/services/hydra-api.ts @@ -23,8 +23,8 @@ export class HydraApi { return this.userAuth.authToken !== ""; } - static async handleExternalAuth(auth: string) { - const { payload } = url.parse(auth, true).query; + static async handleExternalAuth(uri: string) { + const { payload } = url.parse(uri, true).query; const decodedBase64 = atob(payload as string); const jsonData = JSON.parse(decodedBase64); diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 7b57445b..eccceccf 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -15,6 +15,7 @@ import icon from "@resources/icon.png?asset"; import trayIcon from "@resources/tray-icon.png?asset"; import { gameRepository, userPreferencesRepository } from "@main/repository"; import { IsNull, Not } from "typeorm"; +import { HydraApi } from "./hydra-api"; export class WindowManager { public static mainWindow: Electron.BrowserWindow | null = null; @@ -80,6 +81,41 @@ export class WindowManager { }); } + public static openAuthWindow() { + if (this.mainWindow) { + const authWindow = new BrowserWindow({ + width: 600, + height: 640, + backgroundColor: "#1c1c1c", + parent: this.mainWindow, + modal: true, + show: false, + maximizable: false, + resizable: false, + minimizable: false, + webPreferences: { + sandbox: false, + }, + }); + + authWindow.removeMenu(); + + authWindow.loadURL("http://localhost:3000"); + + authWindow.once("ready-to-show", () => { + authWindow.show(); + }); + + authWindow.webContents.on("will-navigate", (_event, url) => { + if (url.startsWith("hydralauncher://auth")) { + authWindow.close(); + + HydraApi.handleExternalAuth(url); + } + }); + } + } + public static redirect(hash: string) { if (!this.mainWindow) this.createMainWindow(); this.loadURL(hash); diff --git a/src/preload/index.ts b/src/preload/index.ts index dd03f114..0cacafe3 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -143,6 +143,7 @@ contextBridge.exposeInMainWorld("electron", { /* Auth */ signOut: () => ipcRenderer.invoke("signOut"), + openAuthWindow: () => ipcRenderer.invoke("openAuthWindow"), onSignIn: (cb: () => void) => { const listener = (_event: Electron.IpcRendererEvent) => cb(); ipcRenderer.on("on-signin", listener); diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index 332a846b..27671a23 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -113,7 +113,7 @@ export function App() { return () => { listeners.forEach((unsubscribe) => unsubscribe()); }; - }, [fetchUserDetails, updateUserDetails, clearUserDetails]); + }, [fetchUserDetails, updateUserDetails, updateLibrary, clearUserDetails]); const handleSearch = useCallback( (query: string) => { diff --git a/src/renderer/src/components/sidebar/sidebar-profile.tsx b/src/renderer/src/components/sidebar/sidebar-profile.tsx index 4a89eff1..c86aecb7 100644 --- a/src/renderer/src/components/sidebar/sidebar-profile.tsx +++ b/src/renderer/src/components/sidebar/sidebar-profile.tsx @@ -12,7 +12,7 @@ export function SidebarProfile() { const handleButtonClick = () => { if (userDetails === null) { - window.electron.openExternal("https://auth.hydra.losbroxas.org"); + window.electron.openAuthWindow(); return; } diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index 6a0160c9..b7707d6f 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -115,6 +115,7 @@ declare global { /* Auth */ signOut: () => Promise; + openAuthWindow: () => Promise; onSignIn: (cb: () => void) => () => Electron.IpcRenderer; onSignOut: (cb: () => void) => () => Electron.IpcRenderer; From b1b48e2ec04364b4f77cb593d13d0d37e859e2ac Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Thu, 20 Jun 2024 13:24:33 +0100 Subject: [PATCH 2/3] fix: fixing auth url --- src/main/services/window-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index eccceccf..3e3eaf1c 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -100,7 +100,7 @@ export class WindowManager { authWindow.removeMenu(); - authWindow.loadURL("http://localhost:3000"); + authWindow.loadURL("https://auth.hydra.losbroxas.org/"); authWindow.once("ready-to-show", () => { authWindow.show(); From 9de7d4a61e9e10e4b1ec19bee38a9ade9028487a Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Thu, 20 Jun 2024 22:02:11 +0100 Subject: [PATCH 3/3] feat: adding toast when signing in and out --- src/locales/en/translation.json | 6 ++- src/locales/pt/translation.json | 6 ++- src/main/index.ts | 18 ++++---- src/renderer/src/app.css.ts | 2 +- src/renderer/src/app.tsx | 41 +++++++++++-------- .../src/components/backdrop/backdrop.css.ts | 6 +-- .../bottom-panel/bottom-panel.css.ts | 2 +- .../src/components/toast/toast.css.ts | 2 +- src/renderer/src/pages/user/user-content.tsx | 8 +++- src/renderer/src/theme.css.ts | 6 +++ 10 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 59145c6f..72b2b4cf 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -1,4 +1,7 @@ { + "app": { + "successfully_signed_in": "Successfully signed in" + }, "home": { "featured": "Featured", "trending": "Trending", @@ -243,6 +246,7 @@ "try_again": "Please, try again", "signout_modal_title": "Are you sure?", "cancel": "Cancel", - "signout": "Sign Out" + "signout": "Sign Out", + "successfully_signed_out": "Successfully signed out" } } diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json index 18ff1356..e658e656 100644 --- a/src/locales/pt/translation.json +++ b/src/locales/pt/translation.json @@ -1,4 +1,7 @@ { + "app": { + "successfully_signed_in": "Logado com sucesso" + }, "home": { "featured": "Destaque", "trending": "Populares", @@ -243,6 +246,7 @@ "try_again": "Por favor, tente novamente", "cancel": "Cancelar", "signout": "Sair da conta", - "signout_modal_title": "Tem certeza?" + "signout_modal_title": "Tem certeza?", + "successfully_signed_out": "Deslogado com sucesso" } } diff --git a/src/main/index.ts b/src/main/index.ts index 33fe128d..b2d07275 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -73,7 +73,7 @@ app.on("browser-window-created", (_, window) => { optimizer.watchWindowShortcuts(window); }); -app.on("second-instance", (_event, commandLine) => { +app.on("second-instance", (_event) => { // Someone tried to run a second instance, we should focus our window. if (WindowManager.mainWindow) { if (WindowManager.mainWindow.isMinimized()) @@ -84,16 +84,16 @@ app.on("second-instance", (_event, commandLine) => { WindowManager.createMainWindow(); } - const [, path] = commandLine.pop()?.split("://") ?? []; - if (path) { - WindowManager.redirect(path); - } + // const [, path] = commandLine.pop()?.split("://") ?? []; + // if (path) { + // WindowManager.redirect(path); + // } }); -app.on("open-url", (_event, url) => { - const [, path] = url.split("://"); - WindowManager.redirect(path); -}); +// app.on("open-url", (_event, url) => { +// const [, path] = url.split("://"); +// WindowManager.redirect(path); +// }); // Quit when all windows are closed, except on macOS. There, it's common // for applications and their menu bar to stay active until the user quits diff --git a/src/renderer/src/app.css.ts b/src/renderer/src/app.css.ts index 65264240..a5f9394b 100644 --- a/src/renderer/src/app.css.ts +++ b/src/renderer/src/app.css.ts @@ -111,6 +111,6 @@ export const titleBar = style({ alignItems: "center", padding: `0 ${SPACING_UNIT * 2}px`, WebkitAppRegion: "drag", - zIndex: "2", + zIndex: "4", borderBottom: `1px solid ${vars.color.border}`, } as ComplexStyleRule); diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index 27671a23..45a0cb43 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -7,6 +7,7 @@ import { useAppSelector, useDownload, useLibrary, + useToast, useUserDetails, } from "@renderer/hooks"; @@ -22,6 +23,7 @@ import { setUserDetails, setProfileBackground, } from "@renderer/features"; +import { useTranslation } from "react-i18next"; export interface AppProps { children: React.ReactNode; @@ -31,6 +33,8 @@ export function App() { const contentRef = useRef(null); const { updateLibrary } = useLibrary(); + const { t } = useTranslation("app"); + const { clearDownload, setLastPacket } = useDownload(); const { fetchUserDetails, updateUserDetails, clearUserDetails } = @@ -49,6 +53,8 @@ export function App() { const toast = useAppSelector((state) => state.toast); + const { showSuccessToast } = useToast(); + useEffect(() => { Promise.all([window.electron.getUserPreferences(), updateLibrary()]).then( ([preferences]) => { @@ -95,25 +101,28 @@ export function App() { }); }, [dispatch, fetchUserDetails]); + const onSignIn = useCallback(() => { + fetchUserDetails().then((response) => { + if (response) { + updateUserDetails(response); + showSuccessToast(t("successfully_signed_in")); + } + }); + }, [fetchUserDetails, t, showSuccessToast, updateUserDetails]); + useEffect(() => { const listeners = [ - window.electron.onSignIn(() => { - fetchUserDetails().then((response) => { - if (response) updateUserDetails(response); - }); - }), + window.electron.onSignIn(onSignIn), window.electron.onLibraryBatchComplete(() => { updateLibrary(); }), - window.electron.onSignOut(() => { - clearUserDetails(); - }), + window.electron.onSignOut(() => clearUserDetails()), ]; return () => { listeners.forEach((unsubscribe) => unsubscribe()); }; - }, [fetchUserDetails, updateUserDetails, updateLibrary, clearUserDetails]); + }, [onSignIn, updateLibrary, clearUserDetails]); const handleSearch = useCallback( (query: string) => { @@ -167,6 +176,13 @@ export function App() { )} + +
@@ -184,13 +200,6 @@ export function App() {
- - ); } diff --git a/src/renderer/src/components/backdrop/backdrop.css.ts b/src/renderer/src/components/backdrop/backdrop.css.ts index 1c95717e..1ccfe12f 100644 --- a/src/renderer/src/components/backdrop/backdrop.css.ts +++ b/src/renderer/src/components/backdrop/backdrop.css.ts @@ -1,7 +1,7 @@ import { keyframes } from "@vanilla-extract/css"; import { recipe } from "@vanilla-extract/recipes"; -import { SPACING_UNIT } from "../../theme.css"; +import { SPACING_UNIT, vars } from "../../theme.css"; export const backdropFadeIn = keyframes({ "0%": { backdropFilter: "blur(0px)", backgroundColor: "rgba(0, 0, 0, 0.5)" }, @@ -30,8 +30,8 @@ export const backdrop = recipe({ display: "flex", justifyContent: "center", alignItems: "center", - zIndex: 1, - top: 0, + zIndex: vars.zIndex.backdrop, + top: "0", padding: `${SPACING_UNIT * 3}px`, backdropFilter: "blur(2px)", transition: "all ease 0.2s", diff --git a/src/renderer/src/components/bottom-panel/bottom-panel.css.ts b/src/renderer/src/components/bottom-panel/bottom-panel.css.ts index a1f5d1a8..e70f3556 100644 --- a/src/renderer/src/components/bottom-panel/bottom-panel.css.ts +++ b/src/renderer/src/components/bottom-panel/bottom-panel.css.ts @@ -12,7 +12,7 @@ export const bottomPanel = style({ transition: "all ease 0.2s", justifyContent: "space-between", position: "relative", - zIndex: "1", + zIndex: vars.zIndex.bottomPanel, }); export const downloadsButton = style({ diff --git a/src/renderer/src/components/toast/toast.css.ts b/src/renderer/src/components/toast/toast.css.ts index 2f4e8d03..a07bb105 100644 --- a/src/renderer/src/components/toast/toast.css.ts +++ b/src/renderer/src/components/toast/toast.css.ts @@ -31,7 +31,7 @@ export const toast = recipe({ display: "flex", flexDirection: "column", justifyContent: "space-between", - zIndex: "0", + zIndex: vars.zIndex.toast, maxWidth: "500px", }, variants: { diff --git a/src/renderer/src/pages/user/user-content.tsx b/src/renderer/src/pages/user/user-content.tsx index 5b4798e7..0c32f989 100644 --- a/src/renderer/src/pages/user/user-content.tsx +++ b/src/renderer/src/pages/user/user-content.tsx @@ -6,7 +6,7 @@ import { SPACING_UNIT, vars } from "@renderer/theme.css"; import { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import SteamLogo from "@renderer/assets/steam-logo.svg?react"; -import { useDate, useUserDetails } from "@renderer/hooks"; +import { useDate, useToast, useUserDetails } from "@renderer/hooks"; import { useNavigate } from "react-router-dom"; import { buildGameDetailsPath } from "@renderer/helpers"; import { PersonIcon, TelescopeIcon } from "@primer/octicons-react"; @@ -28,6 +28,7 @@ export function UserContent({ const { t, i18n } = useTranslation("user_profile"); const { userDetails, profileBackground, signOut } = useUserDetails(); + const { showSuccessToast } = useToast(); const [showEditProfileModal, setShowEditProfileModal] = useState(false); const [showSignOutModal, setShowSignOutModal] = useState(false); @@ -68,7 +69,10 @@ export function UserContent({ }; const handleConfirmSignout = async () => { - signOut(); + await signOut(); + + showSuccessToast(t("successfully_signed_out")); + navigate("/"); }; diff --git a/src/renderer/src/theme.css.ts b/src/renderer/src/theme.css.ts index c748c1c7..6b520614 100644 --- a/src/renderer/src/theme.css.ts +++ b/src/renderer/src/theme.css.ts @@ -21,4 +21,10 @@ export const vars = createGlobalTheme(":root", { body: "14px", small: "12px", }, + zIndex: { + toast: "2", + bottomPanel: "3", + titleBar: "4", + backdrop: "4", + }, });