Skip to content

Commit ce6dc3b

Browse files
committed
basic VC gui
1 parent 49632b3 commit ce6dc3b

File tree

9 files changed

+308
-31
lines changed

9 files changed

+308
-31
lines changed

src/webpage/app.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ <h2 id="serverName" class="ellipsis">Server Name</h2>
8989
<input type="checkbox" id="memberlisttoggle" checked />
9090
</div>
9191
<div class="flexltr flexgrow">
92-
<div class="flexttb flexgrow">
92+
<div class="flexttb flexgrow" id="voiceArea"></div>
93+
<div class="flexttb flexgrow" id="chatArea">
9394
<div id="channelw" class="flexltr">
9495
<div id="loadingdiv"></div>
9596
</div>

src/webpage/channel.ts

Lines changed: 142 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,17 @@ class Channel extends SnowFlake {
729729
if (typeof memb !== "string") {
730730
await Member.new(memb, this.guild);
731731
}
732+
733+
const users = this.usersDiv.deref();
734+
if (users) {
735+
const user = await this.localuser.getUser(typeof memb === "string" ? memb : memb.id);
736+
if (joined) {
737+
this.makeUserBox(user, users);
738+
} else {
739+
this.destUserBox(user);
740+
}
741+
}
742+
732743
this.updateVoiceUsers();
733744
if (this.voice === this.localuser.currentVoice) {
734745
AVoice.noises("join");
@@ -1060,7 +1071,124 @@ class Channel extends SnowFlake {
10601071
if (!this.last_pin_timestamp && !this.lastpin) return false;
10611072
return this.last_pin_timestamp !== this.lastpin;
10621073
}
1063-
async getHTML(addstate = true, getMessages = true) {
1074+
boxMap = new Map<string, HTMLElement>();
1075+
destUserBox(user: User) {
1076+
const box = this.boxMap.get(user.id);
1077+
if (!box) return;
1078+
box.remove();
1079+
this.boxMap.delete(user.id);
1080+
}
1081+
async makeUserBox(user: User, users: HTMLElement) {
1082+
const memb = Member.resolveMember(user, this.guild);
1083+
const box = document.createElement("div");
1084+
this.boxMap.set(user.id, box);
1085+
if (user.accent_color != undefined) {
1086+
box.style.setProperty(
1087+
"--accent_color",
1088+
`#${user.accent_color.toString(16).padStart(6, "0")}`,
1089+
);
1090+
}
1091+
memb.then((_) => {
1092+
if (!_) return;
1093+
if (_.accent_color !== undefined) {
1094+
box.style.setProperty("--accent_color", `#${_.accent_color.toString(16).padStart(6, "0")}`);
1095+
}
1096+
});
1097+
1098+
box.append(user.buildpfp(this.guild));
1099+
1100+
const span = document.createElement("span");
1101+
span.textContent = user.name;
1102+
memb.then((_) => {
1103+
if (!_) return;
1104+
span.textContent = _.name;
1105+
});
1106+
span.classList.add("voiceUsername");
1107+
box.append(span);
1108+
users.append(box);
1109+
}
1110+
usersDiv = new WeakRef(document.createElement("div"));
1111+
async setUpVoiceArea() {
1112+
if (!this.voice) throw new Error("voice not found?");
1113+
const voiceArea = document.getElementById("voiceArea") as HTMLElement;
1114+
const buttonRow = document.createElement("div");
1115+
buttonRow.classList.add("flexltr", "buttonRow");
1116+
const updateMicIcon = () => {
1117+
mspan.classList.remove("svg-micmute", "svg-mic");
1118+
mspan.classList.add(this.localuser.mute ? "svg-micmute" : "svg-mic");
1119+
};
1120+
1121+
const mute = document.createElement("div");
1122+
const mspan = document.createElement("span");
1123+
mute.append(mspan);
1124+
updateMicIcon();
1125+
this.localuser.updateOtherMic = updateMicIcon;
1126+
mute.onclick = () => {
1127+
this.localuser.mute = !this.localuser.mute;
1128+
this.localuser.updateMic();
1129+
};
1130+
mute.classList.add("muteVoiceIcon");
1131+
1132+
const updateCallIcon = () => {
1133+
cspan.classList.remove("svg-call", "svg-hangup");
1134+
cspan.classList.add(this.voice?.open ? "svg-hangup" : "svg-call");
1135+
};
1136+
const call = document.createElement("div");
1137+
const cspan = document.createElement("span");
1138+
call.append(cspan);
1139+
updateCallIcon();
1140+
call.onclick = async () => {
1141+
if (this.voice?.userids.has(this.localuser.user.id)) {
1142+
this.voice.leave();
1143+
} else if (this.voice) {
1144+
await this.localuser.joinVoice(this);
1145+
}
1146+
updateCallIcon();
1147+
};
1148+
call.classList.add("callVoiceIcon");
1149+
1150+
buttonRow.append(mute, call);
1151+
1152+
const users = document.createElement("div");
1153+
users.classList.add("voiceUsers");
1154+
this.voice.userids.forEach(async (_, id) => {
1155+
const user = await this.localuser.getUser(id);
1156+
this.makeUserBox(user, users);
1157+
});
1158+
this.usersDiv = new WeakRef(users);
1159+
this.voice.onSpeakingChange = (id, speaking) => {
1160+
const box = this.boxMap.get(id);
1161+
if (!box) return;
1162+
if (speaking) {
1163+
box.classList.add("speaking");
1164+
} else {
1165+
box.classList.remove("speaking");
1166+
}
1167+
};
1168+
1169+
voiceArea.append(users, buttonRow);
1170+
}
1171+
async getHTML(addstate = true, getMessages: boolean | void = undefined) {
1172+
if (getMessages === undefined) {
1173+
getMessages = this.type !== 2 || !this.localuser.voiceAllowed;
1174+
}
1175+
1176+
const messages = document.getElementById("channelw") as HTMLDivElement;
1177+
const messageContainers = Array.from(messages.getElementsByClassName("messagecontainer"));
1178+
for (const thing of messageContainers) {
1179+
thing.remove();
1180+
}
1181+
const chatArea = document.getElementById("chatArea") as HTMLElement;
1182+
1183+
const voiceArea = document.getElementById("voiceArea") as HTMLElement;
1184+
voiceArea.innerHTML = "";
1185+
if (getMessages) {
1186+
chatArea.style.removeProperty("display");
1187+
} else {
1188+
chatArea.style.setProperty("display", "none");
1189+
this.setUpVoiceArea();
1190+
}
1191+
10641192
const pinnedM = document.getElementById("pinnedMDiv");
10651193
if (pinnedM) {
10661194
if (this.unreadPins()) {
@@ -1069,11 +1197,6 @@ class Channel extends SnowFlake {
10691197
pinnedM.classList.remove("unreadPin");
10701198
}
10711199
}
1072-
const ghostMessages = document.getElementById("ghostMessages") as HTMLElement;
1073-
ghostMessages.innerHTML = "";
1074-
for (const thing of this.fakeMessages) {
1075-
ghostMessages.append(thing[1]);
1076-
}
10771200
if (addstate) {
10781201
history.pushState([this.guild_id, this.id], "", "/channels/" + this.guild_id + "/" + this.id);
10791202
}
@@ -1095,6 +1218,7 @@ class Channel extends SnowFlake {
10951218
if (this.guild !== this.localuser.lookingguild) {
10961219
this.guild.loadGuild();
10971220
}
1221+
10981222
if (this.localuser.channelfocus && this.localuser.channelfocus.myhtml) {
10991223
this.localuser.channelfocus.myhtml.classList.remove("viewChannel");
11001224
}
@@ -1117,15 +1241,22 @@ class Channel extends SnowFlake {
11171241
return;
11181242
}
11191243

1120-
const prom = this.infinite.delete();
1244+
const ghostMessages = document.getElementById("ghostMessages") as HTMLElement;
1245+
ghostMessages.innerHTML = "";
1246+
for (const thing of this.fakeMessages) {
1247+
ghostMessages.append(thing[1]);
1248+
}
11211249

1122-
const loading = document.getElementById("loadingdiv") as HTMLDivElement;
1123-
Channel.regenLoadingMessages();
1124-
loading.classList.add("loading");
1250+
const prom = this.infinite.delete();
1251+
if (getMessages) {
1252+
const loading = document.getElementById("loadingdiv") as HTMLDivElement;
1253+
Channel.regenLoadingMessages();
1254+
loading.classList.add("loading");
1255+
}
11251256
this.rendertyping();
11261257
this.localuser.getSidePannel();
11271258
if (this.voice && this.localuser.voiceAllowed) {
1128-
this.localuser.joinVoice(this);
1259+
//this.localuser.joinVoice(this);
11291260
}
11301261
(document.getElementById("typebox") as HTMLDivElement).contentEditable = "" + this.canMessage;
11311262
(document.getElementById("upload") as HTMLElement).style.visibility = this.canMessage

src/webpage/direct.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class Direct extends Guild {
5454
}
5555
}
5656
getHTML() {
57+
const voiceArea = document.getElementById("voiceArea") as HTMLElement;
58+
voiceArea.innerHTML = "";
5759
const sideContainDiv = document.getElementById("sideContainDiv");
5860
if (sideContainDiv) {
5961
sideContainDiv.classList.remove("searchDiv");

src/webpage/icons/call.svg

Lines changed: 1 addition & 0 deletions
Loading

src/webpage/icons/hangup.svg

Lines changed: 1 addition & 0 deletions
Loading

src/webpage/localuser.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,12 @@ class Localuser {
249249
}
250250
mute = true;
251251
deaf = false;
252-
updateMic() {
252+
updateOtherMic = () => {};
253+
updateMic(updateVoice: boolean = true) {
254+
this.updateOtherMic();
253255
const mic = document.getElementById("mic") as HTMLElement;
254256
mic.classList.remove("svg-mic", "svg-micmute");
257+
if (this.voiceFactory && updateVoice) this.voiceFactory.mute = this.mute;
255258
if (this.mute) {
256259
mic.classList.add("svg-micmute");
257260
} else {
@@ -271,7 +274,11 @@ class Localuser {
271274

272275
this.mdBox();
273276

274-
this.voiceFactory = new VoiceFactory({id: this.user.id});
277+
this.voiceFactory = new VoiceFactory({id: this.user.id}, (g) => {
278+
if (this.ws) {
279+
this.ws.send(JSON.stringify(g));
280+
}
281+
});
275282
this.handleVoice();
276283
this.mfa_enabled = ready.d.user.mfa_enabled as boolean;
277284
this.userinfo.username = this.user.username;
@@ -757,6 +764,10 @@ class Localuser {
757764
}
758765
break;
759766
case "VOICE_STATE_UPDATE":
767+
if (this.user.id === temp.d.user_id) {
768+
this.mute = temp.d.self_mute;
769+
this.updateMic(false);
770+
}
760771
if (this.voiceFactory) {
761772
this.voiceFactory.voiceStateUpdate(temp.d);
762773
}

src/webpage/style.css

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,69 @@ body {
184184
position: relative;
185185
width: 100%;
186186
}
187+
#voiceArea:empty {
188+
display: none;
189+
}
190+
#voiceArea {
191+
background: var(--black);
192+
position: relative;
193+
}
194+
.voiceUsers {
195+
padding: 20px;
196+
display: flex;
197+
flex-direction: row;
198+
flex-wrap: wrap;
199+
}
200+
.speaking {
201+
border: solid var(--green) 3px;
202+
padding: 77px 137px !important;
203+
}
204+
.voiceUsers > * {
205+
background: var(--accent_color, var(--primary-bg));
206+
padding: 80px 140px;
207+
width: fit-content;
208+
border-radius: 8px;
209+
position: relative;
210+
box-sizing: border-box;
211+
margin: 8px;
212+
213+
img {
214+
width: 60px;
215+
height: 60px;
216+
cursor: unset;
217+
}
218+
}
219+
.buttonRow > * {
220+
margin-right: 6px;
221+
width: 54px;
222+
height: 54px;
223+
background: var(--secondary-hover);
224+
border-radius: 100%;
225+
display: flex;
226+
align-items: center;
227+
justify-content: center;
228+
cursor: pointer;
229+
* {
230+
width: 32px !important;
231+
height: 32px !important;
232+
background: var(--primary-text);
233+
}
234+
}
235+
.buttonRow {
236+
position: absolute;
237+
bottom: 20px;
238+
width: 100%;
239+
display: flex;
240+
justify-content: center;
241+
}
242+
.voiceUsername {
243+
position: absolute;
244+
bottom: 10px;
245+
left: 14px;
246+
background: var(--secondary-bg);
247+
padding: 4px;
248+
border-radius: 6px;
249+
}
187250
.flexgrow {
188251
flex-grow: 1;
189252
min-height: 0;
@@ -415,6 +478,15 @@ textarea {
415478
display: block;
416479
mask-size: cover !important;
417480
}
481+
.svg-call {
482+
mask: url(/icons/call.svg);
483+
mask-size: contain !important;
484+
}
485+
.svg-hangup {
486+
mask: url(/icons/hangup.svg);
487+
mask-size: contain !important;
488+
background: var(--red);
489+
}
418490
.svg-plainx {
419491
mask: url(/icons/plainx.svg);
420492
mask-size: contain !important;

src/webpage/user.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -499,14 +499,14 @@ class User extends SnowFlake {
499499
this.bind(div, guild);
500500
return div;
501501
}
502-
async buildstatuspfp(guild: Guild | void | Member | null): Promise<HTMLDivElement> {
502+
buildstatuspfp(guild: Guild | void | Member | null): HTMLDivElement {
503503
const div = document.createElement("div");
504504
div.classList.add("pfpDiv");
505505
const pfp = this.buildpfp(guild, div);
506506
div.append(pfp);
507507
const status = document.createElement("div");
508508
status.classList.add("statusDiv");
509-
switch (await this.getStatus()) {
509+
switch (this.getStatus()) {
510510
case "offline":
511511
case "invisible":
512512
status.classList.add("offlinestatus");
@@ -785,7 +785,7 @@ class User extends SnowFlake {
785785
badgediv.append(badge);
786786
}
787787
})();
788-
const pfp = await this.buildstatuspfp(guild);
788+
const pfp = this.buildstatuspfp(guild);
789789
div.appendChild(pfp);
790790
const userbody = document.createElement("div");
791791
userbody.classList.add("flexttb", "infosection");

0 commit comments

Comments
 (0)