Upload via GUI (21 Dateien)
This commit is contained in:
+254
-11
@@ -256,6 +256,194 @@ function applyTheme(theme) {
|
||||
document.documentElement.setAttribute('data-theme', theme === 'light' ? 'light' : 'dark');
|
||||
}
|
||||
|
||||
// ---------- Instanzen aus MultiMC übernehmen ----------
|
||||
let mmcFound = [];
|
||||
|
||||
function openMmc() {
|
||||
el('mmc-result').classList.add('hidden');
|
||||
el('mmc-do').disabled = true;
|
||||
el('mmc-progress').textContent = '';
|
||||
el('mmc-status').textContent = 'Gib den Ordner an, in dem MultiMC.exe liegt.';
|
||||
show('modal-mmc');
|
||||
el('mmc-path').focus();
|
||||
}
|
||||
|
||||
async function scanMmc() {
|
||||
const folder = el('mmc-path').value.trim();
|
||||
if (!folder) { el('mmc-status').textContent = 'Bitte zuerst einen Ordner angeben.'; return; }
|
||||
el('mmc-status').textContent = 'Suche Instanzen …';
|
||||
const res = await window.api.mmcScan(folder);
|
||||
if (!res.ok) {
|
||||
el('mmc-status').textContent = '✖ Dort wurde kein instances-Ordner gefunden.';
|
||||
el('mmc-result').classList.add('hidden');
|
||||
el('mmc-do').disabled = true;
|
||||
return;
|
||||
}
|
||||
mmcFound = res.instances;
|
||||
el('mmc-status').textContent = `${res.count} Instanz${res.count === 1 ? '' : 'en'} gefunden.`;
|
||||
el('mmc-result').classList.remove('hidden');
|
||||
el('mmc-all').checked = true;
|
||||
renderMmcList();
|
||||
}
|
||||
|
||||
function renderMmcList() {
|
||||
const box = el('mmc-list');
|
||||
box.innerHTML = '';
|
||||
if (!mmcFound.length) { box.innerHTML = '<div class="mods-empty">Keine Instanzen gefunden.</div>'; return; }
|
||||
mmcFound.forEach((inst, idx) => {
|
||||
const row = document.createElement('label');
|
||||
row.className = 'mmc-item';
|
||||
const loaderTxt = inst.loader === 'vanilla'
|
||||
? 'Vanilla'
|
||||
: (LOADER_LABEL[inst.loader] || inst.loader) + (inst.loaderVersion ? ' ' + inst.loaderVersion : '');
|
||||
const meta = [inst.version || 'ohne Version', loaderTxt, inst.group ? 'Gruppe: ' + inst.group : '']
|
||||
.filter(Boolean).join(' · ');
|
||||
row.innerHTML =
|
||||
`<input type="checkbox" data-idx="${idx}" checked />
|
||||
<div class="mod-info">
|
||||
<div class="mmc-name">${escapeHtml(inst.name)}</div>
|
||||
<div class="mmc-meta">${escapeHtml(meta)}</div>
|
||||
</div>`;
|
||||
box.appendChild(row);
|
||||
});
|
||||
updateMmcButton();
|
||||
}
|
||||
|
||||
function selectedMmc() {
|
||||
return [...document.querySelectorAll('#mmc-list input[type=checkbox]')]
|
||||
.filter((c) => c.checked)
|
||||
.map((c) => mmcFound[Number(c.dataset.idx)]);
|
||||
}
|
||||
|
||||
function updateMmcButton() {
|
||||
const n = selectedMmc().length;
|
||||
el('mmc-do').disabled = n === 0;
|
||||
el('mmc-do').textContent = n ? `${n} übernehmen` : 'Übernehmen';
|
||||
}
|
||||
|
||||
async function runMmcImport() {
|
||||
const entries = selectedMmc();
|
||||
if (!entries.length) return;
|
||||
const copy = el('mmc-copy').checked;
|
||||
el('mmc-do').disabled = true;
|
||||
el('mmc-progress').textContent = 'Übernehme …';
|
||||
|
||||
const res = await window.api.mmcImport(entries, copy);
|
||||
await reload();
|
||||
hide('modal-mmc');
|
||||
const n = res.imported.length;
|
||||
const f = res.failed.length;
|
||||
toast(`${n} Instanz${n === 1 ? '' : 'en'} übernommen${f ? ` · ${f} fehlgeschlagen` : ''}.`, f > 0);
|
||||
if (instances.length) await selectInstance(instances[0].id);
|
||||
}
|
||||
|
||||
// ---------- Bedrock (Windows-Store-Ausgabe) ----------
|
||||
let bedrockKind = 'worlds';
|
||||
|
||||
// Bedrock-Knopf nur zeigen, wenn aktiviert UND tatsächlich installiert
|
||||
async function applyBedrockVisibility() {
|
||||
const btn = el('btn-bedrock');
|
||||
let show = false;
|
||||
try {
|
||||
const s = await window.api.getSettings();
|
||||
if (s.bedrockEnabled !== false) {
|
||||
const info = await window.api.bedrockDetect();
|
||||
show = !!info.installed;
|
||||
const hint = el('s-bedrock-hint');
|
||||
if (hint) {
|
||||
hint.textContent = info.installed
|
||||
? 'Bedrock erkannt (Version ' + info.version + ').'
|
||||
: 'Bedrock ist auf diesem PC nicht installiert – der Bereich bleibt ausgeblendet.';
|
||||
}
|
||||
}
|
||||
} catch { /* im Zweifel ausblenden */ }
|
||||
btn.classList.toggle('hidden', !show);
|
||||
}
|
||||
|
||||
async function openBedrock() {
|
||||
show('modal-bedrock');
|
||||
el('bd-sub').textContent = 'Wird geprüft …';
|
||||
const info = await window.api.bedrockDetect();
|
||||
if (!info.installed) {
|
||||
el('bd-sub').textContent = 'nicht installiert';
|
||||
el('bd-missing').classList.remove('hidden');
|
||||
el('bd-content').classList.add('hidden');
|
||||
return;
|
||||
}
|
||||
el('bd-missing').classList.add('hidden');
|
||||
el('bd-content').classList.remove('hidden');
|
||||
el('bd-sub').textContent = 'Version ' + info.version;
|
||||
switchBedrockTab('worlds');
|
||||
}
|
||||
|
||||
function switchBedrockTab(kind) {
|
||||
bedrockKind = kind;
|
||||
document.querySelectorAll('.btab').forEach((t) => t.classList.toggle('on', t.dataset.kind === kind));
|
||||
renderBedrockList();
|
||||
}
|
||||
|
||||
function fmtBytes(n) {
|
||||
if (!n) return '';
|
||||
if (n < 1024) return n + ' B';
|
||||
if (n < 1048576) return (n / 1024).toFixed(0) + ' KB';
|
||||
return (n / 1048576).toFixed(1) + ' MB';
|
||||
}
|
||||
|
||||
async function renderBedrockList() {
|
||||
const box = el('bd-list');
|
||||
box.innerHTML = '<div class="mods-empty">Lade …</div>';
|
||||
const kind = bedrockKind;
|
||||
const items = kind === 'worlds' ? await window.api.bedrockWorlds() : await window.api.bedrockList(kind);
|
||||
|
||||
box.innerHTML = '';
|
||||
if (!items.length) {
|
||||
const leer = {
|
||||
worlds: 'Noch keine Welten vorhanden.',
|
||||
resource_packs: 'Keine Ressourcenpakete installiert.',
|
||||
behavior_packs: 'Keine Verhaltenspakete installiert.',
|
||||
skin_packs: 'Keine Skin-Pakete installiert.',
|
||||
screenshots: 'Noch keine Bildschirmfotos.',
|
||||
};
|
||||
box.innerHTML = `<div class="mods-empty">${leer[kind] || 'Nichts vorhanden.'}</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const it of items) {
|
||||
const name = it.name || it.id;
|
||||
const item = document.createElement('div');
|
||||
item.className = 'mod-item';
|
||||
const meta = [fmtBytes(it.bytes), it.modified ? fmtDate(it.modified) : ''].filter(Boolean).join(' · ');
|
||||
item.innerHTML =
|
||||
`<div class="mod-icon">${kind === 'worlds' ? '🌍' : kind === 'screenshots' ? '🖼' : '📦'}</div>
|
||||
<div class="mod-info">
|
||||
<div class="mod-name">${escapeHtml(name)}</div>
|
||||
<div class="bd-meta">${escapeHtml(meta)}</div>
|
||||
</div>
|
||||
<div class="mod-action"></div>`;
|
||||
|
||||
const actions = item.querySelector('.mod-action');
|
||||
if (kind === 'worlds') {
|
||||
const open = document.createElement('button');
|
||||
open.className = 'btn btn-mini';
|
||||
open.textContent = 'Ordner';
|
||||
open.addEventListener('click', () => window.api.bedrockOpenWorld(it.dir));
|
||||
actions.appendChild(open);
|
||||
}
|
||||
const del = document.createElement('button');
|
||||
del.className = 'btn btn-danger btn-mini';
|
||||
del.textContent = 'Löschen';
|
||||
del.addEventListener('click', () => askConfirm(
|
||||
'Löschen', `„${name}" wird unwiderruflich gelöscht. Fortfahren?`, 'Endgültig löschen',
|
||||
async () => {
|
||||
await window.api.bedrockRemove(kind, kind === 'worlds' ? it.id : it.name);
|
||||
await renderBedrockList();
|
||||
toast('Gelöscht: ' + name);
|
||||
}));
|
||||
actions.appendChild(del);
|
||||
box.appendChild(item);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Kontextmenü (Rechtsklick auf eine Instanz) ----------
|
||||
function openContextMenu(x, y) {
|
||||
const menu = el('ctx-menu');
|
||||
@@ -1222,6 +1410,7 @@ async function openSettings() {
|
||||
el('s-bgskin-pose').value = s.bgSkinPose || 'walking';
|
||||
el('s-sortby').value = s.sortBy || 'lastPlayed';
|
||||
el('s-iso3d').checked = s.iso3dIcons !== false;
|
||||
el('s-bedrock').checked = s.bedrockEnabled !== false;
|
||||
el('s-console-launch').checked = !!s.showConsoleOnLaunch;
|
||||
el('s-console-autoclose').checked = !!s.autoCloseConsole;
|
||||
el('s-console-crash').checked = s.showConsoleOnCrash !== false;
|
||||
@@ -1245,16 +1434,24 @@ async function openSettings() {
|
||||
|
||||
const info = await window.api.appInfo();
|
||||
el('s-appinfo').innerHTML =
|
||||
`AeroMC ${info.version} · Electron ${info.electron} · Node ${info.node}<br>` +
|
||||
`<span class="mono">${escapeHtml(info.userData)}</span>`;
|
||||
`Version ${info.version}<br><span class="mono">${escapeHtml(info.userData)}</span>`;
|
||||
show('modal-settings');
|
||||
await renderAccounts('s-accounts'); // Konten direkt in den Einstellungen zeigen
|
||||
applyBedrockVisibility(); // aktualisiert auch den Hinweistext
|
||||
}
|
||||
|
||||
async function refreshJavaStatus(javaPath) {
|
||||
el('s-java-status').textContent = 'Prüfe Java …';
|
||||
const box = el('s-java-status');
|
||||
box.className = 'hint';
|
||||
box.textContent = 'Prüfe Java …';
|
||||
const r = await window.api.detectJava(javaPath);
|
||||
el('s-java-status').textContent = r.ok ? '✔ ' + r.version : '✖ Java nicht gefunden (' + (r.error || 'unbekannt') + ')';
|
||||
el('s-java-status').style.color = r.ok ? 'var(--accent-hover)' : 'var(--danger-hover)';
|
||||
if (r.ok) {
|
||||
box.classList.add('status-ok'); // grün, wenn Java passt
|
||||
box.textContent = '✔ ' + r.version;
|
||||
} else {
|
||||
box.classList.add('status-bad');
|
||||
box.textContent = '✖ Java nicht gefunden (' + (r.error || 'unbekannt') + ')';
|
||||
}
|
||||
}
|
||||
|
||||
async function scanJava() {
|
||||
@@ -1287,6 +1484,7 @@ async function saveSettings() {
|
||||
bgSkinPose: el('s-bgskin-pose').value,
|
||||
sortBy: el('s-sortby').value,
|
||||
iso3dIcons: el('s-iso3d').checked,
|
||||
bedrockEnabled: el('s-bedrock').checked,
|
||||
showConsoleOnLaunch: el('s-console-launch').checked,
|
||||
autoCloseConsole: el('s-console-autoclose').checked,
|
||||
showConsoleOnCrash: el('s-console-crash').checked,
|
||||
@@ -1309,6 +1507,7 @@ async function saveSettings() {
|
||||
await window.api.saveSettings(patch);
|
||||
applyTheme(patch.theme);
|
||||
iso3dEnabled = patch.iso3dIcons;
|
||||
await applyBedrockVisibility();
|
||||
await applySkinBackground();
|
||||
hide('modal-settings');
|
||||
toast('Einstellungen gespeichert.');
|
||||
@@ -1333,9 +1532,16 @@ async function refreshAccountButton() {
|
||||
}
|
||||
}
|
||||
|
||||
async function renderAccounts() {
|
||||
// aktualisiert Kontoliste im Login-Dialog und in den Einstellungen
|
||||
async function refreshAllAccountLists() {
|
||||
await renderAccounts('login-accounts');
|
||||
if (!el('modal-settings').classList.contains('hidden')) await renderAccounts('s-accounts');
|
||||
}
|
||||
|
||||
async function renderAccounts(boxId = 'login-accounts') {
|
||||
const accounts = await window.api.authAccounts();
|
||||
const box = el('login-accounts');
|
||||
const box = el(boxId);
|
||||
if (!box) return;
|
||||
box.innerHTML = '';
|
||||
if (!accounts.length) {
|
||||
box.innerHTML = '<div class="account-empty">Noch kein Konto angemeldet.</div>';
|
||||
@@ -1369,7 +1575,7 @@ async function renderAccounts() {
|
||||
use.textContent = 'Aktivieren';
|
||||
use.addEventListener('click', async () => {
|
||||
await window.api.authSetActive(a.id);
|
||||
await renderAccounts();
|
||||
await refreshAllAccountLists();
|
||||
await refreshAccountButton();
|
||||
await applySkinBackground();
|
||||
toast('Aktiv: ' + a.name);
|
||||
@@ -1381,7 +1587,7 @@ async function renderAccounts() {
|
||||
rm.textContent = 'Entfernen';
|
||||
rm.addEventListener('click', async () => {
|
||||
await window.api.authRemove(a.id);
|
||||
await renderAccounts();
|
||||
await refreshAllAccountLists();
|
||||
await refreshAccountButton();
|
||||
toast('Entfernt: ' + a.name);
|
||||
});
|
||||
@@ -1399,7 +1605,7 @@ function resetLoginHint() {
|
||||
async function openLogin() {
|
||||
el('login-code').classList.add('hidden');
|
||||
resetLoginHint();
|
||||
await renderAccounts();
|
||||
await refreshAllAccountLists();
|
||||
show('modal-login');
|
||||
}
|
||||
|
||||
@@ -1414,7 +1620,7 @@ async function addAccount() {
|
||||
const res = await window.api.authLogin(); // läuft bis zur Bestätigung
|
||||
el('login-code').classList.add('hidden');
|
||||
if (res.ok) {
|
||||
await renderAccounts();
|
||||
await refreshAllAccountLists();
|
||||
await refreshAccountButton();
|
||||
toast('Angemeldet als ' + res.account.profile.name);
|
||||
} else {
|
||||
@@ -1516,6 +1722,41 @@ function wire() {
|
||||
if (h.ok) toast('Anmelde-Dienste wieder erreichbar.');
|
||||
});
|
||||
|
||||
// MultiMC-Import
|
||||
el('btn-mmc').addEventListener('click', () => { hide('modal-settings'); openMmc(); });
|
||||
el('mmc-pick').addEventListener('click', async () => {
|
||||
const p = await window.api.mmcPickFolder();
|
||||
if (p) { el('mmc-path').value = p; await scanMmc(); }
|
||||
});
|
||||
el('mmc-scan').addEventListener('click', scanMmc);
|
||||
el('mmc-path').addEventListener('keydown', (e) => { if (e.key === 'Enter') scanMmc(); });
|
||||
el('mmc-all').addEventListener('change', (e) => {
|
||||
document.querySelectorAll('#mmc-list input[type=checkbox]').forEach((c) => { c.checked = e.target.checked; });
|
||||
updateMmcButton();
|
||||
});
|
||||
el('mmc-list').addEventListener('change', updateMmcButton);
|
||||
el('mmc-do').addEventListener('click', runMmcImport);
|
||||
window.api.onMmcProgress((p) => {
|
||||
el('mmc-progress').textContent = `Übernehme … ${p.current}/${p.total}`;
|
||||
});
|
||||
|
||||
// Bedrock
|
||||
el('btn-bedrock').addEventListener('click', openBedrock);
|
||||
el('bd-play').addEventListener('click', async () => {
|
||||
const res = await window.api.bedrockLaunch();
|
||||
if (res && res.ok) toast('Bedrock wird gestartet …');
|
||||
else toast('Start fehlgeschlagen: ' + ((res && res.message) || 'unbekannter Fehler'), true);
|
||||
});
|
||||
el('bd-import').addEventListener('click', async () => {
|
||||
const res = await window.api.bedrockInstallAddon();
|
||||
if (res.canceled) return;
|
||||
if (res.ok) toast('Import gestartet – Minecraft übernimmt die Installation.');
|
||||
else toast(res.message || 'Import fehlgeschlagen.', true);
|
||||
});
|
||||
el('bd-folder').addEventListener('click', () => window.api.bedrockOpenFolder(bedrockKind));
|
||||
document.querySelectorAll('.btab').forEach((t) =>
|
||||
t.addEventListener('click', () => switchBedrockTab(t.dataset.kind)));
|
||||
|
||||
// Konsole
|
||||
el('btn-console').addEventListener('click', openConsole);
|
||||
el('console-clear').addEventListener('click', () => { consoleBuffer = ''; el('console-out').textContent = ''; });
|
||||
@@ -1631,6 +1872,7 @@ function wire() {
|
||||
document.querySelectorAll('.spane').forEach((p) => p.classList.toggle('hidden', p.id !== b.dataset.pane));
|
||||
}));
|
||||
el('s-open-accounts').addEventListener('click', () => { hide('modal-settings'); openLogin(); });
|
||||
el('s-add-account').addEventListener('click', () => { hide('modal-settings'); openLogin().then(addAccount); });
|
||||
|
||||
// Updates
|
||||
el('upd-install').addEventListener('click', startUpdate);
|
||||
@@ -1699,6 +1941,7 @@ window.addEventListener('DOMContentLoaded', async () => {
|
||||
window.api.onUpdateProgress(onUpdateProgress);
|
||||
try { showAuthHealth(await window.api.authHealth()); } catch { /* noch keine Prüfung */ }
|
||||
await loadMcIcons(); // echte Minecraft-Icons bereitstellen
|
||||
await applyBedrockVisibility();
|
||||
await refreshAccountButton();
|
||||
await reload();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user