Skip to content

Move Games to another Folder #121

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 1 commit into from
Jan 28, 2021
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: 36 additions & 2 deletions electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import {
} from 'electron'
import { AppSettings, Game, InstalledInfo, KeyImage } from './types.js'

const { showMessageBox, showErrorBox } = dialog
const { showMessageBox, showErrorBox, showOpenDialog } = dialog
let mainWindow: BrowserWindow = null

function createWindow() {
Expand Down Expand Up @@ -406,14 +406,47 @@ ipcMain.on('getLog', (event, appName) =>
spawn('xdg-open', [`${heroicGamesConfigPath}/${appName}-lastPlay.log`])
)

const installed = `${legendaryConfigPath}/installed.json`

ipcMain.handle('moveInstall', async (event, appName: string) => {
const { filePaths } = await showOpenDialog({
title: 'Choose where you want to move',
buttonLabel: 'Choose',
properties: ['openDirectory'],
})

if (filePaths[0]) {
// @ts-ignore
const file = JSON.parse(readFileSync(installed))
const installedGames: Game[] = Object.values(file)
const { install_path } = installedGames.filter(
(game) => game.app_name === appName
)[0]

const splitPath = install_path.split('/')
const installFolder = splitPath[splitPath.length - 1]
const newPath = `${filePaths[0]}/${installFolder}`
const game: Game = { ...file[appName], install_path: newPath }
const modifiedInstall = { ...file, [appName]: game }
return await execAsync(`mv -f ${install_path} ${newPath}`)
.then(() => {
console.log('moved')
writeFile(installed, JSON.stringify(modifiedInstall, null, 2), () =>
console.log('file updated')
)
})
.catch(console.log)
}
return
})

ipcMain.handle('readFile', async (event, file) => {
const loggedIn = isLoggedIn()

if (!isLoggedIn) {
return { user: { displayName: null }, library: [] }
}

const installed = `${legendaryConfigPath}/installed.json`
const files: any = {
// @ts-ignore
user: loggedIn ? JSON.parse(readFileSync(userInfo)) : { displayName: null },
Expand Down Expand Up @@ -468,6 +501,7 @@ ipcMain.handle('readFile', async (event, file) => {
const art_square = gameBoxTall ? gameBoxTall.url : fallBackImage

const installedGames: Game[] = Object.values(files.installed)

const isInstalled = Boolean(
installedGames.filter((game) => game.app_name === app_name).length
)
Expand Down
20 changes: 10 additions & 10 deletions electron/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,14 @@ const launchGame = async (appName: any) => {
prefix = isProton ? '' : `--wine-prefix ${winePrefix}`

const options = {
fps: showFps ? ` DXVK_HUD=fps` : '',
audio: audioFix ? ` PULSE_LATENCY_MSEC=60` : '',
showMangohud: showMangohud ? ` MANGOHUD=1` : '',
proton: isProton ? ` STEAM_COMPAT_DATA_PATH=${winePrefix}` : '',
other: otherOptions ? otherOptions : '',
fps: showFps ? `DXVK_HUD=fps` : '',
audio: audioFix ? `PULSE_LATENCY_MSEC=60` : '',
showMangohud: showMangohud ? `MANGOHUD=1` : '',
proton: isProton ? `STEAM_COMPAT_DATA_PATH=${winePrefix}` : '',
}

envVars = otherOptions
.concat(Object.values(options).join(''))
.replace(' ', '')
envVars = Object.values(options).join(' ')
if (isProton) {
console.log(
`\n You are using Proton, this can lead to some bugs,
Expand Down Expand Up @@ -305,10 +304,11 @@ async function getLatestDxvk() {
'https://api.github.com/repos/lutris/dxvk/releases/latest'
)
const current = assets[0]
const name = current.name.replace('.tar.gz', '')
const pkg = current.name
const name = pkg.replace('.tar.gz', '')
const downloadUrl = current.browser_download_url

const dxvkLatest = `${heroicToolsPath}/DXVK/${name}`
const dxvkLatest = `${heroicToolsPath}/DXVK/${pkg}`
const pastVersionCheck = `${heroicToolsPath}/DXVK/latest_dxvk`
let pastVersion = ''

Expand Down Expand Up @@ -388,7 +388,7 @@ const handleExit = async () => {
if (existsSync(`${heroicGamesConfigPath}/lock`)) {
const { response } = await showMessageBox({
title: 'Exit',
message: 'Games are being download, are you sure?',
message: 'There are pending operations, are you sure?',
buttons: ['NO', 'YES'],
})

Expand Down
8 changes: 3 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "heroic",
"version": "1.2.2",
"version": "1.3.0",
"private": true,
"main": "public/main.js",
"homepage": "./",
Expand Down
38 changes: 31 additions & 7 deletions src/components/GamePage/GamePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export default function GamePage() {
const isPlaying = status === 'playing'
const isUpdating = status === 'updating'
const isReparing = status === 'repairing'
const isMoving = status === 'moving'

useEffect(() => {
const updateConfig = async () => {
Expand Down Expand Up @@ -145,6 +146,12 @@ export default function GamePage() {
>
Verify and Repair
</span>{' '}
<span
onClick={() => handleMoveInstall()}
className="hidden link"
>
Move Game
</span>{' '}
<span
onClick={() => ipcRenderer.send('getLog', appName)}
className="hidden link"
Expand Down Expand Up @@ -229,7 +236,7 @@ export default function GamePage() {
isInstalled || isInstalling ? '#0BD58C' : '#BD0A0A',
}}
>
{getInstallLabel(isInstalled, isUpdating)}
{getInstallLabel(isInstalled)}
</p>
</div>
{!isInstalled && !isInstalling && (
Expand All @@ -247,7 +254,7 @@ export default function GamePage() {
{isInstalled && (
<>
<button
disabled={isReparing}
disabled={isReparing || isMoving}
onClick={handlePlay()}
className={`button ${getPlayBtnClass()}`}
>
Expand All @@ -257,7 +264,9 @@ export default function GamePage() {
)}
<button
onClick={handleInstall(isInstalled)}
disabled={isPlaying || isUpdating || isReparing}
disabled={
isPlaying || isUpdating || isReparing || isMoving
}
className={`button ${getButtonClass(isInstalled)}`}
>
{`${getButtonLabel(isInstalled)}`}
Expand Down Expand Up @@ -296,15 +305,16 @@ export default function GamePage() {
return isPlaying ? 'Playing (Stop)' : 'Play Now'
}

function getInstallLabel(
isInstalled: boolean,
isUpdating: boolean
): React.ReactNode {
function getInstallLabel(isInstalled: boolean): React.ReactNode {
const { eta, percent } = progress
if (isReparing) {
return `Repairing Game ${percent ? `${percent}` : '...'}`
}

if (isMoving) {
return `Moving Installation, please wait.`
}

if (isUpdating && isInstalling) {
return `Updating ${percent ? `${percent} | ETA: ${eta}` : '...'}`
}
Expand Down Expand Up @@ -444,6 +454,20 @@ export default function GamePage() {
}
}

async function handleMoveInstall() {
const { response } = await showMessageBox({
title: 'Move Game Installation',
message: 'This can take a long time, are you sure?',
buttons: ['YES', 'NO'],
})
if (response === 0) {
handleGameStatus({ appName, status: 'moving' })
await ipcRenderer.invoke('moveInstall', appName)
handleGameStatus({ appName, status: 'done' })
}
return
}

async function handleRepair(appName: string) {
const { response } = await showMessageBox({
title: 'Verify and Repair',
Expand Down
7 changes: 5 additions & 2 deletions src/components/UI/GameCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ const GameCard = ({ cover, title, appName, isInstalled, logo }: Card) => {
)[0]

const { status } = gameStatus || {}
const isInstalling =
status === 'installing' || status === 'updating' || status === 'repairing'
const isInstalling = status === 'installing' || status === 'updating'
const isReparing = status === 'repairing'
const isMoving = status === 'moving'

useEffect(() => {
const progressInterval = setInterval(() => {
Expand Down Expand Up @@ -58,6 +59,8 @@ const GameCard = ({ cover, title, appName, isInstalled, logo }: Card) => {
}}
>
{isInstalling && <span className="progress">{percent}</span>}
{isMoving && <span className="progress">Moving...</span>}
{isReparing && <span className="progress">Repairing...</span>}
{logo && (
<img
alt="logo"
Expand Down
17 changes: 16 additions & 1 deletion src/state/GlobalState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ export class GlobalState extends PureComponent<Props> {
return (
currentApp.status === 'installing' ||
currentApp.status === 'repairing' ||
currentApp.status === 'updating'
currentApp.status === 'updating' ||
currentApp.status === 'moving'
)
})
default:
Expand Down Expand Up @@ -191,6 +192,20 @@ export class GlobalState extends PureComponent<Props> {
return currentWindow.reload()
}

if (currentApp && currentApp.status === 'moving' && status === 'done') {
const updatedLibraryStatus = libraryStatus.filter(
(game) => game.appName !== appName
)
this.setState({ libraryStatus: updatedLibraryStatus })
notify([title, 'Finished Moving Installation'])

if (windowIsVisible) {
return this.refresh()
}

return currentWindow.reload()
}

if (status === 'done') {
const updatedLibraryStatus = libraryStatus.filter(
(game) => game.appName !== appName
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export interface GameStatus {
| 'repairing'
| 'done'
| 'canceled'
| 'moving'
progress?: number | null
}

Expand Down