Upload via GUI (21 Dateien)

This commit is contained in:
Git Manager GUI
2026-08-01 19:32:20 +02:00
parent afe02f81be
commit 7a6b31fb11
13 changed files with 858 additions and 20 deletions
+254 -11
View File
@@ -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();