Compare commits

..

2 commits

Author SHA1 Message Date
903aedc8ce add groups (TEST)
All checks were successful
Android Build / publish (push) Successful in 57s
Linux Build / publish (push) Successful in 1m3s
2026-08-01 15:19:27 +02:00
afd6a87228 fix larp.info* text wrap and message context menu positioning 2026-07-29 16:19:27 +02:00
14 changed files with 3134 additions and 1404 deletions

View file

@ -10,6 +10,8 @@
"dm.accepted": "direct meowchat accepted", "dm.accepted": "direct meowchat accepted",
"no.invite.found": "you can't create a dm without invitation *hiss*", "no.invite.found": "you can't create a dm without invitation *hiss*",
"unknown.error": "unknown error :o", "unknown.error": "unknown error :o",
"missing.keys": "cannot rotate nametags: some kitties don't have public nametags available yet. they must set up their identity.",
"key.rotated": "meowchat keys have been successfully rotated! meow!",
"forbidden": "you do not have pawmission to perform this action *hiss*", "forbidden": "you do not have pawmission to perform this action *hiss*",
"dm.key.too.large": "meowchat key too large :o", "dm.key.too.large": "meowchat key too large :o",
"dm.key.not.found": "meowchat key not found :c", "dm.key.not.found": "meowchat key not found :c",
@ -125,6 +127,7 @@
"desc.messages.loading": "loading meows...", "desc.messages.loading": "loading meows...",
"desc.no.dms": "no direct meowchats :c", "desc.no.dms": "no direct meowchats :c",
"action.dm.opening": "opening meowchat...", "action.dm.opening": "opening meowchat...",
"action.group.opening": "opening clowder...",
"dm.open.failed": "failed to open meowchat :c", "dm.open.failed": "failed to open meowchat :c",
"keys.local.server.mismatch": "this device has different nametags than server :c use the device u first logged in on", "keys.local.server.mismatch": "this device has different nametags than server :c use the device u first logged in on",
"keys.server.decrypt.failed": "wrong password for ur secret nametag bundle :c", "keys.server.decrypt.failed": "wrong password for ur secret nametag bundle :c",
@ -201,5 +204,58 @@
"message.unpinned.by": "{0} unpinned a {1}.", "message.unpinned.by": "{0} unpinned a {1}.",
"title.pinned.messages": "Pinned", "title.pinned.messages": "Pinned",
"error.pinned.messages.empty": "No pinned meows", "error.pinned.messages.empty": "No pinned meows",
"title.message.lowercase": "meowsage" "title.message.lowercase": "meowsage",
"action.rotate.keys": "Meowtate Keys",
"already.in.group": "Meowready in group",
"desc.key.rotation.info": "Meow need to purrotate meowcription keys to purrtinue sending meowsages in this group. Other meowmbers will autopurrtically receive the new key.",
"desc.no.groups": "Meow are not in any groups yet.",
"dm.read": "Purread",
"empty.body": "Empty meowdy",
"failed.create.group": "Failed to purreate group",
"federation.not.implemented": "Meowderation not implemeowted",
"group.not.found": "Group not meownd",
"group.read": "Purread",
"invalid.entry.name": "Invalid purrtry name",
"invalid.key.index": "Invalid key index (purrlease purrefresh the page)",
"invalid.msg.id": "Invalid meowsage ID",
"invalid.payload": "Invalid purrload",
"invalid.reaction.id": "Invalid purreaction ID",
"invalid.user": "Invalid meowser",
"joined": "Purroined",
"key.rotation.required": "Key purrotation meowquired",
"key.too.large": "Key too meowrge",
"keys.public.mismatch": "Public keys mismemeow",
"label.members": "MEOWMBERS",
"message.deleted": "Meowsage purrleted",
"message.not.found": "Meowsage not meownd",
"message.pin.toggled": "Meowsage purrin purrggled",
"message.reacted": "Meowsage purreacted",
"message.reaction.removed": "Purreaction remeowed",
"no.invite": "No meowvite",
"not.a.member": "Not a meowmber",
"not.in.group": "Not in purroup",
"reaction.not.found": "Purreaction not meownd",
"rotation.not.required": "Purrotation not meowquired",
"storage.entry.updated": "Storage purrtry updated",
"storage.limit.exceeded": "Storage limit exmeowded",
"title.key.rotation": "Key Purrotation",
"error:messages.decrypt.failed": "Depurryption meowled",
"error.message.already.deleted": "Meowsage alpurrdy meowleted",
"group.user.joined.by": "{0} purroined the group",
"group.created.by": "Group purreated by {0}",
"group.user.left.by": "{0} left the purroup",
"action.group.fetch": "Meowtching groups",
"group.created": "Group purreated",
"group.user.joined": "Purroined group",
"prompt.invite.username": "Enter username to invite meow:",
"desc.failed.load.members": "Failed to load members meow",
"prompt.are.you.sure": "Are you sure meow?",
"title.unknown.group": "Unknown Group meow",
"title.unknown": "Unknown meow",
"en-us": "English meow",
"pl-pl": "Polish meow",
"en-cat": "Meowlish",
"avatar.updated": "Avatar updated successfully",
"profile.updated": "Profile updated successfully",
"banner.updated": "Banner updated successfully"
} }

View file

@ -10,6 +10,8 @@
"dm.accepted": "DM accepted", "dm.accepted": "DM accepted",
"no.invite.found": "You can't create a dm without invitation", "no.invite.found": "You can't create a dm without invitation",
"unknown.error": "Unknown error", "unknown.error": "Unknown error",
"missing.keys": "Cannot rotate keys: Some members don't have public keys available yet. They must configure their identity.",
"key.rotated": "Group keys have been successfully rotated.",
"forbidden": "You do not have permission to perform this action", "forbidden": "You do not have permission to perform this action",
"dm.key.too.large": "DM key too large", "dm.key.too.large": "DM key too large",
"dm.key.not.found": "DM key not found", "dm.key.not.found": "DM key not found",
@ -124,6 +126,7 @@
"desc.messages.loading": "Fetching messages...", "desc.messages.loading": "Fetching messages...",
"desc.no.dms": "No direct messages", "desc.no.dms": "No direct messages",
"action.dm.opening": "Opening DM...", "action.dm.opening": "Opening DM...",
"action.group.opening": "Opening group...",
"dm.open.failed": "Failed to open DM", "dm.open.failed": "Failed to open DM",
"keys.local.server.mismatch": "This device has different encryption keys than the server. Use the device where you first logged in, or restore server keys from backup.", "keys.local.server.mismatch": "This device has different encryption keys than the server. Use the device where you first logged in, or restore server keys from backup.",
"keys.server.decrypt.failed": "Could not decrypt your account keys with this password.", "keys.server.decrypt.failed": "Could not decrypt your account keys with this password.",
@ -201,5 +204,58 @@
"message.unpinned.by": "{0} unpinned a {1}.", "message.unpinned.by": "{0} unpinned a {1}.",
"title.pinned.messages": "Pinned", "title.pinned.messages": "Pinned",
"error.pinned.messages.empty": "No pinned messages", "error.pinned.messages.empty": "No pinned messages",
"title.message.lowercase": "message" "title.message.lowercase": "message",
"action.rotate.keys": "Rotate Keys",
"already.in.group": "Already in group",
"desc.key.rotation.info": "You need to rotate encryption keys to continue sending messages in this group. Other members will automatically receive the new key.",
"desc.no.groups": "You are not in any groups yet.",
"dm.read": "Read",
"empty.body": "Empty body",
"failed.create.group": "Failed to create group",
"federation.not.implemented": "Federation not implemented",
"group.not.found": "Group not found",
"group.read": "Read",
"invalid.entry.name": "Invalid entry name",
"invalid.key.index": "Invalid key index (please refresh the page)",
"invalid.msg.id": "Invalid message ID",
"invalid.payload": "Invalid payload",
"invalid.reaction.id": "Invalid reaction ID",
"invalid.user": "Invalid user",
"joined": "Joined",
"key.rotation.required": "Key rotation required",
"key.too.large": "Key too large",
"keys.public.mismatch": "Public keys mismatch",
"label.members": "MEMBERS",
"message.deleted": "Message deleted",
"message.not.found": "Message not found",
"message.pin.toggled": "Message pin toggled",
"message.reacted": "Message reacted",
"message.reaction.removed": "Reaction removed",
"no.invite": "No invite",
"not.a.member": "Not a member",
"not.in.group": "Not in group",
"reaction.not.found": "Reaction not found",
"rotation.not.required": "Rotation not required",
"storage.entry.updated": "Storage entry updated",
"storage.limit.exceeded": "Storage limit exceeded",
"title.key.rotation": "Key Rotation",
"error:messages.decrypt.failed": "Decryption failed",
"error.message.already.deleted": "Message already deleted",
"group.user.joined.by": "{0} joined the group",
"group.created.by": "Group created by {0}",
"group.user.left.by": "{0} left the group",
"action.group.fetch": "Fetching groups",
"group.created": "Group created",
"group.user.joined": "Joined group",
"prompt.invite.username": "Enter username to invite:",
"desc.failed.load.members": "Failed to load members",
"prompt.are.you.sure": "Are you sure?",
"title.unknown.group": "Unknown Group",
"title.unknown": "Unknown",
"success:banner.updated": "Banner updated successfully",
"success:profile.updated": "Profile updated successfully",
"success:avatar.updated": "Avatar updated successfully",
"en-us": "English",
"pl-pl": "Polish",
"en-cat": "Meowlish"
} }

View file

@ -124,6 +124,7 @@
"desc.messages.loading": "Pobieranie wiadomości...", "desc.messages.loading": "Pobieranie wiadomości...",
"desc.no.dms": "Brak wiadomości prywatnych", "desc.no.dms": "Brak wiadomości prywatnych",
"action.dm.opening": "Otwieranie rozmowy...", "action.dm.opening": "Otwieranie rozmowy...",
"action.group.opening": "Otwieranie grupy...",
"dm.open.failed": "Nie udało się otworzyć rozmowy", "dm.open.failed": "Nie udało się otworzyć rozmowy",
"keys.local.server.mismatch": "To urządzenie ma inne klucze szyfrowania niż serwer. Użyj urządzenia, na którym zalogowano się po raz pierwszy, lub przywróć klucze z kopii zapasowej.", "keys.local.server.mismatch": "To urządzenie ma inne klucze szyfrowania niż serwer. Użyj urządzenia, na którym zalogowano się po raz pierwszy, lub przywróć klucze z kopii zapasowej.",
"keys.server.decrypt.failed": "Nie udało się odszyfrować kluczy konta przy użyciu tego hasła.", "keys.server.decrypt.failed": "Nie udało się odszyfrować kluczy konta przy użyciu tego hasła.",
@ -201,5 +202,60 @@
"message.unpinned.by": "{0} odpiął {1}.", "message.unpinned.by": "{0} odpiął {1}.",
"title.pinned.messages": "Przypięte", "title.pinned.messages": "Przypięte",
"error.pinned.messages.empty": "Brak przypiętych wiadomości", "error.pinned.messages.empty": "Brak przypiętych wiadomości",
"title.message.lowercase": "wiadomość" "title.message.lowercase": "wiadomość",
"action.rotate.keys": "Rotuj Klucze",
"already.in.group": "Już w grupie",
"desc.key.rotation.info": "Musisz zrotować klucze szyfrujące, aby kontynuować wysyłanie wiadomości w tej grupie. Inni członkowie automatycznie otrzymają nowy klucz.",
"desc.no.groups": "Nie jesteś jeszcze w żadnej grupie.",
"dm.read": "Przeczytano",
"empty.body": "Pusta zawartość",
"failed.create.group": "Nie udało się utworzyć grupy",
"federation.not.implemented": "Federacja niezaimplementowana",
"group.not.found": "Nie znaleziono grupy",
"group.read": "Przeczytano",
"invalid.entry.name": "Nieprawidłowa nazwa wpisu",
"invalid.key.index": "Nieprawidłowy indeks klucza (odśwież stronę)",
"invalid.msg.id": "Nieprawidłowe ID wiadomości",
"invalid.payload": "Nieprawidłowy ładunek",
"invalid.reaction.id": "Nieprawidłowe ID reakcji",
"invalid.user": "Nieprawidłowy użytkownik",
"joined": "Dołączono",
"key.rotation.required": "Wymagana rotacja kluczy",
"key.too.large": "Klucz zbyt duży",
"keys.public.mismatch": "Niezgodność kluczy publicznych",
"label.members": "CZŁONKOWIE",
"message.deleted": "Wiadomość usunięta",
"message.not.found": "Nie znaleziono wiadomości",
"message.pin.toggled": "Zmieniono przypięcie wiadomości",
"message.reacted": "Dodano reakcję",
"message.reaction.removed": "Reakcja usunięta",
"no.invite": "Brak zaproszenia",
"not.a.member": "Nie jesteś członkiem",
"not.in.group": "Nie jesteś w grupie",
"reaction.not.found": "Nie znaleziono reakcji",
"rotation.not.required": "Rotacja niewymagana",
"storage.entry.updated": "Zaktualizowano wpis pamięci",
"storage.limit.exceeded": "Przekroczono limit pamięci",
"title.key.rotation": "Rotacja kluczy",
"missing.keys": "Brakujące klucze",
"error:messages.decrypt.failed": "Deszyfrowanie nie powiodło się",
"error.message.already.deleted": "Wiadomość została już usunięta",
"group.user.joined.by": "{0} dołączył do grupy",
"group.created.by": "Grupa utworzona przez {0}",
"group.user.left.by": "{0} opuścił grupę",
"action.group.fetch": "Pobieranie grup",
"group.created": "Utworzono grupę",
"group.user.joined": "Dołączono do grupy",
"prompt.invite.username": "Podaj nazwę użytkownika, aby zaprosić:",
"desc.failed.load.members": "Nie udało się załadować członków",
"prompt.are.you.sure": "Czy na pewno?",
"title.unknown.group": "Nieznana grupa",
"title.unknown": "Nieznany",
"key.rotated": "Klucze grupy zostały pomyślnie zrotowane.",
"success:banner.updated": "Baner został pomyślnie zaktualizowany",
"success:profile.updated": "Profil został pomyślnie zaktualizowany",
"success:avatar.updated": "Awatar został pomyślnie zaktualizowany",
"en-us": "Angielski",
"pl-pl": "Polski",
"en-cat": "Koci (Meowlish)"
} }

View file

@ -119,6 +119,25 @@
</div> </div>
</div> </div>
</div> </div>
<div id="rotation-popup-container" class="profile-popup-container" style="display: none; z-index: 9999;">
<div class="profile-popup-bg" onclick="closeRotationPopup()"></div>
<div class="profile-popup-content">
<button class="profile-popup-close-btn" onclick="closeRotationPopup()">
<script>
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.close());
document.currentScript.remove();
</script>
</button>
<div id="profile-popup-inner" style="padding: 2rem; display: flex; flex-direction: column; align-items: center; gap: 1rem;">
<div style="font-size: 1.2rem; font-weight: 500; text-align: center;"><blah>title.key.rotation</blah></div>
<div style="width: 100%; text-align: center; color: var(--text-color); opacity: 0.8; margin-top: 1rem; margin-bottom: 1rem;" id="rotation-popup-desc">
<!-- content injected dynamically -->
</div>
<button class="profile-action-btn" onclick="executeKeyRotation()"><blah>action.rotate.keys</blah></button>
</div>
</div>
</div>
</body> </body>
</html> </html>
@ -208,8 +227,59 @@
} }
} }
async function createGroup() { async function refreshGroups(waittime = 0, showLoading = true) {
try {
if (showLoading) showAction("action.group.fetch", "grouprefresh");
await delay(waittime);
if (window.cachedGroups && typeof renderGroups === 'function') {
await renderGroups(window.cachedGroups);
}
let res = await fetchEncrypted("user/group/list");
window.cachedGroups = res;
if (typeof renderGroups === 'function') {
await renderGroups(res);
}
if (showLoading) clearAction("grouprefresh");
}
catch (e) {
if (showLoading) clearAction("grouprefresh");
showBlahNotification("error:group.refresh.failed");
}
}
async function createGroup() {
try {
let groupName = document.getElementById("creategroup-name").value;
if (!groupName || groupName.trim() === "") {
showBlahNotification("error:group.name.empty");
return;
}
showAction("action.group.creating", "group.action");
await ensureUserKeys();
const roomKey = randomRoomKey256Chars();
const selfWrapped = await wrapRoomKeyForSelf(roomKey);
let payload = JSON.stringify({
string1: groupName,
string2: selfWrapped
});
let res = await fetchEncrypted("group/create", payload);
clearAction("group.action");
if (res.startsWith("success:")) {
showBlahNotification("success:group.created");
await refreshGroups(200, false);
} else {
showBlahNotification(res || "error:something.wrong");
}
} catch (e) {
clearAction("group.action");
showBlahNotification("error:something.wrong");
console.error(e);
}
} }
</script> </script>
<script src="gifuct.js"></script> <script src="gifuct.js"></script>

File diff suppressed because it is too large Load diff

View file

@ -117,10 +117,10 @@ var notifisScreen = `
var invitesEntry = ` var invitesEntry = `
<div class="invite-entry"> <div class="invite-entry">
<div class="invite-info"> <div class="invite-info">
<img src="{pfp}" class="invite-pfp" onclick="openProfile('{id}')" style="cursor: pointer;"> <img src="{pfp}" class="invite-pfp" {onclick_attr}>
<div class="invite-details"> <div class="invite-details">
<span class="invite-name" onclick="openProfile('{id}')" style="cursor: pointer;">{username}</span> <span class="invite-name" {onclick_attr}>{username}</span>
<span class="invite-desc"><blah>{desc}</blah></span> <span class="invite-desc">{desc}</span>
</div> </div>
</div> </div>
<div class="invite-actions"> <div class="invite-actions">

View file

@ -215,6 +215,25 @@ sidebar {
width: calc(var(--icon-button-height) + (var(--button-margin) * 2) + var(--border-width)); width: calc(var(--icon-button-height) + (var(--button-margin) * 2) + var(--border-width));
border-right: var(--border-width) solid var(--light-border-color); border-right: var(--border-width) solid var(--light-border-color);
} }
sidebar:not(.second) {
overflow-y: auto;
overflow-x: hidden;
}
sidebar:not(.second)::-webkit-scrollbar {
display: none;
}
sidebar:not(.second) {
-ms-overflow-style: none;
scrollbar-width: none;
}
#roomsbar roomcontent2 {
overflow-y: auto;
overflow-x: hidden;
}
sidebar.second { sidebar.second {
width: 17rem; width: 17rem;
min-width: 17rem; min-width: 17rem;

View file

@ -10,6 +10,8 @@
"dm.accepted": "direct meowchat accepted", "dm.accepted": "direct meowchat accepted",
"no.invite.found": "you can't create a dm without invitation *hiss*", "no.invite.found": "you can't create a dm without invitation *hiss*",
"unknown.error": "unknown error :o", "unknown.error": "unknown error :o",
"missing.keys": "cannot rotate nametags: some kitties don't have public nametags available yet. they must set up their identity.",
"key.rotated": "meowchat keys have been successfully rotated! meow!",
"forbidden": "you do not have pawmission to perform this action *hiss*", "forbidden": "you do not have pawmission to perform this action *hiss*",
"dm.key.too.large": "meowchat key too large :o", "dm.key.too.large": "meowchat key too large :o",
"dm.key.not.found": "meowchat key not found :c", "dm.key.not.found": "meowchat key not found :c",
@ -125,6 +127,7 @@
"desc.messages.loading": "loading meows...", "desc.messages.loading": "loading meows...",
"desc.no.dms": "no direct meowchats :c", "desc.no.dms": "no direct meowchats :c",
"action.dm.opening": "opening meowchat...", "action.dm.opening": "opening meowchat...",
"action.group.opening": "opening clowder...",
"dm.open.failed": "failed to open meowchat :c", "dm.open.failed": "failed to open meowchat :c",
"keys.local.server.mismatch": "this device has different nametags than server :c use the device u first logged in on", "keys.local.server.mismatch": "this device has different nametags than server :c use the device u first logged in on",
"keys.server.decrypt.failed": "wrong password for ur secret nametag bundle :c", "keys.server.decrypt.failed": "wrong password for ur secret nametag bundle :c",
@ -201,5 +204,58 @@
"message.unpinned.by": "{0} unpinned a {1}.", "message.unpinned.by": "{0} unpinned a {1}.",
"title.pinned.messages": "Pinned", "title.pinned.messages": "Pinned",
"error.pinned.messages.empty": "No pinned meows", "error.pinned.messages.empty": "No pinned meows",
"title.message.lowercase": "meowsage" "title.message.lowercase": "meowsage",
"action.rotate.keys": "Meowtate Keys",
"already.in.group": "Meowready in group",
"desc.key.rotation.info": "Meow need to purrotate meowcription keys to purrtinue sending meowsages in this group. Other meowmbers will autopurrtically receive the new key.",
"desc.no.groups": "Meow are not in any groups yet.",
"dm.read": "Purread",
"empty.body": "Empty meowdy",
"failed.create.group": "Failed to purreate group",
"federation.not.implemented": "Meowderation not implemeowted",
"group.not.found": "Group not meownd",
"group.read": "Purread",
"invalid.entry.name": "Invalid purrtry name",
"invalid.key.index": "Invalid key index (purrlease purrefresh the page)",
"invalid.msg.id": "Invalid meowsage ID",
"invalid.payload": "Invalid purrload",
"invalid.reaction.id": "Invalid purreaction ID",
"invalid.user": "Invalid meowser",
"joined": "Purroined",
"key.rotation.required": "Key purrotation meowquired",
"key.too.large": "Key too meowrge",
"keys.public.mismatch": "Public keys mismemeow",
"label.members": "MEOWMBERS",
"message.deleted": "Meowsage purrleted",
"message.not.found": "Meowsage not meownd",
"message.pin.toggled": "Meowsage purrin purrggled",
"message.reacted": "Meowsage purreacted",
"message.reaction.removed": "Purreaction remeowed",
"no.invite": "No meowvite",
"not.a.member": "Not a meowmber",
"not.in.group": "Not in purroup",
"reaction.not.found": "Purreaction not meownd",
"rotation.not.required": "Purrotation not meowquired",
"storage.entry.updated": "Storage purrtry updated",
"storage.limit.exceeded": "Storage limit exmeowded",
"title.key.rotation": "Key Purrotation",
"error:messages.decrypt.failed": "Depurryption meowled",
"error.message.already.deleted": "Meowsage alpurrdy meowleted",
"group.user.joined.by": "{0} purroined the group",
"group.created.by": "Group purreated by {0}",
"group.user.left.by": "{0} left the purroup",
"action.group.fetch": "Meowtching groups",
"group.created": "Group purreated",
"group.user.joined": "Purroined group",
"prompt.invite.username": "Enter username to invite meow:",
"desc.failed.load.members": "Failed to load members meow",
"prompt.are.you.sure": "Are you sure meow?",
"title.unknown.group": "Unknown Group meow",
"title.unknown": "Unknown meow",
"en-us": "English meow",
"pl-pl": "Polish meow",
"en-cat": "Meowlish",
"avatar.updated": "Avatar updated successfully",
"profile.updated": "Profile updated successfully",
"banner.updated": "Banner updated successfully"
} }

View file

@ -10,6 +10,8 @@
"dm.accepted": "DM accepted", "dm.accepted": "DM accepted",
"no.invite.found": "You can't create a dm without invitation", "no.invite.found": "You can't create a dm without invitation",
"unknown.error": "Unknown error", "unknown.error": "Unknown error",
"missing.keys": "Cannot rotate keys: Some members don't have public keys available yet. They must configure their identity.",
"key.rotated": "Group keys have been successfully rotated.",
"forbidden": "You do not have permission to perform this action", "forbidden": "You do not have permission to perform this action",
"dm.key.too.large": "DM key too large", "dm.key.too.large": "DM key too large",
"dm.key.not.found": "DM key not found", "dm.key.not.found": "DM key not found",
@ -124,6 +126,7 @@
"desc.messages.loading": "Fetching messages...", "desc.messages.loading": "Fetching messages...",
"desc.no.dms": "No direct messages", "desc.no.dms": "No direct messages",
"action.dm.opening": "Opening DM...", "action.dm.opening": "Opening DM...",
"action.group.opening": "Opening group...",
"dm.open.failed": "Failed to open DM", "dm.open.failed": "Failed to open DM",
"keys.local.server.mismatch": "This device has different encryption keys than the server. Use the device where you first logged in, or restore server keys from backup.", "keys.local.server.mismatch": "This device has different encryption keys than the server. Use the device where you first logged in, or restore server keys from backup.",
"keys.server.decrypt.failed": "Could not decrypt your account keys with this password.", "keys.server.decrypt.failed": "Could not decrypt your account keys with this password.",
@ -201,5 +204,58 @@
"message.unpinned.by": "{0} unpinned a {1}.", "message.unpinned.by": "{0} unpinned a {1}.",
"title.pinned.messages": "Pinned", "title.pinned.messages": "Pinned",
"error.pinned.messages.empty": "No pinned messages", "error.pinned.messages.empty": "No pinned messages",
"title.message.lowercase": "message" "title.message.lowercase": "message",
"action.rotate.keys": "Rotate Keys",
"already.in.group": "Already in group",
"desc.key.rotation.info": "You need to rotate encryption keys to continue sending messages in this group. Other members will automatically receive the new key.",
"desc.no.groups": "You are not in any groups yet.",
"dm.read": "Read",
"empty.body": "Empty body",
"failed.create.group": "Failed to create group",
"federation.not.implemented": "Federation not implemented",
"group.not.found": "Group not found",
"group.read": "Read",
"invalid.entry.name": "Invalid entry name",
"invalid.key.index": "Invalid key index (please refresh the page)",
"invalid.msg.id": "Invalid message ID",
"invalid.payload": "Invalid payload",
"invalid.reaction.id": "Invalid reaction ID",
"invalid.user": "Invalid user",
"joined": "Joined",
"key.rotation.required": "Key rotation required",
"key.too.large": "Key too large",
"keys.public.mismatch": "Public keys mismatch",
"label.members": "MEMBERS",
"message.deleted": "Message deleted",
"message.not.found": "Message not found",
"message.pin.toggled": "Message pin toggled",
"message.reacted": "Message reacted",
"message.reaction.removed": "Reaction removed",
"no.invite": "No invite",
"not.a.member": "Not a member",
"not.in.group": "Not in group",
"reaction.not.found": "Reaction not found",
"rotation.not.required": "Rotation not required",
"storage.entry.updated": "Storage entry updated",
"storage.limit.exceeded": "Storage limit exceeded",
"title.key.rotation": "Key Rotation",
"error:messages.decrypt.failed": "Decryption failed",
"error.message.already.deleted": "Message already deleted",
"group.user.joined.by": "{0} joined the group",
"group.created.by": "Group created by {0}",
"group.user.left.by": "{0} left the group",
"action.group.fetch": "Fetching groups",
"group.created": "Group created",
"group.user.joined": "Joined group",
"prompt.invite.username": "Enter username to invite:",
"desc.failed.load.members": "Failed to load members",
"prompt.are.you.sure": "Are you sure?",
"title.unknown.group": "Unknown Group",
"title.unknown": "Unknown",
"success:banner.updated": "Banner updated successfully",
"success:profile.updated": "Profile updated successfully",
"success:avatar.updated": "Avatar updated successfully",
"en-us": "English",
"pl-pl": "Polish",
"en-cat": "Meowlish"
} }

View file

@ -124,6 +124,7 @@
"desc.messages.loading": "Pobieranie wiadomości...", "desc.messages.loading": "Pobieranie wiadomości...",
"desc.no.dms": "Brak wiadomości prywatnych", "desc.no.dms": "Brak wiadomości prywatnych",
"action.dm.opening": "Otwieranie rozmowy...", "action.dm.opening": "Otwieranie rozmowy...",
"action.group.opening": "Otwieranie grupy...",
"dm.open.failed": "Nie udało się otworzyć rozmowy", "dm.open.failed": "Nie udało się otworzyć rozmowy",
"keys.local.server.mismatch": "To urządzenie ma inne klucze szyfrowania niż serwer. Użyj urządzenia, na którym zalogowano się po raz pierwszy, lub przywróć klucze z kopii zapasowej.", "keys.local.server.mismatch": "To urządzenie ma inne klucze szyfrowania niż serwer. Użyj urządzenia, na którym zalogowano się po raz pierwszy, lub przywróć klucze z kopii zapasowej.",
"keys.server.decrypt.failed": "Nie udało się odszyfrować kluczy konta przy użyciu tego hasła.", "keys.server.decrypt.failed": "Nie udało się odszyfrować kluczy konta przy użyciu tego hasła.",
@ -201,5 +202,60 @@
"message.unpinned.by": "{0} odpiął {1}.", "message.unpinned.by": "{0} odpiął {1}.",
"title.pinned.messages": "Przypięte", "title.pinned.messages": "Przypięte",
"error.pinned.messages.empty": "Brak przypiętych wiadomości", "error.pinned.messages.empty": "Brak przypiętych wiadomości",
"title.message.lowercase": "wiadomość" "title.message.lowercase": "wiadomość",
"action.rotate.keys": "Rotuj Klucze",
"already.in.group": "Już w grupie",
"desc.key.rotation.info": "Musisz zrotować klucze szyfrujące, aby kontynuować wysyłanie wiadomości w tej grupie. Inni członkowie automatycznie otrzymają nowy klucz.",
"desc.no.groups": "Nie jesteś jeszcze w żadnej grupie.",
"dm.read": "Przeczytano",
"empty.body": "Pusta zawartość",
"failed.create.group": "Nie udało się utworzyć grupy",
"federation.not.implemented": "Federacja niezaimplementowana",
"group.not.found": "Nie znaleziono grupy",
"group.read": "Przeczytano",
"invalid.entry.name": "Nieprawidłowa nazwa wpisu",
"invalid.key.index": "Nieprawidłowy indeks klucza (odśwież stronę)",
"invalid.msg.id": "Nieprawidłowe ID wiadomości",
"invalid.payload": "Nieprawidłowy ładunek",
"invalid.reaction.id": "Nieprawidłowe ID reakcji",
"invalid.user": "Nieprawidłowy użytkownik",
"joined": "Dołączono",
"key.rotation.required": "Wymagana rotacja kluczy",
"key.too.large": "Klucz zbyt duży",
"keys.public.mismatch": "Niezgodność kluczy publicznych",
"label.members": "CZŁONKOWIE",
"message.deleted": "Wiadomość usunięta",
"message.not.found": "Nie znaleziono wiadomości",
"message.pin.toggled": "Zmieniono przypięcie wiadomości",
"message.reacted": "Dodano reakcję",
"message.reaction.removed": "Reakcja usunięta",
"no.invite": "Brak zaproszenia",
"not.a.member": "Nie jesteś członkiem",
"not.in.group": "Nie jesteś w grupie",
"reaction.not.found": "Nie znaleziono reakcji",
"rotation.not.required": "Rotacja niewymagana",
"storage.entry.updated": "Zaktualizowano wpis pamięci",
"storage.limit.exceeded": "Przekroczono limit pamięci",
"title.key.rotation": "Rotacja kluczy",
"missing.keys": "Brakujące klucze",
"error:messages.decrypt.failed": "Deszyfrowanie nie powiodło się",
"error.message.already.deleted": "Wiadomość została już usunięta",
"group.user.joined.by": "{0} dołączył do grupy",
"group.created.by": "Grupa utworzona przez {0}",
"group.user.left.by": "{0} opuścił grupę",
"action.group.fetch": "Pobieranie grup",
"group.created": "Utworzono grupę",
"group.user.joined": "Dołączono do grupy",
"prompt.invite.username": "Podaj nazwę użytkownika, aby zaprosić:",
"desc.failed.load.members": "Nie udało się załadować członków",
"prompt.are.you.sure": "Czy na pewno?",
"title.unknown.group": "Nieznana grupa",
"title.unknown": "Nieznany",
"key.rotated": "Klucze grupy zostały pomyślnie zrotowane.",
"success:banner.updated": "Baner został pomyślnie zaktualizowany",
"success:profile.updated": "Profil został pomyślnie zaktualizowany",
"success:avatar.updated": "Awatar został pomyślnie zaktualizowany",
"en-us": "Angielski",
"pl-pl": "Polski",
"en-cat": "Koci (Meowlish)"
} }

View file

@ -119,6 +119,25 @@
</div> </div>
</div> </div>
</div> </div>
<div id="rotation-popup-container" class="profile-popup-container" style="display: none; z-index: 9999;">
<div class="profile-popup-bg" onclick="closeRotationPopup()"></div>
<div class="profile-popup-content">
<button class="profile-popup-close-btn" onclick="closeRotationPopup()">
<script>
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.close());
document.currentScript.remove();
</script>
</button>
<div id="profile-popup-inner" style="padding: 2rem; display: flex; flex-direction: column; align-items: center; gap: 1rem;">
<div style="font-size: 1.2rem; font-weight: 500; text-align: center;"><blah>title.key.rotation</blah></div>
<div style="width: 100%; text-align: center; color: var(--text-color); opacity: 0.8; margin-top: 1rem; margin-bottom: 1rem;" id="rotation-popup-desc">
<!-- content injected dynamically -->
</div>
<button class="profile-action-btn" onclick="executeKeyRotation()"><blah>action.rotate.keys</blah></button>
</div>
</div>
</div>
</body> </body>
</html> </html>
@ -208,8 +227,59 @@
} }
} }
async function createGroup() { async function refreshGroups(waittime = 0, showLoading = true) {
try {
if (showLoading) showAction("action.group.fetch", "grouprefresh");
await delay(waittime);
if (window.cachedGroups && typeof renderGroups === 'function') {
await renderGroups(window.cachedGroups);
}
let res = await fetchEncrypted("user/group/list");
window.cachedGroups = res;
if (typeof renderGroups === 'function') {
await renderGroups(res);
}
if (showLoading) clearAction("grouprefresh");
}
catch (e) {
if (showLoading) clearAction("grouprefresh");
showBlahNotification("error:group.refresh.failed");
}
}
async function createGroup() {
try {
let groupName = document.getElementById("creategroup-name").value;
if (!groupName || groupName.trim() === "") {
showBlahNotification("error:group.name.empty");
return;
}
showAction("action.group.creating", "group.action");
await ensureUserKeys();
const roomKey = randomRoomKey256Chars();
const selfWrapped = await wrapRoomKeyForSelf(roomKey);
let payload = JSON.stringify({
string1: groupName,
string2: selfWrapped
});
let res = await fetchEncrypted("group/create", payload);
clearAction("group.action");
if (res.startsWith("success:")) {
showBlahNotification("success:group.created");
await refreshGroups(200, false);
} else {
showBlahNotification(res || "error:something.wrong");
}
} catch (e) {
clearAction("group.action");
showBlahNotification("error:something.wrong");
console.error(e);
}
} }
</script> </script>
<script src="gifuct.js"></script> <script src="gifuct.js"></script>

File diff suppressed because it is too large Load diff

View file

@ -117,10 +117,10 @@ var notifisScreen = `
var invitesEntry = ` var invitesEntry = `
<div class="invite-entry"> <div class="invite-entry">
<div class="invite-info"> <div class="invite-info">
<img src="{pfp}" class="invite-pfp" onclick="openProfile('{id}')" style="cursor: pointer;"> <img src="{pfp}" class="invite-pfp" {onclick_attr}>
<div class="invite-details"> <div class="invite-details">
<span class="invite-name" onclick="openProfile('{id}')" style="cursor: pointer;">{username}</span> <span class="invite-name" {onclick_attr}>{username}</span>
<span class="invite-desc"><blah>{desc}</blah></span> <span class="invite-desc">{desc}</span>
</div> </div>
</div> </div>
<div class="invite-actions"> <div class="invite-actions">

View file

@ -215,6 +215,25 @@ sidebar {
width: calc(var(--icon-button-height) + (var(--button-margin) * 2) + var(--border-width)); width: calc(var(--icon-button-height) + (var(--button-margin) * 2) + var(--border-width));
border-right: var(--border-width) solid var(--light-border-color); border-right: var(--border-width) solid var(--light-border-color);
} }
sidebar:not(.second) {
overflow-y: auto;
overflow-x: hidden;
}
sidebar:not(.second)::-webkit-scrollbar {
display: none;
}
sidebar:not(.second) {
-ms-overflow-style: none;
scrollbar-width: none;
}
#roomsbar roomcontent2 {
overflow-y: auto;
overflow-x: hidden;
}
sidebar.second { sidebar.second {
width: 17rem; width: 17rem;
min-width: 17rem; min-width: 17rem;