mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
feat: show running game on sidebar
This commit is contained in:
parent
e933cec888
commit
4a59a52174
13 changed files with 85 additions and 12 deletions
|
@ -243,6 +243,7 @@
|
||||||
"try_again": "Please, try again",
|
"try_again": "Please, try again",
|
||||||
"signout_modal_title": "Are you sure?",
|
"signout_modal_title": "Are you sure?",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"signout": "Sign Out"
|
"signout": "Sign Out",
|
||||||
|
"playing_for": "Playing for {{amount}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,6 +243,7 @@
|
||||||
"try_again": "Por favor, tente novamente",
|
"try_again": "Por favor, tente novamente",
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
"signout": "Sair da conta",
|
"signout": "Sair da conta",
|
||||||
"signout_modal_title": "Tem certeza?"
|
"signout_modal_title": "Tem certeza?",
|
||||||
|
"playing_for": "Jogando por {{amount}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,6 @@ const updateProfile = async (
|
||||||
displayName: string,
|
displayName: string,
|
||||||
newProfileImagePath: string | null
|
newProfileImagePath: string | null
|
||||||
): Promise<UserProfile> => {
|
): Promise<UserProfile> => {
|
||||||
console.log(newProfileImagePath);
|
|
||||||
|
|
||||||
if (!newProfileImagePath) {
|
if (!newProfileImagePath) {
|
||||||
return (await patchUserProfile(displayName)).data;
|
return (await patchUserProfile(displayName)).data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ export class HydraApi {
|
||||||
this.instance.interceptors.request.use(
|
this.instance.interceptors.request.use(
|
||||||
(request) => {
|
(request) => {
|
||||||
console.log(" ---- REQUEST -----");
|
console.log(" ---- REQUEST -----");
|
||||||
console.log(request.method, request.url, request.data);
|
console.log(request.method, request.url, request.headers, request.data);
|
||||||
return request;
|
return request;
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
closeToast,
|
closeToast,
|
||||||
setUserDetails,
|
setUserDetails,
|
||||||
setProfileBackground,
|
setProfileBackground,
|
||||||
|
setRunningGame,
|
||||||
} from "@renderer/features";
|
} from "@renderer/features";
|
||||||
|
|
||||||
export interface AppProps {
|
export interface AppProps {
|
||||||
|
@ -29,7 +30,7 @@ export interface AppProps {
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
const contentRef = useRef<HTMLDivElement>(null);
|
const contentRef = useRef<HTMLDivElement>(null);
|
||||||
const { updateLibrary } = useLibrary();
|
const { updateLibrary, library } = useLibrary();
|
||||||
|
|
||||||
const { clearDownload, setLastPacket } = useDownload();
|
const { clearDownload, setLastPacket } = useDownload();
|
||||||
|
|
||||||
|
@ -95,6 +96,30 @@ export function App() {
|
||||||
});
|
});
|
||||||
}, [dispatch, fetchUserDetails]);
|
}, [dispatch, fetchUserDetails]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = window.electron.onGamesRunning((gamesIds) => {
|
||||||
|
if (gamesIds.length) {
|
||||||
|
const lastGame = gamesIds.at(-1);
|
||||||
|
const libraryGame = library.find((library) => library.id == lastGame);
|
||||||
|
|
||||||
|
if (libraryGame) {
|
||||||
|
dispatch(
|
||||||
|
setRunningGame({
|
||||||
|
...libraryGame,
|
||||||
|
sessionStartTimestamp: new Date().getTime(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dispatch(setRunningGame(null));
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const listeners = [
|
const listeners = [
|
||||||
window.electron.onSignIn(() => {
|
window.electron.onSignIn(() => {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { useNavigate } from "react-router-dom";
|
||||||
import { PersonIcon } from "@primer/octicons-react";
|
import { PersonIcon } from "@primer/octicons-react";
|
||||||
import * as styles from "./sidebar-profile.css";
|
import * as styles from "./sidebar-profile.css";
|
||||||
|
|
||||||
import { useUserDetails } from "@renderer/hooks";
|
import { useAppSelector, useUserDetails } from "@renderer/hooks";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
export function SidebarProfile() {
|
export function SidebarProfile() {
|
||||||
|
@ -10,6 +10,8 @@ export function SidebarProfile() {
|
||||||
|
|
||||||
const { userDetails, profileBackground } = useUserDetails();
|
const { userDetails, profileBackground } = useUserDetails();
|
||||||
|
|
||||||
|
const { runningGame } = useAppSelector((state) => state.runningGame);
|
||||||
|
|
||||||
const handleButtonClick = () => {
|
const handleButtonClick = () => {
|
||||||
if (userDetails === null) {
|
if (userDetails === null) {
|
||||||
window.electron.openExternal("https://auth.hydra.losbroxas.org");
|
window.electron.openExternal("https://auth.hydra.losbroxas.org");
|
||||||
|
@ -48,7 +50,21 @@ export function SidebarProfile() {
|
||||||
<p className={styles.profileButtonTitle}>
|
<p className={styles.profileButtonTitle}>
|
||||||
{userDetails ? userDetails.displayName : "Sign in"}
|
{userDetails ? userDetails.displayName : "Sign in"}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{userDetails && runningGame && (
|
||||||
|
<div>
|
||||||
|
<small>{runningGame.title}</small>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{userDetails && runningGame && (
|
||||||
|
<img
|
||||||
|
width={24}
|
||||||
|
style={{ borderRadius: 4 }}
|
||||||
|
src={runningGame.iconUrl}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
|
@ -111,13 +111,13 @@ export function GameDetailsContextProvider({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const listeners = [
|
const listeners = [
|
||||||
window.electron.onGamesRunning((gamesIds) => {
|
window.electron.onGamesRunning((gamesIds) => {
|
||||||
const newIsGameRunning = !!game?.id && gamesIds.includes(game.id);
|
const updatedIsGameRunning = !!game?.id && gamesIds.includes(game.id);
|
||||||
|
|
||||||
if (isGameRunning != newIsGameRunning) {
|
if (isGameRunning != updatedIsGameRunning) {
|
||||||
updateGame();
|
updateGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
setisGameRunning(newIsGameRunning);
|
setisGameRunning(updatedIsGameRunning);
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -5,3 +5,4 @@ export * from "./download-slice";
|
||||||
export * from "./window-slice";
|
export * from "./window-slice";
|
||||||
export * from "./toast-slice";
|
export * from "./toast-slice";
|
||||||
export * from "./user-details-slice";
|
export * from "./user-details-slice";
|
||||||
|
export * from "./running-game-slice";
|
||||||
|
|
22
src/renderer/src/features/running-game-slice.ts
Normal file
22
src/renderer/src/features/running-game-slice.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||||
|
import { RunningGame } from "@types";
|
||||||
|
|
||||||
|
export interface RunningGameState {
|
||||||
|
runningGame: RunningGame | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: RunningGameState = {
|
||||||
|
runningGame: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const runningGameSlice = createSlice({
|
||||||
|
name: "running-game",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setRunningGame: (state, action: PayloadAction<RunningGame | null>) => {
|
||||||
|
state.runningGame = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { setRunningGame } = runningGameSlice.actions;
|
|
@ -72,6 +72,7 @@ export const profileAvatarEditOverlay = style({
|
||||||
export const profileInformation = style({
|
export const profileInformation = style({
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
|
gap: `${SPACING_UNIT}px`,
|
||||||
alignItems: "flex-start",
|
alignItems: "flex-start",
|
||||||
color: "#c0c1c7",
|
color: "#c0c1c7",
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,8 +28,6 @@ export const User = () => {
|
||||||
getUserProfile();
|
getUserProfile();
|
||||||
}, [getUserProfile]);
|
}, [getUserProfile]);
|
||||||
|
|
||||||
console.log(userProfile);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SkeletonTheme baseColor={vars.color.background} highlightColor="#444">
|
<SkeletonTheme baseColor={vars.color.background} highlightColor="#444">
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
userPreferencesSlice,
|
userPreferencesSlice,
|
||||||
toastSlice,
|
toastSlice,
|
||||||
userDetailsSlice,
|
userDetailsSlice,
|
||||||
|
runningGameSlice,
|
||||||
} from "@renderer/features";
|
} from "@renderer/features";
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
|
@ -18,6 +19,7 @@ export const store = configureStore({
|
||||||
download: downloadSlice.reducer,
|
download: downloadSlice.reducer,
|
||||||
toast: toastSlice.reducer,
|
toast: toastSlice.reducer,
|
||||||
userDetails: userDetailsSlice.reducer,
|
userDetails: userDetailsSlice.reducer,
|
||||||
|
runningGame: runningGameSlice.reducer,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,14 @@ export interface Game {
|
||||||
|
|
||||||
export type LibraryGame = Omit<Game, "repacks">;
|
export type LibraryGame = Omit<Game, "repacks">;
|
||||||
|
|
||||||
|
export interface RunningGame {
|
||||||
|
title: string;
|
||||||
|
iconUrl: string;
|
||||||
|
objectID: string;
|
||||||
|
shop: GameShop;
|
||||||
|
sessionStartTimestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DownloadProgress {
|
export interface DownloadProgress {
|
||||||
downloadSpeed: number;
|
downloadSpeed: number;
|
||||||
timeRemaining: number;
|
timeRemaining: number;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue