Look at description for changelog

- Wine support
- Loading script
- Format code
- Hide downloads button on sidebar when not downloading
- Add installs list
- A lot of improvements & more
This commit is contained in:
2025-07-22 23:00:54 -07:00
parent 49b5441136
commit ab26a4f5e9
20 changed files with 826 additions and 392 deletions

View File

@@ -2,14 +2,24 @@ import './Sidebar.css'
import Icon from '../Icon.png'
import { openUrl } from '@tauri-apps/plugin-opener'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCog, faDownload, faRankingStar, faServer } from '@fortawesome/free-solid-svg-icons'
import {
faCog,
faDownload,
faRankingStar,
faServer
} from '@fortawesome/free-solid-svg-icons'
import { faDiscord } from '@fortawesome/free-brands-svg-icons'
import { useState } from 'react'
import { platform } from '@tauri-apps/plugin-os'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { SidebarProps } from '../types/SidebarProps'
export default function Sidebar({ setShowPopup, setPopupMode, setFadeOut }: SidebarProps) {
export default function Sidebar ({
setShowPopup,
setPopupMode,
setFadeOut,
downloadProgress
}: SidebarProps) {
const [rot, setRot] = useState(0)
const [dir, setDir] = useState(1)
@@ -41,7 +51,9 @@ export default function Sidebar({ setShowPopup, setPopupMode, setFadeOut }: Side
style={{
transform: `rotate(${rot}deg)`,
transition: 'transform 0.3s ease',
marginTop: ['windows','macos'].includes(platform()) ? '20px' : '0px'
marginTop: ['windows', 'macos'].includes(platform())
? '20px'
: '0px'
}}
onClick={() =>
setRot(r => {
@@ -71,14 +83,60 @@ export default function Sidebar({ setShowPopup, setPopupMode, setFadeOut }: Side
}
/>
</div>
<nav className="nav-links">
<a draggable={false} href="#installs" className={`link ${(window.location.hash || '#installs') === '#installs' ? 'active' : ''}`}><FontAwesomeIcon icon={faServer} className="mr-1" /> Installs</a>
<a draggable={false} href="#settings" className={`link ${(window.location.hash || '#installs') === '#settings' ? 'active' : ''}`}><FontAwesomeIcon icon={faCog} className="mr-1" /> Settings</a>
<a draggable={false} href="#leaderboards" className={`link ${(window.location.hash || '#installs') === '#leaderboards' ? 'active' : ''}`}><FontAwesomeIcon icon={faRankingStar} className="mr-1" /> Leaderboards</a>
<a draggable={false} onClick={() => openUrl("https://berrydash.lncvrt.xyz/discord")} className="link"><FontAwesomeIcon icon={faDiscord} className="mr-1" /> Community</a>
<nav className='nav-links'>
<a
draggable={false}
href='#installs'
className={`link ${
(window.location.hash || '#installs') === '#installs'
? 'active'
: ''
}`}
>
<FontAwesomeIcon icon={faServer} className='mr-1' /> Installs
</a>
<a
draggable={false}
href='#settings'
className={`link ${
(window.location.hash || '#installs') === '#settings'
? 'active'
: ''
}`}
>
<FontAwesomeIcon icon={faCog} className='mr-1' /> Settings
</a>
<a
draggable={false}
href='#leaderboards'
className={`link ${
(window.location.hash || '#installs') === '#leaderboards'
? 'active'
: ''
}`}
>
<FontAwesomeIcon icon={faRankingStar} className='mr-1' /> Leaderboards
</a>
<a
draggable={false}
onClick={() => openUrl('https://berrydash.lncvrt.xyz/discord')}
className='link'
>
<FontAwesomeIcon icon={faDiscord} className='mr-1' /> Community
</a>
</nav>
<div className='sidebar-downloads' onClick={() => { setPopupMode(1); setShowPopup(true); setFadeOut(false) }}>
<p><FontAwesomeIcon icon={faDownload} /> Downloads</p>
<div
className='sidebar-downloads'
style={{ display: downloadProgress.length != 0 ? 'block' : 'none' }}
onClick={() => {
setPopupMode(1)
setShowPopup(true)
setFadeOut(false)
}}
>
<p>
<FontAwesomeIcon icon={faDownload} /> Downloads
</p>
</div>
</aside>
)

View File

@@ -13,21 +13,45 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faAdd, faRemove, faX } from '@fortawesome/free-solid-svg-icons'
import '@fontsource/roboto'
import Leaderboards from './routes/Leaderboards'
import { isPermissionGranted, requestPermission, sendNotification } from '@tauri-apps/plugin-notification'
import { readNormalConfig, readVersionsConfig, writeVersionsConfig } from './util/BazookaManager'
import {
isPermissionGranted,
requestPermission,
sendNotification
} from '@tauri-apps/plugin-notification'
import {
readNormalConfig,
readVersionsConfig,
writeVersionsConfig
} from './util/BazookaManager'
import { VersionsConfig } from './types/VersionsConfig'
import { DownloadedVersion } from './types/DownloadedVersion'
import { NormalConfig } from './types/NormalConfig'
import { app } from '@tauri-apps/api'
import axios from 'axios'
import { openUrl } from '@tauri-apps/plugin-opener'
function App () {
const [hash, setHash] = useState(window.location.hash || '#installs')
const [versionList, setVersionList] = useState<null | LauncherVersion[]>(null);
const [selectedVersionList, setSelectedVersionList] = useState<LauncherVersion[]>([]);
const [downloadProgress, setDownloadProgress] = useState<DownloadProgress[]>([]);
const [loading, setLoading] = useState(true)
const [loadingText, setLoadingText] = useState('Loading...')
const [outdated, setOutdated] = useState(false)
const [versionList, setVersionList] = useState<null | LauncherVersion[]>(null)
const [selectedVersionList, setSelectedVersionList] = useState<
LauncherVersion[]
>([])
const [downloadProgress, setDownloadProgress] = useState<DownloadProgress[]>(
[]
)
const [showPopup, setShowPopup] = useState(false)
const [popupMode, setPopupMode] = useState<null | number>(null)
const [fadeOut, setFadeOut] = useState(false)
const activeDownloads = useRef(0)
const queue = useRef<(() => void)[]>([])
const [downloadedVersionsConfig, setDownloadedVersionsConfig] =
useState<VersionsConfig | null>(null)
const [normalConfig, setNormalConfig] = useState<NormalConfig | null>(null)
function runNext() {
function runNext () {
if (activeDownloads.current >= 3 || queue.current.length === 0) return
activeDownloads.current++
const next = queue.current.shift()
@@ -35,7 +59,31 @@ function App () {
}
useEffect(() => {
const unlistenProgress = listen<string>('download-progress', (event) => {
;(async () => {
setLoadingText('Checking latest version...')
try {
const response = await axios.get(
'https://berrydash.lncvrt.xyz/database/launcher/latest.php'
)
const client = await app.getVersion()
if (response.data !== client) {
setOutdated(true)
return
}
} catch (e) {
setLoadingText('Failed to check latest version.')
return
}
setLoadingText('Loading configs...')
const normalConfig = await readNormalConfig()
const versionsConfig = await readVersionsConfig()
setDownloadedVersionsConfig(versionsConfig)
setNormalConfig(normalConfig)
setLoading(false)
})()
}, [])
useEffect(() => {
const unlistenProgress = listen<string>('download-progress', event => {
const [versionName, progStr] = event.payload.split(':')
const prog = Number(progStr)
@@ -48,15 +96,18 @@ function App () {
})
})
const unlistenDone = listen<string>('download-done', async (event) => {
const unlistenDone = listen<string>('download-done', async event => {
const versionName = event.payload
setDownloadProgress(prev => {
const downloaded = prev.find(d => d.version.version === versionName)
if (downloaded) {
readVersionsConfig().then(cfg => {
cfg.list.push(downloaded.version)
writeVersionsConfig(cfg)
})
if (downloaded && downloadedVersionsConfig) {
const newDownloaded = DownloadedVersion.import(downloaded.version)
const updatedConfig = {
...downloadedVersionsConfig,
list: [...downloadedVersionsConfig.list, newDownloaded]
}
setDownloadedVersionsConfig(updatedConfig)
writeVersionsConfig(updatedConfig)
}
return prev.filter(d => d.version.version !== versionName)
})
@@ -67,7 +118,7 @@ function App () {
}
})
const unlistenFailed = listen<string>('download-failed', async (event) => {
const unlistenFailed = listen<string>('download-failed', async event => {
const versionName = event.payload
setDownloadProgress(prev =>
prev.map(d =>
@@ -76,7 +127,10 @@ function App () {
)
activeDownloads.current--
runNext()
await notifyUser('Download Failed', `The download for version ${versionName} has failed.`)
await notifyUser(
'Download Failed',
`The download for version ${versionName} has failed.`
)
})
return () => {
@@ -84,54 +138,65 @@ function App () {
unlistenDone.then(f => f())
unlistenFailed.then(f => f())
}
}, [])
}, [downloadedVersionsConfig])
async function downloadVersions(versions: LauncherVersion[]) {
const config = await readNormalConfig()
const useWine = config.settings.useWineOnUnixWhenNeeded
const p = platform()
const newDownloads = versions.map(v => new DownloadProgress(v, 0, false, true))
setDownloadProgress(prev => [...prev, ...newDownloads])
async function downloadVersions (versions: LauncherVersion[]) {
while (normalConfig != null) {
const useWine = normalConfig.settings.useWineOnUnixWhenNeeded
const p = platform()
const newDownloads = versions.map(
v => new DownloadProgress(v, 0, false, true)
)
setDownloadProgress(prev => [...prev, ...newDownloads])
newDownloads.forEach(download => {
let plat = p
if ((p === 'macos' || p === 'linux') && useWine) {
if (!download.version.platforms.includes(p) && download.version.platforms.includes('windows')) {
plat = 'windows'
newDownloads.forEach(download => {
let plat = p
if ((p === 'macos' || p === 'linux') && useWine) {
if (
!download.version.platforms.includes(p) &&
download.version.platforms.includes('windows')
) {
plat = 'windows'
}
}
}
const idx = download.version.platforms.indexOf(plat)
const url = download.version.downloadUrls[idx]
const exe = download.version.executables[idx]
const idx = download.version.platforms.indexOf(plat)
const url = download.version.downloadUrls[idx]
const exe = download.version.executables[idx]
if (!url) {
setDownloadProgress(prev =>
prev.map(d =>
d.version.version === download.version.version ? { ...d, failed: true } : d
if (!url) {
setDownloadProgress(prev =>
prev.map(d =>
d.version.version === download.version.version
? { ...d, failed: true }
: d
)
)
)
return
}
return
}
const task = () => {
setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version.version === download.version.version)
if (i === -1) return prev
const copy = [...prev]
copy[i] = { ...copy[i], queued: false }
return copy
})
const task = () => {
setDownloadProgress(prev => {
const i = prev.findIndex(
d => d.version.version === download.version.version
)
if (i === -1) return prev
const copy = [...prev]
copy[i] = { ...copy[i], queued: false }
return copy
})
invoke('download', {
url,
name: download.version.version,
executable: exe
})
}
invoke('download', {
url,
name: download.version.version,
executable: exe
})
}
queue.current.push(task)
runNext()
})
queue.current.push(task)
runNext()
})
break
}
}
function handleOverlayClick (e: React.MouseEvent<HTMLDivElement>) {
@@ -141,16 +206,18 @@ function App () {
}
}
async function notifyUser(title: string, body: string) {
const config = await readNormalConfig()
if (!config.settings.allowNotifications) return
let permissionGranted = await isPermissionGranted();
async function notifyUser (title: string, body: string) {
while (normalConfig != null) {
if (!normalConfig.settings.allowNotifications) return
break
}
let permissionGranted = await isPermissionGranted()
if (!permissionGranted) {
const permission = await requestPermission();
permissionGranted = permission === 'granted';
const permission = await requestPermission()
permissionGranted = permission === 'granted'
}
if (permissionGranted) {
sendNotification({ title, body });
sendNotification({ title, body })
}
}
@@ -168,109 +235,231 @@ function App () {
function renderContent () {
if (hash === '#installs') {
return <Installs downloadProgress={downloadProgress} showPopup={showPopup} setShowPopup={setShowPopup} setPopupMode={setPopupMode} setFadeOut={setFadeOut} setSelectedVersionList={setSelectedVersionList} setVersionList={setVersionList} />
return (
<Installs
downloadProgress={downloadProgress}
showPopup={showPopup}
setShowPopup={setShowPopup}
setPopupMode={setPopupMode}
setFadeOut={setFadeOut}
setSelectedVersionList={setSelectedVersionList}
setVersionList={setVersionList}
downloadedVersionsConfig={downloadedVersionsConfig}
normalConfig={normalConfig}
/>
)
} else if (hash === '#settings') {
return <Settings />
return <Settings normalConfig={normalConfig} />
} else if (hash === '#leaderboards') {
return <Leaderboards />
}
return null
}
return (
return loading ? (
<div className='w-screen h-screen flex items-center justify-center'>
{outdated ? (
<div className='text-center'>
<p className='text-8xl mb-4'>Outdated Launcher!</p>
<p className='text-4xl mb-4'>
Please update to the latest version to continue.
</p>
<button
className='button'
onClick={() => openUrl('https://berrydash.lncvrt.xyz/download')}
>
Download latest version
</button>
</div>
) : (
<p className='text-8xl text-center'>{loadingText}</p>
)}
</div>
) : (
<>
<Sidebar setShowPopup={setShowPopup} setPopupMode={setPopupMode} setFadeOut={setFadeOut} />
<div className="relative z-[2] ml-[239px] w-[761px] border-b border-[#242424] h-[33px] bg-[#161616]" style={{ display: platform() == 'windows' ? 'block' : 'none' }}></div>
<div className="relative z-0">
<main style={{ marginLeft: '15rem' }}>{renderContent()}</main>
</div>
{showPopup && (
<div
tabIndex={0}
onKeyDown={e => {
if (showPopup && e.key === 'Escape') {
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
}
}}
>
<Sidebar
setShowPopup={setShowPopup}
setPopupMode={setPopupMode}
setFadeOut={setFadeOut}
downloadProgress={downloadProgress}
/>
<div
className={`popup-overlay ${fadeOut ? 'fade-out' : ''}`}
onClick={handleOverlayClick}
>
<div className='popup-box'>
<button
className='close-button'
onClick={() => {
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
}}
>
<FontAwesomeIcon icon={faX} />
</button>
{popupMode === 0 ? (
<>
<p className='text-xl text-center'>Select versions to download</p>
<div className='popup-content'>
{versionList == null ? (
<p className='text-center'>Getting version list...</p>
) : (
versionList.map((v, i) =>
<div key={i} className='popup-entry'>
<p className='text-2xl'>Berry Dash v{v.displayName}</p>
<button className='button right-2 bottom-2' onClick={() => {
if (!selectedVersionList) return
if (!selectedVersionList.includes(v)) {
setSelectedVersionList([...selectedVersionList, v])
} else {
setSelectedVersionList(selectedVersionList.filter(x => x !== v))
}
}}>{selectedVersionList.includes(v) ? <><FontAwesomeIcon icon={faRemove} /> Remove</> : <><FontAwesomeIcon icon={faAdd} /> Add</>}</button>
</div>
)
)}
</div>
</>
) : popupMode === 1 ? (
<>
<p className='text-xl text-center'>Downloads</p>
<div className='popup-content'>
{downloadProgress.length === 0 ? (
<p className='text-center mt-6'>Nothing here...</p>
) : (
downloadProgress.map((v, i) => (
<div key={i} className='popup-entry flex flex-col justify-between'>
<p className='text-2xl'>Berry Dash v{v.version.displayName}</p>
<div className='mt-[25px] flex items-center justify-between'>
{v.failed ? (
<>
<div className='flex items-center'>
<span className='text-red-500'>Download failed</span>
<button
className='button ml-30 mb-2'
onClick={() =>
setDownloadProgress((prev) => prev.filter((_, idx) => idx !== i))
}
>
Cancel
</button>
</div>
</>
) : v.queued ? (
<span className='text-yellow-500'>Queued</span>
) : (
<span>Downloading: {v.progress}% done</span>
)}
</div>
</div>
))
)}
</div>
</>
) : null}
{popupMode == 0 && versionList != null && (
<div className='flex justify-center'>
<button className='button w-fit mt-2 mb-[-16px]' onClick={() => {
className='relative z-[2] ml-[239px] w-[761px] border-b border-[#242424] h-[33px] bg-[#161616]'
style={{ display: platform() == 'windows' ? 'block' : 'none' }}
></div>
<div className='relative z-0'>
<main style={{ marginLeft: '15rem' }}>{renderContent()}</main>
</div>
{showPopup && (
<div
className={`popup-overlay ${fadeOut ? 'fade-out' : ''}`}
onClick={handleOverlayClick}
>
<div className='popup-box'>
<button
className='close-button'
onClick={() => {
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
downloadVersions(selectedVersionList)
}}>Download {selectedVersionList.length} version{selectedVersionList.length == 1 ? '' : 's'}</button>
</div>
)}
}}
>
<FontAwesomeIcon icon={faX} />
</button>
{popupMode === 0 ? (
<>
<p className='text-xl text-center'>
Select versions to download
</p>
<div className='popup-content'>
{versionList == null ? (
<p className='text-center'>Getting version list...</p>
) : (
versionList
.filter(
v =>
!downloadedVersionsConfig?.list.some(
dv => dv.version.version === v.version
)
)
.map((v, i) => (
<div key={i} className='popup-entry'>
<p className='text-2xl'>
Berry Dash v{v.displayName}
</p>
<button
className='button right-2 bottom-2'
onClick={() => {
if (!selectedVersionList) return
if (!selectedVersionList.includes(v)) {
setSelectedVersionList([
...selectedVersionList,
v
])
} else {
setSelectedVersionList(
selectedVersionList.filter(x => x !== v)
)
}
}}
>
{selectedVersionList.includes(v) ? (
<>
<FontAwesomeIcon icon={faRemove} /> Remove
</>
) : (
<>
<FontAwesomeIcon icon={faAdd} /> Add
</>
)}
</button>
</div>
))
)}
</div>
</>
) : popupMode === 1 ? (
<>
<p className='text-xl text-center'>Downloads</p>
<div className='popup-content'>
{downloadProgress.length === 0 ? (
<p className='text-center mt-6'>Nothing here...</p>
) : (
downloadProgress.map((v, i) => (
<div
key={i}
className='popup-entry flex flex-col justify-between'
>
<p className='text-2xl'>
Berry Dash v{v.version.displayName}
</p>
<div className='mt-[25px] flex items-center justify-between'>
{v.failed ? (
<>
<div className='flex items-center'>
<span className='text-red-500'>
Download failed
</span>
<button
className='button ml-30 mb-2'
onClick={() =>
setDownloadProgress(prev =>
prev.filter((_, idx) => idx !== i)
)
}
>
Cancel
</button>
</div>
</>
) : v.queued ? (
<span className='text-yellow-500'>Queued</span>
) : (
<span>Downloading: {v.progress}% done</span>
)}
</div>
</div>
))
)}
</div>
</>
) : null}
{popupMode == 0 && versionList != null && (
<div className='flex justify-center'>
<button
className='button w-fit mt-2 mb-[-16px]'
onClick={() => {
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
downloadVersions(selectedVersionList)
}}
>
Download {selectedVersionList.length} version
{selectedVersionList.length == 1 ? '' : 's'}
</button>
<button
className='button w-fit mt-2 ml-2 mb-[-16px]'
onClick={() => {
const filtered = versionList.filter(
v =>
!downloadedVersionsConfig?.list.some(
dv => dv.version.version === v.version
)
)
if (
selectedVersionList.length === filtered.length &&
filtered.every(v => selectedVersionList.includes(v))
) {
setSelectedVersionList([])
} else {
setSelectedVersionList(filtered)
}
}}
>
{selectedVersionList.length ===
versionList.filter(
v =>
!downloadedVersionsConfig?.list.some(
dv => dv.version.version === v.version
)
).length
? 'Deselect All'
: 'Select All'}
</button>
</div>
)}
</div>
</div>
</div>
)}
)}
</div>
</>
)
}

17
src/routes/Installs.css Normal file
View File

@@ -0,0 +1,17 @@
@import 'tailwindcss';
.downloads-container {
@apply flex justify-center;
}
.downloads-scroll {
@apply h-[515px] bg-[#161616] border border-[#242424] rounded-lg overflow-y-auto w-full;
}
.downloads-entry {
@apply flex justify-between items-center m-2 p-4 rounded-lg text-gray-200 text-lg transition-colors cursor-default bg-[#242424] hover:bg-[#323232] border border-[#484848] hover:border-[#565656];
}
.downloads-entry p.score {
@apply font-mono text-blue-500 text-lg;
}

View File

@@ -2,27 +2,44 @@ import { useEffect } from 'react'
import axios from 'axios'
import { InstallsProps } from '../types/InstallsProps'
import { platform } from '@tauri-apps/plugin-os'
import { readNormalConfig } from '../util/BazookaManager'
import './Installs.css'
import { format } from 'date-fns'
import { invoke } from '@tauri-apps/api/core'
import { message } from '@tauri-apps/plugin-dialog'
export default function Installs({ downloadProgress, showPopup, setShowPopup, setPopupMode, setFadeOut, setSelectedVersionList, setVersionList }: InstallsProps) {
export default function Installs ({
downloadProgress,
showPopup,
setShowPopup,
setPopupMode,
setFadeOut,
setSelectedVersionList,
setVersionList,
downloadedVersionsConfig,
normalConfig
}: InstallsProps) {
useEffect(() => {
if (!showPopup) return
setSelectedVersionList([])
setVersionList(null)
;(async () => {
try {
const config = await readNormalConfig()
const useWine = config.settings.useWineOnUnixWhenNeeded
const res = await axios.get('https://berrydash.lncvrt.xyz/database/launcher/versions.php')
const p = platform()
const filtered = res.data.filter((d: { platforms: string[] }) =>
p === 'macos' || p === 'linux'
? useWine
? d.platforms.includes('windows') || d.platforms.includes(p)
while (normalConfig != null) {
const useWine = normalConfig.settings.useWineOnUnixWhenNeeded
const res = await axios.get(
'https://berrydash.lncvrt.xyz/database/launcher/versions.php'
)
const p = platform()
const filtered = res.data.filter((d: { platforms: string[] }) =>
p === 'macos' || p === 'linux'
? useWine
? d.platforms.includes('windows') || d.platforms.includes(p)
: d.platforms.includes(p)
: d.platforms.includes(p)
: d.platforms.includes(p)
)
setVersionList(filtered)
)
setVersionList(filtered)
break
}
} catch {
setVersionList([])
}
@@ -30,15 +47,90 @@ export default function Installs({ downloadProgress, showPopup, setShowPopup, se
}, [showPopup])
return (
<div className='flex justify-between items-center mt-4 mx-4'>
<p className='text-3xl'>Installs</p>
<button
className='button text-3xl'
onClick={() => { setPopupMode(0); setShowPopup(true); setFadeOut(false) }}
disabled={downloadProgress.length != 0}
>
Download new version
</button>
<div className='mx-4 mt-4'>
<div className='flex justify-between items-center mb-4'>
<p className='text-3xl'>Install</p>
<button
className='button text-3xl'
onClick={() => {
setPopupMode(0)
setShowPopup(true)
setFadeOut(false)
}}
disabled={downloadProgress.length != 0}
>
Download new version
</button>
</div>
<div className='downloads-container'>
<div className='downloads-scroll'>
{downloadedVersionsConfig && downloadedVersionsConfig.list.length ? (
downloadedVersionsConfig.list
.sort((a, b) => b.version.id - a.version.id)
.map((entry, i) => (
<div key={i} className='downloads-entry'>
<div className='flex flex-col'>
<p className='text-2xl'>
Berry Dash v{entry.version.displayName}
</p>
<p className='text-gray-400 text-md'>
Installed{' '}
{format(new Date(entry.installDate), 'yyyy/MM/dd')}
</p>
</div>
<div className='flex flex-row items-center gap-2'>
<button
className='button'
onClick={async () => {
let plat = platform()
let willUseWine = false
if (plat === 'macos' || plat === 'linux') {
if (
!entry.version.platforms.includes(plat) &&
entry.version.platforms.includes('windows')
) {
while (normalConfig != null) {
if (
!normalConfig.settings.useWineOnUnixWhenNeeded
) {
await message(
'Wine support is disabled in settings and this version requires wine',
{
title:
'Wine is needed to load this version',
kind: 'error'
}
)
return
}
break
}
plat = 'windows'
willUseWine = true
}
}
invoke('launch_game', {
name: entry.version.version,
executable:
entry.version.executables[
entry.version.platforms.indexOf(plat)
],
wine: willUseWine
})
}}
>
Launch
</button>
</div>
</div>
))
) : (
<div className='flex justify-center items-center h-full'>
<p className='text-3xl'>No versions installed</p>
</div>
)}
</div>
</div>
</div>
)
}

View File

@@ -16,13 +16,16 @@ export default function Leaderboards () {
setLeaderboardData([])
try {
const launcherVersion = await app.getVersion()
const response = await axios.get('https://berrydash.lncvrt.xyz/database/getTopPlayers.php', {
headers: {
Requester: 'BerryDashLauncher',
LauncherVersion: launcherVersion,
ClientPlatform: platform()
const response = await axios.get(
'https://berrydash.lncvrt.xyz/database/getTopPlayers.php',
{
headers: {
Requester: 'BerryDashLauncher',
LauncherVersion: launcherVersion,
ClientPlatform: platform()
}
}
})
)
const decrypted = await decrypt(response.data)
setLeaderboardData(JSON.parse(decrypted))
} catch (e) {
@@ -72,7 +75,7 @@ export default function Leaderboards () {
<div className='leaderboard-scroll'>
{leaderboardData.length ? (
leaderboardData.map((entry, i) => (
<div key={entry.username} className='leaderboard-entry'>
<div key={i} className='leaderboard-entry'>
<p>
#{i + 1} {entry.username}
</p>

View File

@@ -1,9 +1,10 @@
import { useEffect, useState } from 'react'
import { Setting } from '../componets/Setting'
import { readNormalConfig, writeNormalConfig } from '../util/BazookaManager'
import { writeNormalConfig } from '../util/BazookaManager'
import { platform } from '@tauri-apps/plugin-os'
import { SettingsProps } from '../types/SettingsProps'
export default function Settings () {
export default function Settings ({ normalConfig }: SettingsProps) {
const [checkForNewVersionOnLoad, setCheckForNewVersionOnLoad] =
useState(false)
const [useWineOnUnixWhenNeeded, setUseWineOnUnixWhenNeeded] = useState(false)
@@ -12,11 +13,17 @@ export default function Settings () {
useEffect(() => {
;(async () => {
const config = await readNormalConfig()
setCheckForNewVersionOnLoad(config.settings.checkForNewVersionOnLoad)
setUseWineOnUnixWhenNeeded(config.settings.useWineOnUnixWhenNeeded)
setAllowNotifications(config.settings.allowNotifications)
setLoaded(true)
while (normalConfig != null) {
setCheckForNewVersionOnLoad(
normalConfig.settings.checkForNewVersionOnLoad
)
setUseWineOnUnixWhenNeeded(
normalConfig.settings.useWineOnUnixWhenNeeded
)
setAllowNotifications(normalConfig.settings.allowNotifications)
setLoaded(true)
break
}
})()
}, [])
@@ -29,32 +36,42 @@ export default function Settings () {
label='Check for new version on load'
value={checkForNewVersionOnLoad}
onChange={async () => {
setCheckForNewVersionOnLoad(!checkForNewVersionOnLoad)
const config = await readNormalConfig()
config.settings.checkForNewVersionOnLoad = !checkForNewVersionOnLoad
await writeNormalConfig(config)
while (normalConfig != null) {
setCheckForNewVersionOnLoad(!checkForNewVersionOnLoad)
normalConfig.settings.checkForNewVersionOnLoad =
!checkForNewVersionOnLoad
await writeNormalConfig(normalConfig)
break
}
}}
/>
<Setting
label='Allow sending notifications'
value={allowNotifications}
onChange={async () => {
setAllowNotifications(!allowNotifications)
const config = await readNormalConfig()
config.settings.allowNotifications = !allowNotifications
await writeNormalConfig(config)
while (normalConfig != null) {
setAllowNotifications(!allowNotifications)
normalConfig.settings.allowNotifications = !allowNotifications
await writeNormalConfig(normalConfig)
break
}
}}
/>
<Setting
label='Use wine to launch Berry Dash when needed'
value={useWineOnUnixWhenNeeded}
onChange={async () => {
setUseWineOnUnixWhenNeeded(!useWineOnUnixWhenNeeded)
const config = await readNormalConfig()
config.settings.useWineOnUnixWhenNeeded = !useWineOnUnixWhenNeeded
await writeNormalConfig(config)
while (normalConfig != null) {
setUseWineOnUnixWhenNeeded(!useWineOnUnixWhenNeeded)
normalConfig.settings.useWineOnUnixWhenNeeded =
!useWineOnUnixWhenNeeded
await writeNormalConfig(normalConfig)
break
}
}}
className={platform() == 'linux' || platform() == 'macos' ? '' : 'hidden'}
className={
platform() == 'linux' || platform() == 'macos' ? '' : 'hidden'
}
/>
</div>
)}

View File

@@ -0,0 +1,12 @@
import { LauncherVersion } from './LauncherVersion'
export class DownloadedVersion {
constructor (
public version: LauncherVersion,
public installDate: number = Date.now()
) {}
static import (data: LauncherVersion) {
return new DownloadedVersion(data)
}
}

View File

@@ -1,5 +1,7 @@
import { DownloadProgress } from './DownloadProgress'
import { LauncherVersion } from './LauncherVersion'
import { NormalConfig } from './NormalConfig'
import { VersionsConfig } from './VersionsConfig'
export type InstallsProps = {
downloadProgress: DownloadProgress[]
@@ -9,4 +11,6 @@ export type InstallsProps = {
setFadeOut: (v: boolean) => void
setSelectedVersionList: (v: LauncherVersion[]) => void
setVersionList: (v: null | LauncherVersion[]) => void
downloadedVersionsConfig: VersionsConfig | null
normalConfig: NormalConfig | null
}

View File

@@ -2,6 +2,7 @@ export interface LauncherVersion {
version: string
displayName: string
platforms: string[]
downloadUrls: string[],
downloadUrls: string[]
executables: string[]
id: number
}

View File

@@ -1,6 +1,6 @@
export type SettingProps = {
label: string
value: boolean
onChange: (val: boolean) => void,
onChange: (val: boolean) => void
className?: string
}

View File

@@ -0,0 +1,5 @@
import { NormalConfig } from './NormalConfig'
export type SettingsProps = {
normalConfig: NormalConfig | null
}

View File

@@ -2,6 +2,6 @@ export class SettingsType {
constructor (
public checkForNewVersionOnLoad: boolean = true,
public allowNotifications: boolean = true,
public useWineOnUnixWhenNeeded: boolean = false,
public useWineOnUnixWhenNeeded: boolean = false
) {}
}

View File

@@ -1,5 +1,8 @@
import { DownloadProgress } from './DownloadProgress'
export type SidebarProps = {
setShowPopup: (v: boolean) => void
setPopupMode: (v: null | number) => void
setFadeOut: (v: boolean) => void
downloadProgress: DownloadProgress[]
}

View File

@@ -1,10 +1,7 @@
import { LauncherVersion } from './LauncherVersion'
import { DownloadedVersion } from './DownloadedVersion'
export class VersionsConfig {
constructor (
public version: string,
public list: LauncherVersion[] = []
) {}
constructor (public version: string, public list: DownloadedVersion[] = []) {}
static import (data: any) {
const cfg = new VersionsConfig(data.version)

View File

@@ -36,9 +36,7 @@ export async function readNormalConfig (): Promise<NormalConfig> {
return new NormalConfig(version)
}
const config = await readTextFile('config.dat', options)
return NormalConfig.import(
JSON.parse(await decrypt(config, await getKey(2)))
)
return NormalConfig.import(JSON.parse(await decrypt(config, await getKey(2))))
}
export async function writeNormalConfig (data: NormalConfig) {

View File

@@ -1,11 +1,11 @@
import { invoke } from "@tauri-apps/api/core";
import { invoke } from '@tauri-apps/api/core'
export async function getKey(key: number): Promise<string> {
export async function getKey (key: number): Promise<string> {
try {
const message = await invoke('get_keys_config', { key });
return message as string;
const message = await invoke('get_keys_config', { key })
return message as string
} catch (error) {
console.error('Failed to get key from Tauri backend', error);
return '';
console.error('Failed to get key from Tauri backend', error)
return ''
}
}
}