Skip to content

[UI]: Divide GamePage component into multiple components #2848

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/frontend/screens/Game/GameContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react'

import { GameContextType } from 'frontend/types'

const initialContext: GameContextType = {
appName: 'default',
runner: 'legendary',
gameInfo: null,
gameExtraInfo: null,
gameSettings: null,
gameInstallInfo: null,
is: {
installing: false,
installingUbisoft: false,
launching: false,
linux: false,
linuxNative: false,
mac: false,
macNative: false,
native: false,
moving: false,
notAvailable: false,
notInstallable: false,
notSupportedGame: false,
playing: false,
queued: false,
reparing: false,
sideloaded: false,
syncing: false,
uninstalling: false,
updating: false,
win: false
},
status: undefined,
wikiInfo: null
}

export default React.createContext(initialContext)
57 changes: 57 additions & 0 deletions src/frontend/screens/Game/GamePage/components/AppleWikiInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import GameContext from '../../GameContext'
import { WineBar } from '@mui/icons-material'
import { createNewWindow } from 'frontend/helpers'
import { GameInfo } from 'common/types'

interface Props {
gameInfo: GameInfo
}

const AppleWikiInfo = ({ gameInfo }: Props) => {
const { t } = useTranslation('gamepage')
const { wikiInfo } = useContext(GameContext)

if (!wikiInfo) {
return null
}

const applegamingwiki = wikiInfo.applegamingwiki

if (!applegamingwiki) {
return null
}

const hasAppleInfo = applegamingwiki?.crossoverRating

if (!hasAppleInfo) {
return null
}

return (
<a
role="button"
className="iconWithText"
title={t('info.clickToOpen', 'Click to open')}
onClick={() => {
if (applegamingwiki.crossoverLink) {
createNewWindow(
`https://www.codeweavers.com/compatibility/crossover/${applegamingwiki.crossoverLink}`
)
} else {
createNewWindow(
`https://www.codeweavers.com/compatibility?browse=&app_desc=&company=&rating=&platform=&date_start=&date_end=&name=${gameInfo.title}&search=app#results`
)
}
}}
>
<WineBar />
{t('info.apple-gaming-wiki', 'AppleGamingWiki Rating')}:{' '}
{applegamingwiki.crossoverRating.charAt(0).toUpperCase() +
applegamingwiki.crossoverRating.slice(1)}
</a>
)
}

export default AppleWikiInfo
77 changes: 77 additions & 0 deletions src/frontend/screens/Game/GamePage/components/CloudSavesSync.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import GameContext from '../../GameContext'
import { CloudOff, CloudQueue } from '@mui/icons-material'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCircleInfo } from '@fortawesome/free-solid-svg-icons'
import { GameInfo } from 'common/types'

interface Props {
gameInfo: GameInfo
}

const CloudSavesSync = ({ gameInfo }: Props) => {
const { t } = useTranslation('gamepage')
const { gameSettings, is } = useContext(GameContext)

if (!gameSettings) {
return null
}

if (!gameInfo.is_installed) {
return null
}

if (gameInfo.runner === 'sideload') {
return null
}

if (!gameInfo.cloud_save_enabled) {
return null
}

const cloud_save_enabled = gameInfo.cloud_save_enabled || false
const showCloudSaveInfo = cloud_save_enabled && !is.linuxNative
const { autoSyncSaves } = gameSettings

return (
<>
{showCloudSaveInfo && (
<p
style={{
color: autoSyncSaves ? '#07C5EF' : ''
}}
className="iconWithText"
>
<CloudQueue />
<b>{t('info.syncsaves')}</b>
{': '}
{autoSyncSaves ? t('enabled') : t('disabled')}
</p>
)}
{!showCloudSaveInfo && (
<p
style={{
color: '#F45460'
}}
className="iconWithText"
>
<CloudOff />
<b>{t('info.syncsaves')}</b>
{': '}
{t('cloud_save_unsupported', 'Unsupported')}
<FontAwesomeIcon
className="helpIcon"
icon={faCircleInfo}
title={t(
'help.cloud_save_unsupported',
'This game does not support cloud saves. This information is provided by the game developers. Some games do implement their own cloud save system'
)}
/>
</p>
)}
</>
)
}

export default CloudSavesSync
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import GameContext from '../../GameContext'
import {
CheckCircle,
DoNotDisturb,
Error,
HelpOutline,
WineBar
} from '@mui/icons-material'
import { createNewWindow } from 'frontend/helpers'
import { GameInfo } from 'common/types'

interface Props {
gameInfo: GameInfo
}

const CompatibilityInfo = ({ gameInfo }: Props) => {
const { t } = useTranslation('gamepage')
const { wikiInfo } = useContext(GameContext)

if (!wikiInfo) {
return null
}

const steamInfo = wikiInfo.steamInfo

if (!steamInfo) {
return null
}

const hasProtonDB = steamInfo?.compatibilityLevel

// check if we got a number. zero is also valid.
const hasSteamDeckCompat = Number.isFinite(steamInfo?.steamDeckCatagory)
const steamLevelNames = [
// use outline for help icon because steam does it aswell
// colors come from the steam verified icons
<HelpOutline
key={0}
style={{ marginLeft: '5px', cursor: 'default', color: '#a0a5a8' }}
/>,
<DoNotDisturb
key={1}
style={{ marginLeft: '5px', cursor: 'default', color: '#a0a5a8' }}
/>,
<Error
key={2}
style={{ marginLeft: '5px', cursor: 'default', color: '#ffc82c' }}
/>,
<CheckCircle
key={3}
style={{ marginLeft: '5px', cursor: 'default', color: '#58be42' }}
/>
]

let protonDBurl = `https://www.protondb.com/search?q=${gameInfo.title}`
if (wikiInfo.pcgamingwiki?.steamID) {
protonDBurl = `https://www.protondb.com/app/${wikiInfo.pcgamingwiki?.steamID}`
}

return (
<>
{hasProtonDB && (
<a
role="button"
onClick={() => {
createNewWindow(protonDBurl)
}}
title={t('info.clickToOpen', 'Click to open')}
className="iconWithText"
>
<WineBar />
{t(
'info.protondb-compatibility-info',
'Proton Compatibility Tier'
)}:{' '}
{steamInfo!.compatibilityLevel!.charAt(0).toUpperCase() +
steamInfo!.compatibilityLevel!.slice(1)}
</a>
)}
{hasSteamDeckCompat && (
<a className="iconWithText" style={{ cursor: 'default' }}>
<WineBar />
{t(
'info.steamdeck-compatibility-info',
'SteamDeck Compatibility'
)}: {steamLevelNames[steamInfo?.steamDeckCatagory ?? 3]}
</a>
)}
</>
)
}

export default CompatibilityInfo
21 changes: 21 additions & 0 deletions src/frontend/screens/Game/GamePage/components/Description.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { useContext } from 'react'
import GameContext from '../../GameContext'
import { useTranslation } from 'react-i18next'

const Description = () => {
const { t } = useTranslation('gamepage')
const { gameExtraInfo, runner } = useContext(GameContext)

if (runner === 'sideload') {
return null
}

const description =
gameExtraInfo?.about?.shortDescription ||
gameExtraInfo?.about?.description ||
t('generic.noDescription', 'No description available')

return <div className="summary">{description}</div>
}

export default Description
19 changes: 19 additions & 0 deletions src/frontend/screens/Game/GamePage/components/Developer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React, { useContext } from 'react'
import GameContext from '../../GameContext'
import { GameInfo } from 'common/types'

interface Props {
gameInfo: GameInfo
}

const Developer = ({ gameInfo }: Props) => {
const { runner } = useContext(GameContext)

if (runner === 'sideload') {
return null
}

return <div className="developer">{gameInfo.developer}</div>
}

export default Developer
Loading