Compare commits

...
8 Commits
Author SHA1 Message Date
Lncvrt 2e02275c29 1.5.5 2026-02-04 19:22:03 -07:00
Lncvrt dbaac6a6a6 Remove green & mint theme 2026-02-04 19:22:01 -07:00
Lncvrt 68525f161e Add a reinstall button for manage menu 2026-02-04 18:28:03 -07:00
Lncvrt d386454e91 Fix versions config not being set right when downloading 2026-02-04 17:58:07 -07:00
Lncvrt 6e05aac871 Fix games that can't even be installed showing up 2026-02-04 16:56:25 -07:00
Lncvrt fbe3feec9d Fix some issues 2026-02-04 16:47:54 -07:00
Lncvrt 1c540ad35b Fix eslint 2026-02-04 15:55:08 -07:00
Lncvrt 4ec597967a 1.5.4 2026-02-03 18:51:40 -07:00
14 changed files with 234 additions and 114 deletions

No files matched your search

+2 -1
View File
@@ -11,7 +11,8 @@ const eslintConfig = defineConfig([
'.next/**',
'out/**',
'build/**',
'next-env.d.ts'
'next-env.d.ts',
'src-tauri/**'
])
])
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "lncvrt-games-launcher",
"private": true,
"version": "1.5.3",
"version": "1.5.5",
"type": "module",
"scripts": {
"dev": "next dev",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "lncvrt-games-launcher"
version = "1.5.3"
version = "1.5.5"
authors = ["Lncvrt"]
edition = "2024"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher",
"version": "1.5.3",
"version": "1.5.5",
"identifier": "xyz.lncvrt.games-launcher",
"build": {
"beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher",
"version": "1.5.3",
"version": "1.5.5",
"identifier": "xyz.lncvrt.games-launcher",
"build": {
"beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher",
"version": "1.5.3",
"version": "1.5.5",
"identifier": "xyz.lncvrt.games-launcher",
"build": {
"beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher",
"version": "1.5.3",
"version": "1.5.5",
"identifier": "xyz.lncvrt.games-launcher",
"build": {
"beforeDevCommand": "next dev",
-24
View File
@@ -28,18 +28,6 @@ body {
--col8: rgb(152, 128, 128);
}
.green-theme {
--col0: rgb(8, 32, 8);
--col1: rgb(16, 40, 16);
--col2: rgb(32, 56, 32);
--col3: rgb(48, 72, 48);
--col4: rgb(64, 88, 64);
--col5: rgb(80, 104, 80);
--col6: rgb(96, 120, 96);
--col7: rgb(112, 136, 112);
--col8: rgb(128, 152, 128);
}
.blue-theme {
--col0: rgb(8, 8, 32);
--col1: rgb(16, 16, 40);
@@ -64,18 +52,6 @@ body {
--col8: rgb(140, 128, 152);
}
.mint-theme {
--col0: rgb(8, 32, 16);
--col1: rgb(16, 48, 32);
--col2: rgb(32, 56, 40);
--col3: rgb(48, 72, 48);
--col4: rgb(64, 88, 66);
--col5: rgb(80, 104, 65);
--col6: rgb(96, 120, 80);
--col7: rgb(112, 136, 85);
--col8: rgb(128, 152, 95);
}
.button {
@apply rounded-md cursor-pointer text-[16px] py-1 px-2 transition-colors border;
}
+10 -6
View File
@@ -43,9 +43,11 @@ export default function Sidebar () {
hidden={platform() != 'macos'}
onMouseDown={e => {
if (e.buttons === 1) {
e.detail === 2
? getCurrentWindow().toggleMaximize()
: getCurrentWindow().startDragging()
if (e.detail === 2) {
getCurrentWindow().toggleMaximize()
} else {
getCurrentWindow().startDragging()
}
}
}}
></div>
@@ -62,9 +64,11 @@ export default function Sidebar () {
onMouseDown={e => {
if (platform() != 'macos') return
if (e.buttons === 1) {
e.detail === 2
? getCurrentWindow().toggleMaximize()
: getCurrentWindow().startDragging()
if (e.detail === 2) {
getCurrentWindow().toggleMaximize()
} else {
getCurrentWindow().startDragging()
}
}
}}
>
+5 -4
View File
@@ -23,10 +23,6 @@ export default function VersionInfo () {
viewingInfoFromDownloads,
setPopupMode
} = useGlobal()
if (!managingVersion || !downloadedVersionsConfig) return <></>
const versionInfo = getVersionInfo(managingVersion)
const gameInfo = getGameInfo(versionInfo?.game)
const [versionSize, setVersionSize] = useState<number | null>(null)
useEffect(() => {
@@ -37,6 +33,11 @@ export default function VersionInfo () {
})
}, [managingVersion, setVersionSize])
if (!managingVersion || !downloadedVersionsConfig) return <></>
const versionInfo = getVersionInfo(managingVersion)
const gameInfo = getGameInfo(versionInfo?.game)
return (
<>
<p className='text-xl text-center'>
+53 -10
View File
@@ -26,18 +26,25 @@ export default function Installs () {
} = useGlobal()
const params = useSearchParams()
const [category, setCategory] = useState<number>(-1)
const id = Number(params.get('id') || 0)
if (!id) return <p>Invalid game</p>
const game = serverVersionList?.games.find(g => g.id === id)
if (!game) return <p>Invalid game</p>
const [category, setCategory] = useState<number>(-1)
const [lastId, setLastId] = useState(id)
useEffect(() => {
if (!showPopup) return
setSelectedVersionList([])
}, [normalConfig, setSelectedVersionList, showPopup])
if (!id || !game) return <p>Invalid game</p>
if (lastId !== id) {
setLastId(id)
setCategory(-1)
}
return (
<div className='mx-4 mt-4'>
<div className='flex justify-between items-center mb-4'>
@@ -76,10 +83,31 @@ export default function Installs () {
}`}
>
{category == -1 &&
Object.entries(game.categoryNames).map(([key, value]) => {
Object.entries(game.categoryNames)
.sort(([a], [b]) => Number(b) - Number(a))
.filter(([key]) => {
const count = Object.keys(
downloadedVersionsConfig?.list ?? {}
).filter(v => {
const info = getVersionInfo(v)
if (!info) return false
if (
platform() === 'linux' &&
info.wine &&
!normalConfig?.settings.useWineOnUnixWhenNeeded
)
return false
return info.game === id && info.category === Number(key)
}).length
return count >= 1
})
.map(([key, value]) => {
return (
<div
key={crypto.randomUUID()}
key={value}
className={`downloads-entry ${
normalConfig?.settings.useLegacyInteractButtons
? ''
@@ -91,7 +119,8 @@ export default function Installs () {
: 'Click to view category'
}
onClick={() => {
if (normalConfig?.settings.useLegacyInteractButtons) return
if (normalConfig?.settings.useLegacyInteractButtons)
return
setCategory(Number(key))
}}
>
@@ -114,11 +143,13 @@ export default function Installs () {
if (
platform() === 'linux' &&
info.wine &&
!normalConfig?.settings.useWineOnUnixWhenNeeded
!normalConfig?.settings
.useWineOnUnixWhenNeeded
)
return false
return (
info.game === id && info.category == Number(key)
info.game === id &&
info.category == Number(key)
)
}).length ?? 0
return `${count} install${count === 1 ? '' : 's'}`
@@ -128,7 +159,9 @@ export default function Installs () {
<button
className='button absolute right-0 bottom-0'
hidden={!normalConfig?.settings.useLegacyInteractButtons}
hidden={
!normalConfig?.settings.useLegacyInteractButtons
}
title='Click to view category'
onClick={() => setCategory(Number(key))}
>
@@ -277,9 +310,19 @@ export default function Installs () {
e.stopPropagation()
const verInfo = getVersionInfo(entry)
if (verInfo == undefined) return
const gameInfo = getGameInfo(verInfo.game)
if (gameInfo == undefined) return
invoke('launch_game', {
name: verInfo.id,
executable: verInfo.executable
executable: verInfo.executable,
displayName: verInfo.displayName,
useWine: !!(
platform() === 'linux' &&
verInfo.wine &&
normalConfig?.settings.useWineOnUnixWhenNeeded
),
wineCommand:
normalConfig?.settings.wineOnUnixCommand
})
}}
hidden={
+92 -31
View File
@@ -1,6 +1,6 @@
'use client'
import { useEffect, useRef, useState } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import Sidebar from './componets/Sidebar'
import './Globals.css'
import { DownloadProgress } from './types/DownloadProgress'
@@ -111,15 +111,21 @@ export default function RootLayout ({
})
}
function getVersionInfo (id: string | undefined): GameVersion | undefined {
const getVersionInfo = useCallback(
(id: string | undefined): GameVersion | undefined => {
if (!id) return undefined
return serverVersionList?.versions.find(v => v.id === id)
}
},
[serverVersionList]
)
function getGameInfo (game: number | undefined): Game | undefined {
const getGameInfo = useCallback(
(game: number | undefined): Game | undefined => {
if (!game) return undefined
return serverVersionList?.games.find(g => g.id === game)
}
},
[serverVersionList]
)
function getListOfGames (): Game[] {
if (!downloadedVersionsConfig?.list) return []
@@ -292,10 +298,8 @@ export default function RootLayout ({
return () => document.removeEventListener('contextmenu', handler)
}, [])
async function downloadVersions (
list: string[],
currentConfig: VersionsConfig
): Promise<void> {
const downloadVersions = useCallback(
async (list: string[]): Promise<void> => {
if (list.length === 0) return
setSelectedVersionList([])
@@ -346,13 +350,20 @@ export default function RootLayout ({
setDownloadProgress(prev =>
prev.filter(d => d.version !== download.version)
)
const date = Date.now()
const newConfig = {
...currentConfig,
list: { ...currentConfig.list, [download.version]: date }
setDownloadedVersionsConfig(prev => {
if (!prev) return prev
const updated = {
...prev,
list: {
...prev.list,
[download.version]: Date.now()
}
setDownloadedVersionsConfig(newConfig)
writeVersionsConfig(newConfig)
}
writeVersionsConfig(updated)
return updated
})
} else {
setDownloadProgress(prev =>
prev.map(d =>
@@ -374,7 +385,9 @@ export default function RootLayout ({
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
}
},
[getGameInfo, getVersionInfo, normalConfig]
)
useEffect(() => {
if (revisionCheck.current) return
@@ -402,9 +415,9 @@ export default function RootLayout ({
writeVersionsConfig(newConfig)
setSelectedVersionList(prev => [...prev, ...versionsToSelect])
await downloadVersions(versionsToSelect, newConfig)
await downloadVersions(versionsToSelect)
})()
}, [serverVersionList, downloadedVersionsConfig])
}, [serverVersionList, downloadedVersionsConfig, downloadVersions])
return (
<>
@@ -414,13 +427,9 @@ export default function RootLayout ({
normalConfig?.settings.theme === 1
? 'red-theme'
: normalConfig?.settings.theme === 2
? 'green-theme'
: normalConfig?.settings.theme === 3
? 'blue-theme'
: normalConfig?.settings.theme === 4
: normalConfig?.settings.theme === 3
? 'purple-theme'
: normalConfig?.settings.theme === 5
? 'mint-theme'
: 'dark-theme'
}
>
@@ -591,7 +600,13 @@ export default function RootLayout ({
Select a game to download
</p>
<div className='popup-content'>
{serverVersionList?.games.map((v, i) => (
{serverVersionList?.games
.filter(v => {
const data = getVersionsAmountData(v.id)
if (!data) return false
if (data.total > 0) return true
})
.map((v, i) => (
<div key={i} className='popup-entry'>
<p className='text-2xl'>{v.name}</p>
<div className='flex gap-2'>
@@ -601,7 +616,9 @@ export default function RootLayout ({
>
<p>
{(() => {
const data = getVersionsAmountData(v.id)
const data = getVersionsAmountData(
v.id
)
if (!data) return 'N/A'
return `${data.installed}/${data.total}`
})()}{' '}
@@ -630,9 +647,13 @@ export default function RootLayout ({
>
<FontAwesomeIcon
icon={
v.verified ? faShieldHalved : faWarning
v.verified
? faShieldHalved
: faWarning
}
color={
v.verified ? '#19c84b' : '#ffc800'
}
color={v.verified ? '#19c84b' : '#ffc800'}
/>
<p>
{v.verified ? 'Verified' : 'Unverified'}
@@ -799,6 +820,49 @@ export default function RootLayout ({
>
Uninstall
</button>
<button
className='button btntheme2'
disabled={downloadProgress.length != 0}
onClick={async () => {
//uninstall
closePopup()
setDownloadedVersionsConfig(prev => {
if (!prev) return prev
const updatedList = Object.fromEntries(
Object.entries(prev.list).filter(
([k]) => k !== managingVersion
)
)
const updatedConfig = {
...prev,
list: updatedList
}
writeVersionsConfig(updatedConfig)
setManagingVersion(null)
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
return updatedConfig
})
if (
await exists('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData
})
)
await remove('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData,
recursive: true
})
//reinstall
setSelectedVersionList([managingVersion])
downloadVersions([managingVersion])
}}
title="Click to reinstall this game. This will NOT remove any progress or any save files. This WILL uninstall any modifications to the game's executable files."
>
Reinstall
</button>
<button
className='button btntheme2'
onClick={async () =>
@@ -844,10 +908,7 @@ export default function RootLayout ({
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
if (downloadedVersionsConfig)
downloadVersions(
selectedVersionList,
downloadedVersionsConfig
)
downloadVersions(selectedVersionList)
}}
disabled={downloadProgress.length != 0}
title={
+38 -29
View File
@@ -50,7 +50,7 @@ export default function Settings () {
label='Allow sending notifications'
value={allowNotifications}
onChange={async () => {
while (normalConfig != null) {
if (!normalConfig) return
setAllowNotifications(!allowNotifications)
setNormalConfig({
...normalConfig,
@@ -59,15 +59,13 @@ export default function Settings () {
allowNotifications: !allowNotifications
}
})
writeNormalConfig({
await writeNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
allowNotifications: !allowNotifications
}
})
break
}
}}
title='This setting does as you expect, allow the launcher to send notifications for when stuff like downloading is done.'
/>
@@ -75,7 +73,7 @@ export default function Settings () {
label='Always show games in sidebar'
value={alwaysShowGamesInSidebar}
onChange={async () => {
while (normalConfig != null) {
if (!normalConfig) return
setAlwaysShowGamesInSidebar(!alwaysShowGamesInSidebar)
setNormalConfig({
...normalConfig,
@@ -84,15 +82,13 @@ export default function Settings () {
alwaysShowGamesInSidebar: !alwaysShowGamesInSidebar
}
})
writeNormalConfig({
await writeNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
alwaysShowGamesInSidebar: !alwaysShowGamesInSidebar
}
})
break
}
}}
title="This setting will make it so when you are on a page like this, the games won't disappear."
/>
@@ -100,7 +96,7 @@ export default function Settings () {
label='Show Installs/Launch/Manage Buttons'
value={useLegacyInteractButtons}
onChange={async () => {
while (normalConfig != null) {
if (!normalConfig) return
setUseLegacyInteractButtons(!useLegacyInteractButtons)
setNormalConfig({
...normalConfig,
@@ -109,15 +105,13 @@ export default function Settings () {
useLegacyInteractButtons: !useLegacyInteractButtons
}
})
writeNormalConfig({
await writeNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
useLegacyInteractButtons: !useLegacyInteractButtons
}
})
break
}
}}
title='Enable the legacy method of using the installs/launch/manage buttons. In the future this setting may be removed so try and get used to the new method.'
/>
@@ -125,13 +119,22 @@ export default function Settings () {
label='Use wine when needed to launch games'
value={useWineOnUnixWhenNeeded}
onChange={async () => {
while (normalConfig != null) {
if (!normalConfig) return
setUseWineOnUnixWhenNeeded(!useWineOnUnixWhenNeeded)
normalConfig.settings.useWineOnUnixWhenNeeded =
!useWineOnUnixWhenNeeded
await writeNormalConfig(normalConfig)
break
setNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
useWineOnUnixWhenNeeded: !useWineOnUnixWhenNeeded
}
})
await writeNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
useWineOnUnixWhenNeeded: !useWineOnUnixWhenNeeded
}
})
}}
className={platform() == 'linux' ? '' : 'hidden'}
/>
@@ -142,12 +145,22 @@ export default function Settings () {
type='text'
value={wineOnUnixCommand}
onChange={async e => {
while (normalConfig != null) {
if (!normalConfig) return
setWineOnUnixCommand(e.target.value)
normalConfig.settings.wineOnUnixCommand = e.target.value
await writeNormalConfig(normalConfig)
break
setNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
wineOnUnixCommand: e.target.value
}
})
await writeNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
wineOnUnixCommand: e.target.value
}
})
}}
className={`input-field my-1 ${
platform() == 'linux' && useWineOnUnixWhenNeeded ? '' : 'hidden'
@@ -159,8 +172,8 @@ export default function Settings () {
className='ml-2 bg-(--col2) border border-(--col4) rounded-md'
value={theme}
onChange={async e => {
if (!normalConfig) return
const newTheme = parseInt(e.target.value)
while (normalConfig != null) {
setTheme(newTheme)
setNormalConfig({
...normalConfig,
@@ -169,23 +182,19 @@ export default function Settings () {
theme: newTheme
}
})
writeNormalConfig({
await writeNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
theme: newTheme
}
})
break
}
}}
>
<option value={0}>Dark (default)</option>
<option value={1}>Red</option>
<option value={2}>Green</option>
<option value={3}>Blue</option>
<option value={4}>Purple</option>
<option value={5}>Mint</option>
<option value={2}>Blue</option>
<option value={3}>Purple</option>
</select>
</div>
</div>
+28 -3
View File
@@ -32,7 +32,31 @@ export async function readNormalConfig (): Promise<NormalConfig> {
return new NormalConfig(version)
}
const config = await readTextFile('config.json', options)
return NormalConfig.import(JSON.parse(config))
const raw = JSON.parse(config)
if (
raw.settings &&
raw.settings.theme &&
(raw.version == '1.0.0' ||
raw.version == '1.1.0' ||
raw.version == '1.1.1' ||
raw.version == '1.2.0' ||
raw.version == '1.3.0' ||
raw.version == '1.3.1' ||
raw.version == '1.4.0' ||
raw.version == '1.5.0' ||
raw.version == '1.5.1' ||
raw.version == '1.5.2' ||
raw.version == '1.5.3' ||
raw.version == '1.5.4')
) {
const parsed = Number(raw.settings.theme)
if (parsed == 3) raw.settings.theme = 2
if (parsed == 4) raw.settings.theme = 3
else if (parsed != 0 && parsed != 1) raw.settings.theme = 0
}
raw.version = version
writeNormalConfig(raw)
return NormalConfig.import(raw)
} catch {
return new NormalConfig(version)
}
@@ -83,8 +107,7 @@ export async function readVersionsConfig (): Promise<VersionsConfig> {
}
const config = await readTextFile('versions.json', options)
const raw = JSON.parse(config)
if (raw.version && raw.list && raw.timestamps) {
raw.version = version
if (raw.list && raw.timestamps) {
raw.list = raw.timestamps
delete raw.timestamps
@@ -94,6 +117,8 @@ export async function readVersionsConfig (): Promise<VersionsConfig> {
options
)
}
raw.version = version
writeVersionsConfig(raw)
return VersionsConfig.import(raw)
} catch {
return new VersionsConfig(version)