diff --git a/src/webpage/channel.ts b/src/webpage/channel.ts
index b47ee69..42ceb82 100644
--- a/src/webpage/channel.ts
+++ b/src/webpage/channel.ts
@@ -1124,7 +1124,7 @@ class Channel extends SnowFlake {
loading.classList.add("loading");
this.rendertyping();
this.localuser.getSidePannel();
- if (this.voice && localStorage.getItem("Voice enabled")) {
+ if (this.voice && this.localuser.voiceAllowed) {
this.localuser.joinVoice(this);
}
(document.getElementById("typebox") as HTMLDivElement).contentEditable = "" + this.canMessage;
diff --git a/src/webpage/icons/mic.svg b/src/webpage/icons/mic.svg
new file mode 100644
index 0000000..533378f
--- /dev/null
+++ b/src/webpage/icons/mic.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/webpage/icons/micmute.svg b/src/webpage/icons/micmute.svg
new file mode 100644
index 0000000..e41993b
--- /dev/null
+++ b/src/webpage/icons/micmute.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/webpage/index.html b/src/webpage/index.html
index 2dfe5d4..3afb6a5 100644
--- a/src/webpage/index.html
+++ b/src/webpage/index.html
@@ -58,8 +58,9 @@
-
diff --git a/src/webpage/jsontypes.ts b/src/webpage/jsontypes.ts
index 7f4dd37..0f8f6d0 100644
--- a/src/webpage/jsontypes.ts
+++ b/src/webpage/jsontypes.ts
@@ -1,4 +1,4 @@
-type readyjson = {
+interface readyjson {
op: 0;
t: "READY";
s: number;
@@ -120,7 +120,39 @@ type readyjson = {
flags: number;
};
};
-};
+}
+interface readySuplemental {
+ op: 0;
+ t: "READY_SUPPLEMENTAL";
+ s: number;
+ d: {
+ merged_presences: {
+ guilds: [];
+ friends: [];
+ };
+ merged_members: [];
+ lazy_private_channels: [];
+ guilds: {
+ voice_states: {
+ user_id: string;
+ suppress: boolean;
+ session_id: string;
+ self_video: boolean;
+ self_mute: boolean;
+ self_deaf: boolean;
+ self_stream: boolean;
+ request_to_speak_timestamp: null;
+ mute: boolean;
+ deaf: boolean;
+ channel_id: string; //weird reasons, don't question it too much
+ guild_id: string;
+ }[];
+ id: string;
+ embedded_activities: [];
+ }[];
+ disclose: [];
+ };
+}
interface banObj {
reason: string | null;
user: {
@@ -508,6 +540,7 @@ type roleCreate = {
s: 6;
};
type wsjson =
+ | readySuplemental
| roleCreate
| {
op: 0;
@@ -704,22 +737,23 @@ type memberChunk = {
chunk_count: number;
not_found: string[];
};
+export type voiceStatus = {
+ guild_id: string;
+ channel_id: string;
+ user_id: string;
+ member?: memberjson;
+ session_id: string;
+ deaf: boolean;
+ mute: boolean;
+ self_deaf: boolean;
+ self_mute: boolean;
+ self_video: boolean;
+ suppress: boolean;
+};
type voiceupdate = {
op: 0;
t: "VOICE_STATE_UPDATE";
- d: {
- guild_id: string;
- channel_id: string;
- user_id: string;
- member: memberjson;
- session_id: string;
- deaf: boolean;
- mute: boolean;
- self_deaf: boolean;
- self_mute: boolean;
- self_video: boolean;
- suppress: boolean;
- };
+ d: voiceStatus;
s: number;
};
type voiceserverupdate = {
diff --git a/src/webpage/localuser.ts b/src/webpage/localuser.ts
index 129f945..21fe074 100644
--- a/src/webpage/localuser.ts
+++ b/src/webpage/localuser.ts
@@ -243,6 +243,21 @@ class Localuser {
if (this.perminfo.user.disableColors === undefined) this.perminfo.user.disableColors = true;
this.updateTranslations();
}
+ readysup = false;
+ get voiceAllowed() {
+ return this.readysup || localStorage.getItem("Voice enabled");
+ }
+ mute = true;
+ deaf = false;
+ updateMic() {
+ const mic = document.getElementById("mic") as HTMLElement;
+ mic.classList.remove("svg-mic", "svg-micmute");
+ if (this.mute) {
+ mic.classList.add("svg-micmute");
+ } else {
+ mic.classList.add("svg-mic");
+ }
+ }
async gottenReady(ready: readyjson): Promise {
await I18n.done;
this.initialized = true;
@@ -273,6 +288,12 @@ class Localuser {
members[thing[0].guild_id] = thing[0];
}
}
+ this.updateMic();
+ const mic = document.getElementById("mic") as HTMLElement;
+ mic.onclick = () => {
+ this.mute = !this.mute;
+ this.updateMic();
+ };
for (const thing of ready.d.guilds) {
const temp = new Guild(thing, this, members[thing.id]);
this.guilds.push(temp);
@@ -722,9 +743,22 @@ class Localuser {
this.memberListUpdate(temp);
break;
}
+ case "READY_SUPPLEMENTAL":
+ {
+ temp.d.guilds.forEach((_) =>
+ _.voice_states.forEach((status) => {
+ if (this.voiceFactory && status.channel_id) {
+ this.voiceFactory.voiceStateUpdate(status);
+ console.log(status);
+ }
+ }),
+ );
+ this.readysup = temp.d.guilds.length !== 0;
+ }
+ break;
case "VOICE_STATE_UPDATE":
if (this.voiceFactory) {
- this.voiceFactory.voiceStateUpdate(temp);
+ this.voiceFactory.voiceStateUpdate(temp.d);
}
break;
@@ -838,7 +872,9 @@ class Localuser {
async joinVoice(channel: Channel) {
if (!this.voiceFactory) return;
if (!this.ws) return;
- this.ws.send(JSON.stringify(this.voiceFactory.joinVoice(channel.id, channel.guild.id)));
+ this.ws.send(
+ JSON.stringify(this.voiceFactory.joinVoice(channel.id, channel.guild.id, this.mute)),
+ );
return undefined;
}
changeVCStatus(status: string) {
@@ -891,6 +927,9 @@ class Localuser {
if (!guild) return;
const channel = this.channelfocus;
if (!channel) return;
+ if (channel.voice && this.voiceAllowed) {
+ return;
+ }
if (list) {
const counts = new Map();
for (const thing of list.d.ops[0].items) {
diff --git a/src/webpage/style.css b/src/webpage/style.css
index b27f670..32eb23f 100644
--- a/src/webpage/style.css
+++ b/src/webpage/style.css
@@ -538,6 +538,21 @@ textarea {
aspect-ratio: 1/1;
flex-shrink: 0;
}
+.svg-mic {
+ height: 22px;
+ width: 22px;
+ margin: 6px;
+ mask: url(/icons/mic.svg);
+ mask-size: contain !important;
+}
+.svg-micmute {
+ height: 22px;
+ width: 22px;
+ margin: 6px;
+ mask: url(/icons/micmute.svg);
+ background-color: var(--red);
+ mask-size: contain !important;
+}
.mobileback {
visibility: hidden;
height: 0px;
@@ -1186,10 +1201,6 @@ span.instanceStatus {
#userinfo {
min-width: 50%;
padding: 0 6px;
- background: var(--user-info-bg);
- color: var(--user-info-text);
- border-radius: 8px;
- box-sizing: border-box;
gap: 6px;
cursor: pointer;
}
@@ -1205,11 +1216,14 @@ span.instanceStatus {
#status {
font-size: 0.8em;
}
-#user-actions {
+#user-actions > * {
border-radius: 50%;
cursor: pointer;
+ background: var(--user-info-bg);
+ color: var(--user-info-text);
+ box-sizing: border-box;
}
-#user-actions:hover {
+#user-actions > :hover {
background: var(--dock-hover);
}
#settings {
diff --git a/src/webpage/voice.ts b/src/webpage/voice.ts
index ee743d6..6458616 100644
--- a/src/webpage/voice.ts
+++ b/src/webpage/voice.ts
@@ -1,5 +1,4 @@
-import {memberjson, sdpback, voiceserverupdate, voiceupdate, webRTCSocket} from "./jsontypes.js";
-
+import {memberjson, sdpback, voiceserverupdate, voiceStatus, webRTCSocket} from "./jsontypes.js";
class VoiceFactory {
settings: {id: string};
constructor(usersettings: VoiceFactory["settings"]) {
@@ -28,7 +27,7 @@ class VoiceFactory {
}
onJoin = (_voice: Voice) => {};
onLeave = (_voice: Voice) => {};
- joinVoice(channelId: string, guildId: string) {
+ joinVoice(channelId: string, guildId: string, self_mute = false) {
const voice = this.voiceChannels.get(channelId);
if (this.currentVoice && this.currentVoice.ws) {
this.currentVoice.leave();
@@ -42,7 +41,7 @@ class VoiceFactory {
d: {
guild_id: guildId,
channel_id: channelId,
- self_mute: false, //todo
+ self_mute,
self_deaf: false, //todo
self_video: false, //What is this? I have some guesses
flags: 2, //?????
@@ -51,16 +50,16 @@ class VoiceFactory {
};
}
userMap = new Map();
- voiceStateUpdate(update: voiceupdate) {
- const prev = this.userMap.get(update.d.user_id);
+ voiceStateUpdate(update: voiceStatus) {
+ const prev = this.userMap.get(update.user_id);
console.log(prev, this.userMap);
if (prev) {
- prev.disconnect(update.d.user_id);
+ prev.disconnect(update.user_id);
this.onLeave(prev);
}
- const voice = this.voiceChannels.get(update.d.channel_id);
+ const voice = this.voiceChannels.get(update.channel_id);
if (voice) {
- this.userMap.set(update.d.user_id, voice);
+ this.userMap.set(update.user_id, voice);
voice.voiceupdate(update);
}
}
@@ -696,11 +695,11 @@ a=rtcp-mux\r`;
}
onMemberChange = (_member: memberjson | string, _joined: boolean) => {};
userids = new Map();
- async voiceupdate(update: voiceupdate) {
+ async voiceupdate(update: voiceStatus) {
console.log("Update!");
- this.userids.set(update.d.member.id, {deaf: update.d.deaf, muted: update.d.mute});
- this.onMemberChange(update.d.member, true);
- if (update.d.member.id === this.userid && this.open) {
+ this.userids.set(update.user_id, {deaf: update.deaf, muted: update.mute});
+ this.onMemberChange(update?.member || update.user_id, true);
+ if (update.user_id === this.userid && this.open) {
if (!update) {
this.status = "bad responce from WS";
return;
@@ -737,9 +736,9 @@ a=rtcp-mux\r`;
JSON.stringify({
op: 0,
d: {
- server_id: update.d.guild_id,
- user_id: update.d.user_id,
- session_id: update.d.session_id,
+ server_id: update.guild_id,
+ user_id: update.user_id,
+ session_id: update.session_id,
token: this.urlobj.token,
video: false,
streams: [