add app and apps icons
This commit is contained in:
parent
e0173d410b
commit
7508811374
16 changed files with 554 additions and 7 deletions
|
|
@ -262,6 +262,31 @@ function wineLabel(id) {
|
|||
return w ? w.label : (id === 'system' ? t('wines.system') : id)
|
||||
}
|
||||
|
||||
function iconUrl(id) {
|
||||
return `plgl-icon://${encodeURIComponent(id)}/icon`
|
||||
}
|
||||
|
||||
function fmtPlaytime(seconds) {
|
||||
const s = Math.round(seconds || 0)
|
||||
if (s < 60) return t('library.playtimeSeconds', s)
|
||||
const h = Math.floor(s / 3600)
|
||||
const m = Math.floor((s % 3600) / 60)
|
||||
if (h > 0) return t('library.playtimeHM', h, m)
|
||||
return t('library.playtimeMin', m)
|
||||
}
|
||||
|
||||
async function attachCardIcon(card, game) {
|
||||
const p = await window.plgl.gamesIconPath(game.id)
|
||||
if (!p) return
|
||||
const img = document.createElement('img')
|
||||
img.className = 'game-icon'
|
||||
img.alt = ''
|
||||
img.onerror = () => img.remove()
|
||||
img.onload = () => card.prepend(img)
|
||||
img.src = iconUrl(game.id)
|
||||
if (img.complete && img.naturalWidth > 0) card.prepend(img)
|
||||
}
|
||||
|
||||
function renderLibrary() {
|
||||
const list = qs('#game-list')
|
||||
list.innerHTML = ''
|
||||
|
|
@ -280,6 +305,7 @@ function renderLibrary() {
|
|||
<span class="badge">${wineLabel(game.wine)}</span>
|
||||
</div>
|
||||
<div class="meta">${t('library.lastPlayed', last)}</div>
|
||||
<div class="meta">${t('library.playtime', fmtPlaytime(game.playSeconds || 0))}</div>
|
||||
<div class="actions">
|
||||
<button class="button primary small" data-act="play">${t('library.play')}</button>
|
||||
<button class="button small danger" data-act="kill" style="display:none">${t('library.stop')}</button>
|
||||
|
|
@ -321,6 +347,7 @@ function renderLibrary() {
|
|||
renderLibrary()
|
||||
}
|
||||
list.appendChild(card)
|
||||
attachCardIcon(card, game)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -571,6 +598,31 @@ function renderPrefixOptions(selectId, selected) {
|
|||
else selects[selectId].update(opts, selected || '')
|
||||
}
|
||||
|
||||
async function refreshConfigIcon() {
|
||||
const game = state.currentGame
|
||||
if (!game) return
|
||||
const p = await window.plgl.gamesIconPath(game.id)
|
||||
const img = qs('#gc-icon')
|
||||
const ph = qs('#gc-icon-placeholder')
|
||||
img.onerror = () => {
|
||||
img.style.display = 'none'
|
||||
img.removeAttribute('src')
|
||||
ph.style.display = 'flex'
|
||||
}
|
||||
if (p) {
|
||||
img.onload = () => {
|
||||
img.style.display = ''
|
||||
ph.style.display = 'none'
|
||||
}
|
||||
img.src = iconUrl(game.id) + '?t=' + Date.now()
|
||||
if (img.complete && img.naturalWidth > 0) img.onload()
|
||||
} else {
|
||||
img.style.display = 'none'
|
||||
img.removeAttribute('src')
|
||||
ph.style.display = 'flex'
|
||||
}
|
||||
}
|
||||
|
||||
async function openGameConfig(id) {
|
||||
const game = state.games.find(g => g.id === id)
|
||||
if (!game) return
|
||||
|
|
@ -578,6 +630,7 @@ async function openGameConfig(id) {
|
|||
showView('gameconfig')
|
||||
qs('#gc-title').textContent = game.name
|
||||
qs('#gc-name').value = game.name
|
||||
refreshConfigIcon()
|
||||
qs('#gc-exe').value = game.exePath
|
||||
qs('#gc-workdir').value = game.workdir
|
||||
qs('#gc-args').value = game.args || ''
|
||||
|
|
@ -744,6 +797,46 @@ function wireEvents() {
|
|||
if (p) qs('#gc-workdir').value = p
|
||||
})
|
||||
qs('#gc-tool-run').addEventListener('click', runCustomTool)
|
||||
qs('#gc-icon-auto').addEventListener('click', async () => {
|
||||
const res = await window.plgl.gamesAutoIcon(state.currentGame.id)
|
||||
if (res.ok) {
|
||||
toast(t('config.icon.set'), 'success')
|
||||
refreshConfigIcon()
|
||||
} else {
|
||||
toast(t('config.icon.noIcon'), 'error')
|
||||
}
|
||||
})
|
||||
qs('#gc-icon-browse').addEventListener('click', async () => {
|
||||
const p = await window.plgl.dialogPickFile({
|
||||
properties: ['openFile'],
|
||||
title: t('config.icon.pick'),
|
||||
filters: [{ name: t('config.icon.pick'), extensions: ['png', 'jpg', 'jpeg', 'svg', 'ico', 'webp', 'gif', 'bmp', 'exe'] }]
|
||||
})
|
||||
if (!p) return
|
||||
let res
|
||||
if (p.toLowerCase().endsWith('.exe')) {
|
||||
res = await window.plgl.gamesSetIconFile(state.currentGame.id, p)
|
||||
if (res.ok) toast(t('config.icon.set'), 'success')
|
||||
else toast(t('config.icon.noIcon'), 'error')
|
||||
} else {
|
||||
res = await window.plgl.gamesSetIconFile(state.currentGame.id, p)
|
||||
if (res.ok) toast(t('config.icon.set'), 'success')
|
||||
else toast(t('config.icon.noIcon'), 'error')
|
||||
}
|
||||
refreshConfigIcon()
|
||||
})
|
||||
qs('#gc-icon-reset').addEventListener('click', async () => {
|
||||
await window.plgl.gamesResetIcon(state.currentGame.id)
|
||||
refreshConfigIcon()
|
||||
})
|
||||
qs('#btn-gc-clear-playtime').addEventListener('click', async () => {
|
||||
const ok = await confirmModal(t('config.clearPlaytimeConfirm'), t('config.clearPlaytime'))
|
||||
if (!ok) return
|
||||
await window.plgl.gamesClearPlaytime(state.currentGame.id)
|
||||
state.games = await window.plgl.gamesList()
|
||||
state.currentGame = state.games.find(g => g.id === state.currentGame.id)
|
||||
toast(t('config.playtimeCleared'), 'success')
|
||||
})
|
||||
qs('#modal-overlay').addEventListener('click', e => {
|
||||
if (e.target === qs('#modal-overlay')) closeModal()
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue