mirror of
				https://github.com/hydralauncher/hydra.git
				synced 2025-03-09 15:40:26 +00:00 
			
		
		
		
	show toast if game has no executable selected
This commit is contained in:
		
							parent
							
								
									58dff75f64
								
							
						
					
					
						commit
						4f4ada8d54
					
				
					 9 changed files with 40 additions and 26 deletions
				
			
		| 
						 | 
				
			
			@ -5,7 +5,7 @@ import { useLocation, useNavigate } from "react-router-dom";
 | 
			
		|||
import type { LibraryGame } from "@types";
 | 
			
		||||
 | 
			
		||||
import { TextField } from "@renderer/components";
 | 
			
		||||
import { useDownload, useLibrary } from "@renderer/hooks";
 | 
			
		||||
import { useDownload, useLibrary, useToast } from "@renderer/hooks";
 | 
			
		||||
 | 
			
		||||
import { routes } from "./routes";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +36,8 @@ export function Sidebar() {
 | 
			
		|||
 | 
			
		||||
  const { lastPacket, progress } = useDownload();
 | 
			
		||||
 | 
			
		||||
  const { showWarningToast } = useToast();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    updateLibrary();
 | 
			
		||||
  }, [lastPacket?.game.id, updateLibrary]);
 | 
			
		||||
| 
						 | 
				
			
			@ -131,8 +133,12 @@ export function Sidebar() {
 | 
			
		|||
      navigate(path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (event.detail == 2 && game.executablePath) {
 | 
			
		||||
      window.electron.openGame(game.id, game.executablePath);
 | 
			
		||||
    if (event.detail == 2) {
 | 
			
		||||
      if (game.executablePath) {
 | 
			
		||||
        window.electron.openGame(game.id, game.executablePath);
 | 
			
		||||
      } else {
 | 
			
		||||
        showWarningToast("Jogo não possui executável selecionado");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,3 +81,7 @@ export const successIcon = style({
 | 
			
		|||
export const errorIcon = style({
 | 
			
		||||
  color: vars.color.danger,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const warningIcon = style({
 | 
			
		||||
  color: vars.color.warning,
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import { useCallback, useEffect, useRef, useState } from "react";
 | 
			
		||||
import {
 | 
			
		||||
  AlertIcon,
 | 
			
		||||
  CheckCircleFillIcon,
 | 
			
		||||
  XCircleFillIcon,
 | 
			
		||||
  XIcon,
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +12,7 @@ import { SPACING_UNIT } from "@renderer/theme.css";
 | 
			
		|||
export interface ToastProps {
 | 
			
		||||
  visible: boolean;
 | 
			
		||||
  message: string;
 | 
			
		||||
  type: "success" | "error";
 | 
			
		||||
  type: "success" | "error" | "warning";
 | 
			
		||||
  onClose: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,6 +85,8 @@ export function Toast({ visible, message, type, onClose }: ToastProps) {
 | 
			
		|||
          )}
 | 
			
		||||
 | 
			
		||||
          {type === "error" && <XCircleFillIcon className={styles.errorIcon} />}
 | 
			
		||||
 | 
			
		||||
          {type === "warning" && <AlertIcon className={styles.warningIcon} />}
 | 
			
		||||
          <span style={{ fontWeight: "bold" }}>{message}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,5 +29,17 @@ export function useToast() {
 | 
			
		|||
    [dispatch]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return { showSuccessToast, showErrorToast };
 | 
			
		||||
  const showWarningToast = useCallback(
 | 
			
		||||
    (message: string) => {
 | 
			
		||||
      dispatch(
 | 
			
		||||
        showToast({
 | 
			
		||||
          message,
 | 
			
		||||
          type: "warning",
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    [dispatch]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return { showSuccessToast, showErrorToast, showWarningToast };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,6 @@ export const heroPanelAction = style({
 | 
			
		|||
 | 
			
		||||
export const separator = style({
 | 
			
		||||
  width: "1px",
 | 
			
		||||
  backgroundColor: vars.color.border,
 | 
			
		||||
  backgroundColor: vars.color.muted,
 | 
			
		||||
  margin: `${SPACING_UNIT / 2}px 0`,
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,8 +35,9 @@ export function HeroPanel() {
 | 
			
		|||
  const getInfo = () => {
 | 
			
		||||
    if (isGameDeleting(game?.id ?? -1)) return <p>{t("deleting")}</p>;
 | 
			
		||||
 | 
			
		||||
    if (game && (game.progress === 1 || !game.status))
 | 
			
		||||
    if (game && (game.progress === 1 || !game.status)) {
 | 
			
		||||
      return <HeroPanelPlaytime />;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (game?.status === "active") {
 | 
			
		||||
      if (lastPacket?.isDownloadingMetadata && isGameDownloading) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,11 +3,11 @@ import { SPACING_UNIT } from "../../../theme.css";
 | 
			
		|||
 | 
			
		||||
export const optionsContainer = style({
 | 
			
		||||
  display: "flex",
 | 
			
		||||
  gap: `${SPACING_UNIT}px`,
 | 
			
		||||
  gap: `${SPACING_UNIT * 2}px`,
 | 
			
		||||
  flexDirection: "column",
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const downloadSourceField = style({
 | 
			
		||||
export const gameOptionRow = style({
 | 
			
		||||
  display: "flex",
 | 
			
		||||
  gap: `${SPACING_UNIT}px`,
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,8 @@
 | 
			
		|||
import { useContext, useState } from "react";
 | 
			
		||||
import { useTranslation } from "react-i18next";
 | 
			
		||||
 | 
			
		||||
import { Button, Modal, TextField } from "@renderer/components";
 | 
			
		||||
import type { Game } from "@types";
 | 
			
		||||
 | 
			
		||||
import * as styles from "./game-options-modal.css";
 | 
			
		||||
 | 
			
		||||
import { SPACING_UNIT } from "../../../theme.css";
 | 
			
		||||
import { gameDetailsContext } from "../game-details.context";
 | 
			
		||||
import {
 | 
			
		||||
  FileDirectoryOpenFillIcon,
 | 
			
		||||
| 
						 | 
				
			
			@ -80,15 +76,8 @@ export function GameOptionsModal({
 | 
			
		|||
          deleteGame={handleDeleteGame}
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
        <div
 | 
			
		||||
          style={{
 | 
			
		||||
            display: "flex",
 | 
			
		||||
            flexDirection: "column",
 | 
			
		||||
            gap: `${SPACING_UNIT}px`,
 | 
			
		||||
            width: "100%",
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <div className={styles.downloadSourceField}>
 | 
			
		||||
        <div className={styles.optionsContainer}>
 | 
			
		||||
          <div className={styles.gameOptionRow}>
 | 
			
		||||
            <Button
 | 
			
		||||
              onClick={openRepacksModal}
 | 
			
		||||
              theme="outline"
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +86,7 @@ export function GameOptionsModal({
 | 
			
		|||
              {t("open_download_options")}
 | 
			
		||||
            </Button>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div className={styles.downloadSourceField}>
 | 
			
		||||
          <div className={styles.gameOptionRow}>
 | 
			
		||||
            <TextField
 | 
			
		||||
              label="Caminho do executável"
 | 
			
		||||
              value={game.executablePath || ""}
 | 
			
		||||
| 
						 | 
				
			
			@ -137,10 +126,8 @@ export function GameOptionsModal({
 | 
			
		|||
            </Button>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div className={styles.downloadSourceField}></div>
 | 
			
		||||
 | 
			
		||||
          {game.folderName && (
 | 
			
		||||
            <div className={styles.downloadSourceField}>
 | 
			
		||||
            <div className={styles.gameOptionRow}>
 | 
			
		||||
              <TextField
 | 
			
		||||
                label={t("installer_path")}
 | 
			
		||||
                value={`${game.downloadPath}\\${game.folderName}`}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ export const [themeClass, vars] = createTheme({
 | 
			
		|||
    border: "#424244",
 | 
			
		||||
    success: "#1c9749",
 | 
			
		||||
    danger: "#e11d48",
 | 
			
		||||
    warning: "#ffc107",
 | 
			
		||||
  },
 | 
			
		||||
  opacity: {
 | 
			
		||||
    disabled: "0.5",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue