friend and more update

This commit is contained in:
MathMan05 2024-11-26 22:30:04 -06:00
parent e24afe2abe
commit 2502d8f977
13 changed files with 491 additions and 79 deletions

View file

@ -40,6 +40,7 @@ jsc: {
gulp.task('watch', function () { gulp.task('watch', function () {
gulp.watch('./src', gulp.series("default")); gulp.watch('./src', gulp.series("default"));
gulp.watch('./translations', gulp.series("default"));
}, {debounceDelay: 10}); }, {debounceDelay: 10});
// Clean task to delete the dist directory // Clean task to delete the dist directory

View file

@ -842,6 +842,10 @@ class Channel extends SnowFlake{
if(this.voice&&localStorage.getItem("Voice enabled")){ if(this.voice&&localStorage.getItem("Voice enabled")){
this.localuser.joinVoice(this); this.localuser.joinVoice(this);
} }
(document.getElementById("typebox") as HTMLDivElement).contentEditable =""+this.canMessage;
(document.getElementById("upload") as HTMLElement).style.visibility=this.canMessage?"visible":"hidden";
(document.getElementById("typediv") as HTMLElement).style.visibility="visible";
(document.getElementById("typebox") as HTMLDivElement).focus();
await this.putmessages(); await this.putmessages();
await prom; await prom;
if(id !== Channel.genid){ if(id !== Channel.genid){
@ -851,10 +855,7 @@ class Channel extends SnowFlake{
await this.buildmessages(); await this.buildmessages();
//loading.classList.remove("loading"); //loading.classList.remove("loading");
(document.getElementById("typebox") as HTMLDivElement).contentEditable =""+this.canMessage;
(document.getElementById("upload") as HTMLElement).style.visibility=this.canMessage?"visible":"hidden";
(document.getElementById("typediv") as HTMLElement).style.visibility="visible";
(document.getElementById("typebox") as HTMLDivElement).focus();
} }
typingmap: Map<Member, number> = new Map(); typingmap: Map<Member, number> = new Map();
async typingStart(typing: startTypingjson): Promise<void>{ async typingStart(typing: startTypingjson): Promise<void>{
@ -938,6 +939,7 @@ class Channel extends SnowFlake{
} }
lastmessage: Message | undefined; lastmessage: Message | undefined;
async putmessages(){ async putmessages(){
//TODO swap out with the WS op code
if(this.allthewayup){ if(this.allthewayup){
return; return;
} }

View file

@ -8,9 +8,11 @@ import{ Permissions }from"./permissions.js";
import{ SnowFlake }from"./snowflake.js"; import{ SnowFlake }from"./snowflake.js";
import{ Contextmenu }from"./contextmenu.js"; import{ Contextmenu }from"./contextmenu.js";
import { I18n } from "./i18n.js"; import { I18n } from "./i18n.js";
import { Float, FormError } from "./settings.js";
class Direct extends Guild{ class Direct extends Guild{
declare channelids: { [key: string]: Group }; declare channelids: { [key: string]: Group };
channels: Group[];
getUnixTime(): number{ getUnixTime(): number{
throw new Error("Do not call this for Direct, it does not make sense"); throw new Error("Do not call this for Direct, it does not make sense");
} }
@ -26,7 +28,7 @@ class Direct extends Guild{
this.roles = []; this.roles = [];
this.roleids = new Map(); this.roleids = new Map();
this.prevchannel = undefined; this.prevchannel = undefined;
this.properties.name = "Direct Messages"; this.properties.name = I18n.getTranslation("DMs.name");
for(const thing of json){ for(const thing of json){
const temp = new Group(thing, this); const temp = new Group(thing, this);
this.channels.push(temp); this.channels.push(temp);
@ -60,7 +62,7 @@ class Direct extends Guild{
icon.classList.add("svgicon","svg-friends","space"); icon.classList.add("svgicon","svg-friends","space");
freindDiv.append(icon); freindDiv.append(icon);
freindDiv.append("Friends"); freindDiv.append(I18n.getTranslation("friends.friends"));
ddiv.append(freindDiv); ddiv.append(freindDiv);
freindDiv.onclick=()=>{ freindDiv.onclick=()=>{
this.loadChannel(null); this.loadChannel(null);
@ -69,6 +71,217 @@ class Direct extends Guild{
ddiv.append(build); ddiv.append(build);
return ddiv; return ddiv;
} }
noChannel(addstate:boolean){
if(addstate){
history.pushState([this.id,undefined], "", "/channels/" + this.id);
}
this.localuser.pageTitle(I18n.getTranslation("friends.friendlist"));
const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement;
channelTopic.removeAttribute("hidden");
channelTopic.textContent="";
const loading = document.getElementById("loadingdiv") as HTMLDivElement;
loading.classList.remove("loading");
this.localuser.getSidePannel();
const messages = document.getElementById("channelw") as HTMLDivElement;
for(const thing of Array.from(messages.getElementsByClassName("messagecontainer"))){
thing.remove();
}
const container=document.createElement("div");
container.classList.add("messagecontainer","flexttb","friendcontainer")
messages.append(container);
const checkVoid=()=>{
if(this.localuser.channelfocus!==undefined||this.localuser.lookingguild!==this){
this.localuser.relationshipsUpdate=()=>{};
}
}
function genuserstrip(user:User,icons:HTMLElement):HTMLElement{
const div=document.createElement("div");
div.classList.add("flexltr","liststyle");
user.bind(div);
div.append(user.buildpfp());
const userinfos=document.createElement("div");
userinfos.classList.add("flexttb");
const username=document.createElement("span");
username.textContent=user.name;
userinfos.append(username,user.getStatus());
div.append(userinfos);
User.contextmenu.bindContextmenu(div,user,undefined);
userinfos.style.flexGrow="1";
div.append(icons);
return div;
}
{
//TODO update on users coming online
const online=document.createElement("button");
online.textContent=I18n.getTranslation("friends.online");
channelTopic.append(online);
const genOnline=()=>{
this.localuser.relationshipsUpdate=genOnline;
checkVoid();
container.innerHTML="";
container.append(I18n.getTranslation("friends.online:"));
for(const user of this.localuser.inrelation){
if(user.relationshipType===1&&user.online){
const buttonc=document.createElement("div");
const button1=document.createElement("span");
button1.classList.add("svg-frmessage","svgicon");
buttonc.append(button1);
buttonc.classList.add("friendlyButton");
buttonc.onclick=(e)=>{
e.stopImmediatePropagation();
user.opendm();
}
container.append(genuserstrip(user,buttonc));
}
}
}
online.onclick=genOnline;
genOnline();
}
{
const all=document.createElement("button");
all.textContent=I18n.getTranslation("friends.all");
const genAll=()=>{
this.localuser.relationshipsUpdate=genAll;
checkVoid();
container.innerHTML="";
container.append(I18n.getTranslation("friends.all:"));
for(const user of this.localuser.inrelation){
if(user.relationshipType===1){
const buttonc=document.createElement("div");
const button1=document.createElement("span");
button1.classList.add("svg-frmessage","svgicon");
buttonc.append(button1);
buttonc.classList.add("friendlyButton");
buttonc.onclick=(e)=>{
e.stopImmediatePropagation();
user.opendm();
}
container.append(genuserstrip(user,buttonc));
}
}
}
all.onclick=genAll;
channelTopic.append(all);
}
{
const pending=document.createElement("button");
pending.textContent=I18n.getTranslation("friends.pending");
const genPending=()=>{
this.localuser.relationshipsUpdate=genPending;
checkVoid();
container.innerHTML="";
container.append(I18n.getTranslation("friends.pending:"));
for(const user of this.localuser.inrelation){
if(user.relationshipType===3||user.relationshipType===4){
const buttons=document.createElement("div");
buttons.classList.add("flexltr");
const buttonc=document.createElement("div");
const button1=document.createElement("span");
button1.classList.add("svgicon","svg-x");
if(user.relationshipType===3){
const buttonc=document.createElement("div");
const button2=document.createElement("span");
button2.classList.add("svgicon","svg-x");
button2.classList.add("svg-addfriend");
buttonc.append(button2);
buttonc.classList.add("friendlyButton");
buttonc.append(button2);
buttons.append(buttonc);
buttonc.onclick=(e)=>{
e.stopImmediatePropagation();
user.changeRelationship(1);
outerDiv.remove();
}
}
buttonc.append(button1);
buttonc.classList.add("friendlyButton");
buttonc.onclick=(e)=>{
e.stopImmediatePropagation();
user.changeRelationship(0);
outerDiv.remove();
}
buttons.append(buttonc);
const outerDiv=genuserstrip(user,buttons);
container.append(outerDiv);
}
}
}
pending.onclick=genPending;
channelTopic.append(pending);
}
{
const blocked=document.createElement("button");
blocked.textContent=I18n.getTranslation("friends.blocked");
const genBlocked=()=>{
this.localuser.relationshipsUpdate=genBlocked;
checkVoid();
container.innerHTML="";
container.append(I18n.getTranslation("friends.blockedusers"));
for(const user of this.localuser.inrelation){
if(user.relationshipType===2){
const buttonc=document.createElement("div");
const button1=document.createElement("span");
button1.classList.add("svg-x","svgicon");
buttonc.append(button1);
buttonc.classList.add("friendlyButton");
buttonc.onclick=(e)=>{
user.changeRelationship(0);
e.stopImmediatePropagation();
outerDiv.remove();
}
const outerDiv=genuserstrip(user,buttonc);
container.append(outerDiv);
}
}
}
blocked.onclick=genBlocked;
channelTopic.append(blocked);
}
{
const add=document.createElement("button");
add.textContent=I18n.getTranslation("friends.addfriend");
add.onclick=()=>{
this.localuser.relationshipsUpdate=()=>{};
container.innerHTML="";
const float=new Float("");
const options=float.options;
const form=options.addForm("",(e:any)=>{
console.log(e);
if(e.code===404){
throw new FormError(text,I18n.getTranslation("friends.notfound"));
}else if(e.code===400){
throw new FormError(text,e.message.split("Error: ")[1]);
}else{
const box=text.input.deref();
if(!box)return;
box.value="";
}
},{
method:"POST",
fetchURL:this.info.api+"/users/@me/relationships",
headers:this.headers
});
const text=form.addTextInput(I18n.getTranslation("friends.addfriendpromt"),"username");
form.addPreprocessor((obj:any)=>{
const [username,discriminator]=obj.username.split("#");
obj.username=username;
obj.discriminator=discriminator;
if(!discriminator){
throw new FormError(text,I18n.getTranslation("friends.discnotfound"));
}
});
container.append(float.generateHTML());
}
channelTopic.append(add);
}
}
giveMember(_member: memberjson){ giveMember(_member: memberjson){
console.error("not a real guild, can't give member object"); console.error("not a real guild, can't give member object");
} }
@ -143,15 +356,15 @@ class Group extends Channel{
this.user = this.localuser.user; this.user = this.localuser.user;
} }
this.name ??= this.localuser.user.username; this.name ??= this.localuser.user.username;
this.parent_id!; this.parent_id!;
this.parent!; this.parent!;
this.children = []; this.children = [];
this.guild_id = "@me"; this.guild_id = "@me";
this.permission_overwrites = new Map(); this.permission_overwrites = new Map();
this.lastmessageid = json.last_message_id; this.lastmessageid = json.last_message_id;
this.mentions = 0; this.mentions = 0;
this.setUpInfiniteScroller(); this.setUpInfiniteScroller();
this.updatePosition(); this.updatePosition();
} }
updatePosition(){ updatePosition(){
if(this.lastmessageid){ if(this.lastmessageid){
@ -202,6 +415,10 @@ class Group extends Channel{
loading.classList.add("loading"); loading.classList.add("loading");
this.rendertyping(); this.rendertyping();
(document.getElementById("typebox") as HTMLDivElement).contentEditable ="" + true;
(document.getElementById("upload") as HTMLElement).style.visibility="visible";
(document.getElementById("typediv") as HTMLElement).style.visibility="visible";
(document.getElementById("typebox") as HTMLDivElement).focus();
await this.putmessages(); await this.putmessages();
await prom; await prom;
this.localuser.getSidePannel(); this.localuser.getSidePannel();
@ -209,10 +426,7 @@ class Group extends Channel{
return; return;
} }
this.buildmessages(); this.buildmessages();
(document.getElementById("typebox") as HTMLDivElement).contentEditable ="" + true;
(document.getElementById("upload") as HTMLElement).style.visibility="visible";
(document.getElementById("typediv") as HTMLElement).style.visibility="visible";
(document.getElementById("typebox") as HTMLDivElement).focus();
} }
messageCreate(messagep: { d: messagejson }){ messageCreate(messagep: { d: messagejson }){
const messagez = new Message(messagep.d, this); const messagez = new Message(messagep.d, this);

View file

@ -626,7 +626,7 @@ class Guild extends SnowFlake{
if(addstate){ if(addstate){
history.pushState([this.id,undefined], "", "/channels/" + this.id); history.pushState([this.id,undefined], "", "/channels/" + this.id);
} }
this.localuser.pageTitle("Weird spot"); this.localuser.pageTitle(I18n.getTranslation("guild.emptytitle"));
const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement; const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement;
channelTopic.setAttribute("hidden", ""); channelTopic.setAttribute("hidden", "");
@ -640,7 +640,7 @@ class Guild extends SnowFlake{
} }
const h1=document.createElement("h1"); const h1=document.createElement("h1");
h1.classList.add("messagecontainer") h1.classList.add("messagecontainer")
h1.textContent="You're in a weird spot, this guild has no channels"; h1.textContent=I18n.getTranslation("guild.emptytext");
messages.append(h1); messages.append(h1);
} }
loadGuild(){ loadGuild(){

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180"><g fill="red"><circle cx="71" cy="31.3" r="27.5"/><path d="M72.2 62.1A48.2 48.2 0 0 0 23.5 110l-.6 70h96.5l.3-32a13.5 13.5 0 0 1-12-13.2v-10.2H97.4A13.5 13.5 0 0 1 84 111.1a13.5 13.5 0 0 1 13.5-13.5h10.1V87.5a13.5 13.5 0 0 1 2.1-7 48.2 48.2 0 0 0-37.5-18.4z" overflow="visible"/><path stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width="15" d="M121.1 87.5v47.3m23.7-23.7H97.5"/></g></svg>

After

Width:  |  Height:  |  Size: 472 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180"><g fill="red"><circle cx="97.7" cy="97.7" r="82.3"/><path d="M0 180h90v-80Z"/></g></svg>

After

Width:  |  Height:  |  Size: 150 B

View file

@ -59,7 +59,7 @@
<span class="svgicon svg-category"></span> <span class="svgicon svg-category"></span>
</label> </label>
<input type="checkbox" id="maintoggle"> <input type="checkbox" id="maintoggle">
<span class="flexltr"> <span class="flexltr" style="align-items: center;">
<span id="channelname">Channel name</span> <span id="channelname">Channel name</span>
<span id="channelTopic" class="ellipsis" hidden>Channel topic</span> <span id="channelTopic" class="ellipsis" hidden>Channel topic</span>
</span> </span>

View file

@ -505,7 +505,25 @@ roleCreate | {
op:9, op:9,
d:boolean, d:boolean,
s:number s:number
}|memberlistupdatejson|voiceupdate|voiceserverupdate; }|memberlistupdatejson|voiceupdate|voiceserverupdate|{
op: 0,
t: "RELATIONSHIP_ADD",
d: {
id: string,
type: 0|1|2|3|4|5|6,
user: userjson
},
s: number
}|{
op: 0,
t: "RELATIONSHIP_REMOVE",
d: {
id: string,
type: number,
nickname: null
},
s: number
};
type memberChunk = { type memberChunk = {

View file

@ -124,12 +124,14 @@ class Localuser{
const user = new User(thing.user, this); const user = new User(thing.user, this);
user.nickname = thing.nickname; user.nickname = thing.nickname;
user.relationshipType = thing.type; user.relationshipType = thing.type;
this.inrelation.add(user);
} }
this.pingEndpoint(); this.pingEndpoint();
this.userinfo.updateLocal(); this.userinfo.updateLocal();
} }
inrelation=new Set<User>();
outoffocus(): void{ outoffocus(): void{
const servers = document.getElementById("servers") as HTMLDivElement; const servers = document.getElementById("servers") as HTMLDivElement;
servers.innerHTML = ""; servers.innerHTML = "";
@ -365,6 +367,7 @@ class Localuser{
}); });
await promise; await promise;
} }
relationshipsUpdate=()=>{};
async handleEvent(temp: wsjson){ async handleEvent(temp: wsjson){
console.debug(temp); console.debug(temp);
if(temp.s)this.lastSequence = temp.s; if(temp.s)this.lastSequence = temp.s;
@ -539,6 +542,23 @@ class Localuser{
guild.memberupdate(temp.d) guild.memberupdate(temp.d)
break break
} }
case "RELATIONSHIP_ADD":{
const user = new User(temp.d.user, this);
user.nickname = null;
user.relationshipType = temp.d.type;
this.inrelation.add(user);
this.relationshipsUpdate();
break;
}
case "RELATIONSHIP_REMOVE":{
const user = this.userMap.get(temp.d.id);
if(!user) return;
user.nickname = null;
user.relationshipType = 0;
this.inrelation.delete(user);
this.relationshipsUpdate();
break;
}
default :{ default :{
//@ts-ignore //@ts-ignore
console.warn("Unhandled case "+temp.t,temp); console.warn("Unhandled case "+temp.t,temp);

View file

@ -516,11 +516,27 @@ class HtmlArea implements OptionsElement<void>{
} }
watchForChange(){} watchForChange(){}
} }
/**
* This is a simple wrapper class for Options to make it happy so it can be used outside of Settings.
*/
class Float{
options:Options;
/**
* This is a simple wrapper class for Options to make it happy so it can be used outside of Settings.
*/
constructor(name:string, options={ ltr:false, noSubmit:false}){
this.options=new Options(name,this,options)
}
changed=()=>{};
generateHTML(){
return this.options.generateHTML();
}
}
class Options implements OptionsElement<void>{ class Options implements OptionsElement<void>{
name: string; name: string;
haschanged = false; haschanged = false;
readonly options: OptionsElement<any>[]; readonly options: OptionsElement<any>[];
readonly owner: Buttons | Options | Form; readonly owner: Buttons | Options | Form | Float;
readonly ltr: boolean; readonly ltr: boolean;
value!: void; value!: void;
readonly html: WeakMap<OptionsElement<any>, WeakRef<HTMLDivElement>> = new WeakMap(); readonly html: WeakMap<OptionsElement<any>, WeakRef<HTMLDivElement>> = new WeakMap();
@ -530,7 +546,7 @@ class Options implements OptionsElement<void>{
); );
constructor( constructor(
name: string, name: string,
owner: Buttons | Options | Form, owner: Buttons | Options | Form | Float,
{ ltr = false, noSubmit=false} = {} { ltr = false, noSubmit=false} = {}
){ ){
this.name = name; this.name = name;
@ -1145,38 +1161,84 @@ class Form implements OptionsElement<object>{
} }
console.log("middle2"); console.log("middle2");
await Promise.allSettled(promises); await Promise.allSettled(promises);
this.preprocessor(build); try{
this.preprocessor(build);
}catch(e){
if(e instanceof FormError){
const elm = this.options.html.get(e.elem);
if(elm){
const html = elm.deref();
if(html){
this.makeError(html, e.message);
}
}
}
return;
}
if(this.fetchURL !== ""){ if(this.fetchURL !== ""){
fetch(this.fetchURL, { fetch(this.fetchURL, {
method: this.method, method: this.method,
body: JSON.stringify(build), body: JSON.stringify(build),
headers: this.headers, headers: this.headers,
}) })
.then(_=>_.json()) .then(_=>{
return _.text()
}).then(_=>{
if(_==="") return {};
return JSON.parse(_)
})
.then(json=>{ .then(json=>{
if(json.errors && this.errors(json.errors))return; if(json.errors){
this.onSubmit(json); if(this.errors(json)){
return;
}
}
try{
this.onSubmit(json);
}catch(e){
console.error(e);
if(e instanceof FormError){
const elm = this.options.html.get(e.elem);
if(elm){
const html = elm.deref();
if(html){
this.makeError(html, e.message);
}
}
}
return;
}
}); });
}else{ }else{
this.onSubmit(build); try{
this.onSubmit(build);
}catch(e){
if(e instanceof FormError){
const elm = this.options.html.get(e.elem);
if(elm){
const html = elm.deref();
if(html){
this.makeError(html, e.message);
}
}
}
return;
}
} }
console.warn("needs to be implemented"); console.warn("needs to be implemented");
} }
errors(errors: { errors(errors: {code: number; message: string; errors: { [key: string]: { _errors: { message: string; code: string }[] } }}){
code: number;
message: string;
errors: { [key: string]: { _errors: { message: string; code: string } } };
}){
if(!(errors instanceof Object)){ if(!(errors instanceof Object)){
return; return;
} }
for(const error of Object.keys(errors)){ for(const error of Object.keys(errors.errors)){
const elm = this.names.get(error); const elm = this.names.get(error);
if(elm){ if(elm){
const ref = this.options.html.get(elm); const ref = this.options.html.get(elm);
if(ref && ref.deref()){ if(ref && ref.deref()){
const html = ref.deref() as HTMLDivElement; const html = ref.deref() as HTMLDivElement;
this.makeError(html, errors.errors[error]._errors.message); const errorMessage=errors.errors[error]._errors[0].message;
this.makeError(html, errorMessage);
return true; return true;
} }
} }
@ -1253,4 +1315,4 @@ class Settings extends Buttons{
} }
} }
export{ Settings, OptionsElement, Buttons, Options,Form }; export{ Settings, OptionsElement, Buttons, Options,Form,Float };

View file

@ -256,9 +256,15 @@ textarea {
} }
.svg-friends{ .svg-friends{
mask: url(/icons/friends.svg); mask: url(/icons/friends.svg);
width: 24px !important;!i;!; width: 24px !important;
height: 24px !important;!i;!; height: 24px !important;
margin-right: 0 !important;!i;!; margin-right: 0 !important;
}
.svg-frmessage{
mask: url(/icons/frmessage.svg);
}
.svg-addfriend{
mask: url(/icons/addfriend.svg);
} }
.svgicon { .svgicon {
display: block; display: block;
@ -833,6 +839,9 @@ span.instanceStatus {
margin: auto 0 0 8px; margin: auto 0 0 8px;
font-size: .9em; font-size: .9em;
color: var(--primary-text-soft); color: var(--primary-text-soft);
button{
margin-right:.05in;
}
} }
#channelTopic[hidden] { #channelTopic[hidden] {
display: none; display: none;
@ -2045,7 +2054,18 @@ fieldset input[type="radio"] {
margin: 6px 12px; margin: 6px 12px;
} }
} }
.friendcontainer{
display: flex;
width: 100%;
padding: .2in;
>div{
background:#00000030;
margin-bottom:.1in;
padding:.06in .1in;
border-radius:.1in;
border: solid 1px var(--black);
}
}
.fixedsearch{ .fixedsearch{
position: absolute; position: absolute;
background: var(--primary-bg); background: var(--primary-bg);
@ -2064,6 +2084,35 @@ fieldset input[type="radio"] {
} }
} }
.suberror{
animation: goout 6s forwards;
}
.suberrora{
background:var(--channel-hover);
border-radius:.1in;
position:absolute;
border:solid var(--primary-text) .02in;
color:color-mix(in hsl,var(--yellow),var(--red));
font-weight:bold;
opacity:0;
cursor:default;
/* height: .4in; */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-evenly;
padding: .075in;
box-sizing: border-box;
pointer-events: none;
}
@keyframes goout {
0%,100%{
opacity:0;
}
5%,90%{
opacity:1;
}
}
.friendsbutton{ .friendsbutton{
transition: background-color .2s; transition: background-color .2s;
background-color: #00000050; background-color: #00000050;
@ -2072,3 +2121,16 @@ fieldset input[type="radio"] {
.bigemoji{ .bigemoji{
width:.6in; width:.6in;
} }
.friendlyButton{
padding: .07in;
background: #00000045;
transition:background .2s;
border-radius: 1in;
border: solid 1px var(--black);
width: 24px;
height: 24px;
margin: 0 .05in;
}
.friendlyButton:hover{
background:black;
}

View file

@ -8,6 +8,7 @@ import{ presencejson, userjson }from"./jsontypes.js";
import { Role } from "./role.js"; import { Role } from "./role.js";
import { Search } from "./search.js"; import { Search } from "./search.js";
import { I18n } from "./i18n.js"; import { I18n } from "./i18n.js";
import { Direct } from "./direct.js";
class User extends SnowFlake{ class User extends SnowFlake{
owner: Localuser; owner: Localuser;
@ -15,7 +16,7 @@ class User extends SnowFlake{
avatar!: string | null; avatar!: string | null;
username!: string; username!: string;
nickname: string | null = null; nickname: string | null = null;
relationshipType: 0 | 1 | 2 | 3 | 4 = 0; relationshipType: 0 | 1 | 2 | 3 | 4 | 5 | 6 = 0;
bio!: MarkDown; bio!: MarkDown;
discriminator!: string; discriminator!: string;
pronouns!: string; pronouns!: string;
@ -85,31 +86,59 @@ class User extends SnowFlake{
this.setstatus("offline"); this.setstatus("offline");
} }
} }
get online(){
return (this.status)&&(this.status!="offline");
}
setstatus(status: string): void{ setstatus(status: string): void{
this.status = status; this.status = status;
} }
async getStatus(): Promise<string>{ getStatus(): string{
return this.status || "offline"; return this.status || "offline";
} }
static contextmenu = new Contextmenu<User, Member | undefined>("User Menu"); static contextmenu = new Contextmenu<User, Member | undefined>("User Menu");
async opendm(){
for(const dm of (this.localuser.guildids.get("@me") as Direct).channels){
if(dm.user.id===this.id){
this.localuser.goToChannel(dm.id);
return;
}
}
await fetch(this.info.api + "/users/@me/channels", {
method: "POST",
body: JSON.stringify({ recipients: [this.id] }),
headers: this.localuser.headers,
})
.then(res=>res.json())
.then(json=>{
this.localuser.goToChannel(json.id);
});
return;
}
async changeRelationship(type:0|1|2|3|4|5){
if(type!==0){
await fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
method: "PUT",
headers: this.owner.headers,
body: JSON.stringify({
type,
}),
});
}else{
await fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
method: "DELETE",
headers: this.owner.headers
});
}
this.relationshipType=type;
}
static setUpContextMenu(): void{ static setUpContextMenu(): void{
this.contextmenu.addbutton(()=>I18n.getTranslation("user.copyId"), function(this: User){ this.contextmenu.addbutton(()=>I18n.getTranslation("user.copyId"), function(this: User){
navigator.clipboard.writeText(this.id); navigator.clipboard.writeText(this.id);
}); });
this.contextmenu.addbutton(()=>I18n.getTranslation("user.message"), function(this: User){ this.contextmenu.addbutton(()=>I18n.getTranslation("user.message"), function(this: User){
fetch(this.info.api + "/users/@me/channels", { this.opendm();
method: "POST",
body: JSON.stringify({ recipients: [this.id] }),
headers: this.localuser.headers,
})
.then(res=>res.json())
.then(json=>{
this.localuser.goToChannel(json.id);
});
}); });
this.contextmenu.addbutton( this.contextmenu.addbutton(
()=>I18n.getTranslation("user.block"), ()=>I18n.getTranslation("user.block"),
@ -133,13 +162,7 @@ class User extends SnowFlake{
} }
); );
this.contextmenu.addbutton(()=>I18n.getTranslation("user.friendReq"), function(this: User){ this.contextmenu.addbutton(()=>I18n.getTranslation("user.friendReq"), function(this: User){
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, { this.changeRelationship(1);
method: "PUT",
headers: this.owner.headers,
body: JSON.stringify({
type: 1,
}),
});
}); });
this.contextmenu.addbutton( this.contextmenu.addbutton(
()=>I18n.getTranslation("user.kick"), ()=>I18n.getTranslation("user.kick"),
@ -370,15 +393,8 @@ class User extends SnowFlake{
); );
} }
block(): void{ async block(){
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, { await this.changeRelationship(2);
method: "PUT",
headers: this.owner.headers,
body: JSON.stringify({
type: 2,
}),
});
this.relationshipType = 2;
const channel = this.localuser.channelfocus; const channel = this.localuser.channelfocus;
if(channel){ if(channel){
for(const message of channel.messages){ for(const message of channel.messages){
@ -387,12 +403,8 @@ class User extends SnowFlake{
} }
} }
unblock(): void{ async unblock(){
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, { await this.changeRelationship(0);
method: "DELETE",
headers: this.owner.headers,
});
this.relationshipType = 0;
const channel = this.localuser.channelfocus; const channel = this.localuser.channelfocus;
if(channel){ if(channel){
for(const message of channel.messages){ for(const message of channel.messages){

View file

@ -229,7 +229,9 @@
"noDelete":"Nevermind", "noDelete":"Nevermind",
"create":"Create guild", "create":"Create guild",
"loadingDiscovery":"Loading...", "loadingDiscovery":"Loading...",
"disoveryTitle":"Guild discovery ($1) {{PLURAL:$1|entry|entries}}" "disoveryTitle":"Guild discovery ($1) {{PLURAL:$1|entry|entries}}",
"emptytitle":"Weird spot",
"emptytext":"You're in a weird spot, this guild has no channels"
}, },
"role":{ "role":{
"displaySettings":"Display settings", "displaySettings":"Display settings",
@ -345,11 +347,28 @@
"joinUsing":"Join using invite", "joinUsing":"Join using invite",
"inviteLinkCode":"Invite Link/Code" "inviteLinkCode":"Invite Link/Code"
}, },
"friends":{
"blocked":"Blocked",
"blockedusers":"Blocked Users:",
"addfriend":"Add Friend",
"addfriendpromt":"Add friends by username:",
"notfound":"User not found",
"discnotfound":"Discriminator not found",
"pending":"Pending",
"pending:":"Pending friend requests:",
"all":"All",
"all:":"All friends:",
"online":"Online",
"online:":"Online friends:",
"friendlist":"Friend List",
"friends":"Friends"
},
"replyingTo":"Replying to $1", "replyingTo":"Replying to $1",
"DMs":{ "DMs":{
"copyId":"Copy DM id", "copyId":"Copy DM id",
"markRead":"Mark as read", "markRead":"Mark as read",
"close":"Close DM" "close":"Close DM",
"name":"Dirrect Messages"
}, },
"user":{ "user":{
"copyId":"Copy user ID", "copyId":"Copy user ID",