Launcher 0.3.3: Freunde-Eingabe bleibt, Lobby eines Freundes beitreten
Das Feld Benutzername wird beim Aktualisieren nicht mehr neu angelegt (Text, Fokus und Cursor bleiben), neu gezeichnet wird nur bei Aenderungen. Beitreten-Knopf bei Freunden mit Lobby und Liste der Freundes-Lobbys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>BSO.Launcher</RootNamespace>
|
||||
<AssemblyName>BSO-Launcher</AssemblyName>
|
||||
<Version>0.3.2</Version>
|
||||
<Version>0.3.3</Version>
|
||||
<Company>MBM.wtf</Company>
|
||||
<Product>BSO Launcher</Product>
|
||||
<Description>BSO Launcher - Bus Simulator Online</Description>
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
Neue Version: hier einen Abschnitt `## <Version>` anlegen, `<Version>` in `BSO.Launcher.csproj` erhöhen, dann
|
||||
`dotnet publish -c Release -o publish` – lädt die Version hoch; der Abschnitt wird der Changelog auf der Website und im Launcher.
|
||||
|
||||
## 0.3.3
|
||||
- Freunde: Was man ins Feld „Benutzername“ tippt, verschwindet nicht mehr nach ein paar Sekunden
|
||||
- Lobby eines Freundes beitreten, auch ohne Einladung („Beitreten“ beim Freund und unter „Lobbys deiner Freunde“)
|
||||
|
||||
## 0.3.2
|
||||
- Auto-Update wie beim MSCO Launcher: ein neuer Launcher installiert sich beim Start sofort selbst und startet neu,
|
||||
neue BSO-Versionen kommen beim Start (beides in den Einstellungen abschaltbar)
|
||||
|
||||
@@ -275,7 +275,11 @@ let socialTick = 0;
|
||||
setInterval(async () => {
|
||||
if ($("app").classList.contains("hidden")) return;
|
||||
if (page !== "friends" && socialTick++ % 5 !== 0) return;
|
||||
try { await loadSocial(); if (page === "friends") drawSocial(); } catch { }
|
||||
const before = JSON.stringify(social);
|
||||
try {
|
||||
await loadSocial();
|
||||
if (page === "friends" && JSON.stringify(social) !== before) drawSocial(); // nur neu zeichnen, wenn sich was geaendert hat
|
||||
} catch { }
|
||||
}, 3000);
|
||||
|
||||
async function renderFriends(root) {
|
||||
@@ -297,14 +301,34 @@ function action(label, cls, cmd, args, done) {
|
||||
return b;
|
||||
}
|
||||
|
||||
// Eingabefeld "Freund hinzufuegen" bleibt ueber das Neuzeichnen hinweg dasselbe - sonst waere Getipptes weg
|
||||
const friendName = h("input", { maxlength: "32", spellcheck: "false" });
|
||||
|
||||
function drawSocial() {
|
||||
const root = $("socialRoot");
|
||||
if (!root) return;
|
||||
const typing = document.activeElement === friendName;
|
||||
const [start, end] = [friendName.selectionStart, friendName.selectionEnd];
|
||||
root.replaceChildren(lobbyCard(), friendsCard());
|
||||
if (typing) { friendName.focus(); friendName.setSelectionRange(start, end); }
|
||||
}
|
||||
|
||||
/** Der Lobby eines Freundes beitreten - auch ohne Einladung. Wer selbst eine Lobby erstellt hat, loest sie dabei auf. */
|
||||
function joinButton(fl) {
|
||||
const b = h("button", { class: "btn small primary", type: "button" }, t("Beitreten"));
|
||||
b.disabled = fl.full;
|
||||
if (fl.full) b.title = t("Die Lobby ist voll");
|
||||
b.addEventListener("click", () => {
|
||||
const mine = social.lobby.lobby;
|
||||
if (mine && mine.isOwner && !confirm(t("Deine Lobby wird dabei aufgelöst. Trotzdem {0} beitreten?", fl.owner))) return;
|
||||
busy(b, async () => { await call("lobbyJoin", { lobbyId: fl.lobbyId }); await loadSocial(); drawSocial(); });
|
||||
});
|
||||
return b;
|
||||
}
|
||||
|
||||
function lobbyCard() {
|
||||
const { lobby, invites } = social.lobby;
|
||||
const friendLobbies = social.lobby.friendLobbies || [];
|
||||
const card = h("div", { class: "card" });
|
||||
for (const i of invites)
|
||||
card.append(h("div", { class: "invite" }, h("span", {}, h("b", {}, i.owner), t(" lädt dich in die Lobby ein")),
|
||||
@@ -314,6 +338,13 @@ function lobbyCard() {
|
||||
card.append(h("h3", {}, t("Lobby")),
|
||||
h("p", { class: "muted small" }, t("Erstelle eine Lobby und lade Freunde ein. Der Server läuft auf dem BSO-Relay – niemand muss etwas hosten oder Ports freigeben.")),
|
||||
h("div", { class: "row" }, action(t("Lobby erstellen"), "primary", "lobbyCreate")));
|
||||
if (friendLobbies.length)
|
||||
card.append(h("div", { class: "section-title" }, t("Lobbys deiner Freunde")),
|
||||
h("div", { class: "people" }, ...friendLobbies.map((fl) => h("div", { class: "person" },
|
||||
h("span", { class: "dot " + (fl.serverOnline ? "ok" : "") }),
|
||||
h("span", { class: "name" }, t("Lobby von {0}", fl.owner)),
|
||||
h("span", { class: "muted small" }, t("{0} Spieler", fl.members)),
|
||||
joinButton(fl)))));
|
||||
return card;
|
||||
}
|
||||
|
||||
@@ -350,7 +381,8 @@ function lobbyCard() {
|
||||
function friendsCard() {
|
||||
const { friends, incoming, outgoing } = social.friends;
|
||||
const lobby = social.lobby.lobby;
|
||||
const name = h("input", { placeholder: t("Benutzername"), maxlength: "32", spellcheck: "false" });
|
||||
const name = friendName;
|
||||
name.placeholder = t("Benutzername");
|
||||
const add = h("button", { class: "btn small primary", type: "button" }, t("Hinzufügen"));
|
||||
const send = () => busy(add, async () => {
|
||||
if (!name.value.trim()) return;
|
||||
@@ -361,7 +393,7 @@ function friendsCard() {
|
||||
drawSocial();
|
||||
});
|
||||
add.addEventListener("click", send);
|
||||
name.addEventListener("keydown", (e) => { if (e.key === "Enter") send(); });
|
||||
name.onkeydown = (e) => { if (e.key === "Enter") send(); }; // onkeydown statt addEventListener: das Feld bleibt, der Knopf ist neu
|
||||
|
||||
const card = h("div", { class: "card" }, h("h3", {}, t("Freunde")), h("div", { class: "row" }, name, add));
|
||||
if (incoming.length)
|
||||
@@ -373,12 +405,14 @@ function friendsCard() {
|
||||
card.append(h("div", { class: "people" }, ...friends.map((f) => {
|
||||
const inLobby = lobby && lobby.members.some((m) => m.accountId === f.accountId);
|
||||
const invited = lobby && lobby.invited.includes(f.accountId);
|
||||
const theirLobby = (social.lobby.friendLobbies || []).find((fl) => fl.ownerId === f.accountId);
|
||||
const remove = h("button", { class: "x", type: "button", title: t("Freund entfernen") }, "");
|
||||
remove.addEventListener("click", () => { if (confirm(t("{0} als Freund entfernen?", f.username))) busy(remove, async () => { await call("friendRemove", { id: f.id }); await loadSocial(); drawSocial(); }); });
|
||||
return h("div", { class: "person" },
|
||||
h("span", { class: "dot " + (f.online ? "ok" : "") }), h("span", { class: "name" }, f.username),
|
||||
lobby && lobby.isOwner && !inLobby ? (invited ? h("span", { class: "muted small" }, t("eingeladen")) : action(t("Einladen"), "", "lobbyInvite", { accountId: f.accountId })) : null,
|
||||
inLobby ? h("span", { class: "muted small" }, t("in der Lobby")) : null,
|
||||
!inLobby && theirLobby ? joinButton(theirLobby) : null,
|
||||
remove);
|
||||
})));
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ const EN = {
|
||||
"Server läuft – alle können SPIELEN drücken": "Server is running – everyone can press PLAY",
|
||||
"Drück SPIELEN – der Server startet dann für die ganze Lobby": "Press PLAY – the server then starts for the whole lobby",
|
||||
"Warte, bis {0} SPIELEN drückt – dann startet der Server": "Waiting for {0} to press PLAY – then the server starts", "Server stoppen": "Stop server",
|
||||
"Lobbys deiner Freunde": "Your friends' lobbies", "{0} Spieler": "{0} players", "Die Lobby ist voll": "The lobby is full",
|
||||
"Deine Lobby wird dabei aufgelöst. Trotzdem {0} beitreten?": "Your lobby will be closed. Join {0} anyway?",
|
||||
"Ersteller": "Owner", "Entfernen": "Remove", "Deine Lobby": "Your lobby", "Lobby von {0}": "{0}'s lobby", "Mitglieder ({0})": "Members ({0})",
|
||||
"{0} Einladung(en) offen": "{0} invitation(s) pending", "Lobby auflösen": "Close lobby", "Lobby verlassen": "Leave lobby",
|
||||
"Hinzufügen": "Add", "Anfrage an {0} geschickt": "Request sent to {0}", "Anfragen": "Requests", "Annehmen": "Accept",
|
||||
|
||||
Reference in New Issue
Block a user