diff --git a/src/frontend/screens/Library/components/GameCard/index.tsx b/src/frontend/screens/Library/components/GameCard/index.tsx
index a893446c01..8dc2a2b85d 100644
--- a/src/frontend/screens/Library/components/GameCard/index.tsx
+++ b/src/frontend/screens/Library/components/GameCard/index.tsx
@@ -117,6 +117,8 @@ const GameCard = ({
const { status, folder, label } = hasStatus(appName, gameInfo, size)
+ const isBrowserGame = gameInfo.install.platform === 'Browser'
+
useEffect(() => {
setIsLaunching(false)
const updateGameInfo = async () => {
@@ -311,15 +313,12 @@ const GameCard = ({
// settings
label: t('submenu.settings', 'Settings'),
onclick: () => setIsSettingsModalOpen(true, 'settings', gameInfo),
- show: isInstalled && !isUninstalling
+ show: isInstalled && !isUninstalling && !isBrowserGame
},
{
label: t('submenu.logs', 'Logs'),
onclick: () => setIsSettingsModalOpen(true, 'log', gameInfo),
- show:
- isInstalled &&
- !isUninstalling &&
- gameInfo.install.platform !== 'Browser'
+ show: isInstalled && !isUninstalling && !isBrowserGame
},
{
// hide
@@ -385,6 +384,8 @@ const GameCard = ({
)
}
+ const showSettingsButton = isInstalled && !isUninstalling && !isBrowserGame
+
return (
{showUninstallModal && (
@@ -464,7 +465,7 @@ const GameCard = ({
)}
- {isInstalled && !isUninstalling && (
+ {showSettingsButton && (
<>
{
const { t } = useTranslation()
@@ -12,6 +13,11 @@ const BattlEyeRuntime = () => {
'battlEyeRuntime',
false
)
+ const { platform } = useContext(ContextProvider)
+
+ if (platform !== 'linux') {
+ return null
+ }
const handleBattlEyeRuntime = async () => {
if (!battlEyeRuntime) {
diff --git a/src/frontend/screens/Settings/components/EacRuntime.tsx b/src/frontend/screens/Settings/components/EacRuntime.tsx
index 116fed17ec..ee039b17b0 100644
--- a/src/frontend/screens/Settings/components/EacRuntime.tsx
+++ b/src/frontend/screens/Settings/components/EacRuntime.tsx
@@ -11,7 +11,11 @@ const EacRuntime = () => {
const [installing, setInstalling] = useState(false)
const [eacRuntime, setEacRuntime] = useSetting('eacRuntime', false)
const [useGameMode, setUseGameMode] = useSetting('useGameMode', false)
- const { showDialogModal } = useContext(ContextProvider)
+ const { showDialogModal, platform } = useContext(ContextProvider)
+
+ if (platform !== 'linux') {
+ return null
+ }
const handleEacRuntime = async () => {
if (!eacRuntime) {
diff --git a/src/frontend/screens/Settings/components/SettingsModal/index.scss b/src/frontend/screens/Settings/components/SettingsModal/index.scss
index eb7d819789..f2c6ec7d76 100644
--- a/src/frontend/screens/Settings/components/SettingsModal/index.scss
+++ b/src/frontend/screens/Settings/components/SettingsModal/index.scss
@@ -2,8 +2,9 @@
width: 65vw;
display: flex;
flex-direction: column;
- justify-content: space-between;
+ flex: 1 1 60vh;
max-width: 800px;
+ min-height: 50vh;
.log-box {
width: 100%;
diff --git a/src/frontend/screens/Settings/components/SettingsModal/index.tsx b/src/frontend/screens/Settings/components/SettingsModal/index.tsx
index 1af5db7173..7096cc14a3 100644
--- a/src/frontend/screens/Settings/components/SettingsModal/index.tsx
+++ b/src/frontend/screens/Settings/components/SettingsModal/index.tsx
@@ -51,7 +51,7 @@ function SettingsModal({ gameInfo, type }: Props) {
- {type === 'settings' ? : }
+ {type === 'settings' ? : }
diff --git a/src/frontend/screens/Settings/components/Tools/index.scss b/src/frontend/screens/Settings/components/Tools/index.scss
index 1b1a42cfdc..87fcc85919 100644
--- a/src/frontend/screens/Settings/components/Tools/index.scss
+++ b/src/frontend/screens/Settings/components/Tools/index.scss
@@ -8,6 +8,13 @@
.button {
padding-block: var(--space-lg);
margin: 0 var(--space-3xs);
+ display: flex;
+ align-items: center;
+ border-radius: 8px;
+ }
+
+ .active {
+ animation: fading 1s alternate infinite;
}
.drag {
@@ -19,8 +26,9 @@
flex-direction: column;
text-decoration: none;
white-space: nowrap;
+ justify-content: center;
- & > span {
+ & span {
transition: 350ms;
font-size: var(--text-xs);
font-style: italic;
@@ -29,3 +37,19 @@
}
}
}
+
+@keyframes fading {
+ 0% {
+ opacity: 0.2;
+ }
+
+ 50% {
+ opacity: 0.5;
+ background-color: var(--navbar-background);
+ color: var(--text-default);
+ }
+
+ 100% {
+ opacity: 1;
+ }
+}
diff --git a/src/frontend/screens/Settings/components/Tools/index.tsx b/src/frontend/screens/Settings/components/Tools/index.tsx
index 9b2bf70554..807e94fcdf 100644
--- a/src/frontend/screens/Settings/components/Tools/index.tsx
+++ b/src/frontend/screens/Settings/components/Tools/index.tsx
@@ -14,6 +14,7 @@ export default function Tools() {
const { t } = useTranslation()
const [winecfgRunning, setWinecfgRunning] = useState(false)
const [winetricksRunning, setWinetricksRunning] = useState(false)
+ const [runExeRunning, setRunExeRunning] = useState(false)
const [progress, setProgress] = useState([])
const { appName, runner, isDefault } = useContext(SettingsContext)
const { platform } = useContext(ContextProvider)
@@ -25,20 +26,26 @@ export default function Tools() {
type Tool = 'winecfg' | 'winetricks' | string
async function callTools(tool: Tool, exe?: string) {
- if (tool === 'winetricks') {
- setWinetricksRunning(true)
+ const toolStates = {
+ winetricks: setWinetricksRunning,
+ winecfg: setWinecfgRunning,
+ runExe: setRunExeRunning
}
- if (tool === 'winecfg') {
- setWinecfgRunning(true)
+
+ if (tool in toolStates) {
+ toolStates[tool](true)
}
+
await window.api.callTool({
tool,
exe,
appName,
runner
})
- setWinetricksRunning(false)
- setWinecfgRunning(false)
+
+ if (tool in toolStates) {
+ toolStates[tool](false)
+ }
}
useEffect(() => {
@@ -131,11 +138,12 @@ export default function Tools() {
dropHandler(ev)}
onDragOver={(ev) => dragOverHandler(ev)}
- className="button outline drag"
+ className={classNames('button outline drag', {
+ active: runExeRunning
+ })}
onClick={handleRunExe}
>
- {t('setting.runexe.title')}
-
+ {t('setting.runexe.title')}
{t('setting.runexe.message')}
diff --git a/src/frontend/screens/Settings/index.tsx b/src/frontend/screens/Settings/index.tsx
index dd85697ee3..182bc22568 100644
--- a/src/frontend/screens/Settings/index.tsx
+++ b/src/frontend/screens/Settings/index.tsx
@@ -121,7 +121,7 @@ function Settings() {
{isGeneralSettings &&
}
- {isGamesSettings &&
}
+ {isGamesSettings &&
}
{isSyncSettings &&
}
{isAdvancedSetting &&
}
{isLogSettings &&
}
diff --git a/src/frontend/screens/Settings/sections/GamesSettings/index.scss b/src/frontend/screens/Settings/sections/GamesSettings/index.scss
index 6c51b87c15..e1657c3657 100644
--- a/src/frontend/screens/Settings/sections/GamesSettings/index.scss
+++ b/src/frontend/screens/Settings/sections/GamesSettings/index.scss
@@ -26,6 +26,26 @@
}
}
+.MuiTabs-root {
+ padding-bottom: var(--space-xs);
+
+ .MuiTabs-scroller {
+ .MuiTabs-indicator {
+ background-color: var(--accent);
+ }
+
+ .MuiTabs-flexContainer {
+ .MuiTab-root {
+ color: var(--text-default);
+ }
+
+ .Mui-selected {
+ color: var(--accent);
+ }
+ }
+ }
+}
+
// details, should have an hover effect and a pointer cursor and also the summary should be bold and have a background color
details {
cursor: pointer;
diff --git a/src/frontend/screens/Settings/sections/GamesSettings/index.tsx b/src/frontend/screens/Settings/sections/GamesSettings/index.tsx
index 1b2e44f396..fc54773f7e 100644
--- a/src/frontend/screens/Settings/sections/GamesSettings/index.tsx
+++ b/src/frontend/screens/Settings/sections/GamesSettings/index.tsx
@@ -37,25 +37,95 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faInfoCircle } from '@fortawesome/free-solid-svg-icons'
import useSetting from 'frontend/hooks/useSetting'
import { defaultWineVersion } from '../..'
-import Collapsible from 'frontend/components/UI/Collapsible/Collapsible'
import SyncSaves from '../SyncSaves'
import FooterInfo from '../FooterInfo'
+import { Tabs, Tab } from '@mui/material'
+import { GameInfo } from 'common/types'
-type Props = {
- useDetails?: boolean
+type TabPanelProps = {
+ children?: React.ReactNode
+ index: string
+ value: string
}
-export default function GamesSettings({ useDetails = true }: Props) {
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props
+
+ return (
+
+ {value === index &&
{children}
}
+
+ )
+}
+
+const windowsPlatforms = ['Win32', 'Windows', 'windows']
+function getStartingTab(platform: string, gameInfo?: GameInfo | null): string {
+ if (!gameInfo) {
+ if (platform !== 'win32') {
+ return 'wine'
+ }
+ return 'advanced'
+ }
+ if (platform === 'win32') {
+ return 'advanced'
+ } else if (windowsPlatforms.includes(gameInfo?.install.platform || '')) {
+ return 'wine'
+ } else if (platform === 'darwin') {
+ return 'advanced'
+ } else {
+ return 'other'
+ }
+}
+
+export default function GamesSettings() {
const { t } = useTranslation()
const { platform } = useContext(ContextProvider)
const { isDefault, gameInfo } = useContext(SettingsContext)
const [wineVersion] = useSetting('wineVersion', defaultWineVersion)
- const [nativeGame, setNativeGame] = useState(false)
+ const [isNative, setIsNative] = useState(false)
const isLinux = platform === 'linux'
const isWin = platform === 'win32'
const isCrossover = wineVersion?.type === 'crossover'
const hasCloudSaves =
gameInfo?.cloud_save_enabled && gameInfo.install.platform !== 'linux'
+ const isBrowserGame = gameInfo?.install.platform === 'Browser'
+ const isSideloaded = gameInfo?.runner === 'sideload'
+
+ function shouldShowSettings(tab: 'wine' | 'other'): boolean {
+ if (tab === 'wine') {
+ if (isWin || isNative || isBrowserGame) {
+ return false
+ }
+ return true
+ }
+
+ if (isLinux) {
+ return true
+ }
+ return false
+ }
+
+ // Get the latest used tab index for the current game
+ const localStorageKey = gameInfo
+ ? `${gameInfo!.app_name}-setting_tab`
+ : 'default'
+ const latestTabIndex =
+ localStorage.getItem(localStorageKey) || getStartingTab(platform, gameInfo)
+ const [value, setValue] = useState(latestTabIndex)
+
+ const handleChange = (
+ event: React.ChangeEvent
,
+ newValue: string
+ ) => {
+ setValue(newValue)
+ // Store the latest used tab index for the current game
+ localStorage.setItem(localStorageKey, newValue.toString())
+ }
useEffect(() => {
if (gameInfo) {
@@ -64,12 +134,15 @@ export default function GamesSettings({ useDetails = true }: Props) {
appName: gameInfo?.app_name,
runner: gameInfo?.runner
})
- setNativeGame(isNative)
+ setIsNative(isNative)
}
getIsNative()
}
}, [])
+ const showOtherTab = shouldShowSettings('other')
+ const showWineTab = shouldShowSettings('wine')
+
return (
<>
{isDefault && (
@@ -82,101 +155,85 @@ export default function GamesSettings({ useDetails = true }: Props) {
)}
- {!nativeGame && (
- <>
-
-
-
-
-
- {!isCrossover && (
- <>
-
- {isLinux && (
- <>
-
-
-
-
-
-
-
- >
- )}
-
- >
- )}
-
- >
- )}
-
-
-
-
-
-
- {!nativeGame && }
+ {showWineTab && }
+ {showOtherTab && (
+
+ )}
+
+
+ {hasCloudSaves && (
+
+ )}
+
- {!isWin && !nativeGame && (
+
+
+
+
+ {!isCrossover && (
<>
-
-
+
{isLinux && (
<>
-
-
-
-
-
-
-
+
+
>
)}
+
+
+
+
+
>
)}
+
-
-
- {isLinux && }
-
+
+ {!isNative && }
+
+
+
+
+ {!isNative && (
+ <>
+
+
+ >
+ )}
+
-
-
-
-
-
-
-
-
+
+ {!isSideloaded && (
+ <>
+
+
+ >
+ )}
+
+
+
+ {!isSideloaded && }
+
-
-
-
- {hasCloudSaves && (
-
-
-
- )}
+
+
+
-
+ {!isDefault && }
>
)
}