Skip to content

People App redesign #1422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2178761
Basic application.
Armored-Dragon Apr 8, 2025
466aa65
Serverless fix.
Armored-Dragon Apr 8, 2025
410e370
Audio levels.
Armored-Dragon Apr 8, 2025
3b514dd
Solve a few QML errors.
Armored-Dragon Apr 8, 2025
86586f2
User list alignment.
Armored-Dragon Apr 8, 2025
79897fd
Change volume bar color, added margin.
Armored-Dragon Apr 8, 2025
0e79249
Set user volume.
Armored-Dragon Apr 9, 2025
b0fdaaa
Don't show ourself in the list.
Armored-Dragon Apr 9, 2025
379e45f
User actions.
Armored-Dragon Apr 9, 2025
afa48fe
isAdmin > canKick.
Armored-Dragon Apr 9, 2025
ee69d8b
Focused user halo.
Armored-Dragon Apr 9, 2025
50da57a
User teleportation.
Armored-Dragon Apr 9, 2025
5fe8487
Account availability. Edit display name.
Armored-Dragon Apr 9, 2025
39d17b9
Fix more QML warnings.
Armored-Dragon Apr 9, 2025
4edca99
User usernames. Better long name handling.
Armored-Dragon Apr 9, 2025
4b6ecb2
Better ignore handling.
Armored-Dragon Apr 9, 2025
df11fd1
Fix logspam when focus user disconnects.
Armored-Dragon Apr 9, 2025
1fc300b
Contacts. Friends.
Armored-Dragon Apr 10, 2025
f8c4742
App icon.
Armored-Dragon Apr 10, 2025
b72f39a
Moved app to /people, dropping "uui-" prefix. Added to default scripts.
Armored-Dragon Apr 10, 2025
08eb1f5
Highlight all children of avatar.
Armored-Dragon Apr 15, 2025
83b13e5
Edit persona buttons.
Armored-Dragon Apr 15, 2025
34eaf62
Overte directory server libraries.
Armored-Dragon Apr 16, 2025
94e7b4d
Minor library cleanup.
Armored-Dragon Apr 16, 2025
af08d57
Improved sendMyData readability.
Armored-Dragon Apr 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/defaultScripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
"system/menu.js",
"system/bubble.js",
"system/snapshot.js",
"system/pal.js", // "system/mod.js", // older UX, if you prefer
"system/people/people.js", //"system/pal.js" for older UIX, "system/mod.js" for older UIX.
"system/avatarapp.js",
"system/graphicsSettings.js",
"system/makeUserConnection.js",
Expand Down
1 change: 1 addition & 0 deletions scripts/system/people/img/default_profile_avatar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 80 additions & 0 deletions scripts/system/people/img/icon_black.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions scripts/system/people/img/icon_white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 127 additions & 0 deletions scripts/system/people/libs/contacts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//
// contacts.js
//
// A small library to help with managing user contacts
//
// Created by Armored Dragon, 2025.
// Copyright 2025 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
"use strict";

let helper = Script.require("./helper.js");

const directoryBase = Account.metaverseServerURL;

let contactsLib = {
contacts: [],

addContact: (uuid) => {
return new Promise((resolve, reject) => {
print(`Adding contact '${uuid}'`);

const requestUrl = `${directoryBase}/api/v1/user/connection_request`;
const requestBody = {'node_id': helper.removeCurlyBracesFromUuid(MyAvatar.sessionUUID), 'proposed_node_id': helper.removeCurlyBracesFromUuid(uuid)};

helper.request(requestUrl, "POST", {'user_connection_request': requestBody}).then(onResponse);

function onResponse(response){
const responseJSON = helper.makeJSON(response);

// Error check
if (responseJSON.status !== "success") {
print(`Error sending contact request.`)
return reject({success: false, message: "Unknown error", response: responseJSON});
}


// We sent a request, but the recipient does not have an outgoing request to us.
if (responseJSON.data.connection === "pending") {
print(`Contact request is pending.`);
return resolve({success: true, message: "Contact request sent.", accepted: false});
}

// We sent a request, and the recipient has a outgoing request for us.
// We are now contacts
if (responseJSON.data.connection.new_connection) {
print(`Contact request is accepted.`);
return resolve({success: true, message: `Contact request for ${uuid} accepted.`, accepted: true});
}
}
})
},
removeContact: (username) => {
return new Promise((resolve, reject) => {
print(`Removing contact '${username}'.`);

helper.request(`${directoryBase}/api/v1/user/connections/${username}`, `DELETE`).then(onResponse);

function onResponse(response){
const responseJSON = helper.makeJSON(response);

helper.logJSON(responseJSON);

if (responseJSON.status !== "success") {
print(`Error sending contact removal request.`)
return reject({success: false, message: "Unknown error", response: responseJSON});
}

resolve({success: true, message: `Contact '${username}' was removed.`})
}
});
},
addFriend: (username) => {
return new Promise((resolve, reject) => {
print(`Adding friend '${username}'.`);

helper.request(`${directoryBase}/api/v1/user/friends`, `POST`, {username: username}).then(onResponse);

function onResponse(response) {
const responseJSON = helper.makeJSON(response);
helper.logJSON(responseJSON);
}
})
},
removeFriend: (username) => {
return new Promise((resolve, reject) => {
print(`Removing friend '${username}'.`);
helper.request(`${directoryBase}/api/v1/user/friends/${username}`, `DELETE`).then(onResponse);

function onResponse(response) {
const responseJSON = helper.makeJSON(response);
helper.logJSON(responseJSON);
}
})
},
getContactList: () => {
return new Promise((resolve, reject) => {
print(`Getting contact list.`);

helper.request(`https://mv.overte.org/server/api/v1/users/connections`).then(onResponse);

function onResponse(response) {
const responseJSON = helper.makeJSON(response);

if (responseJSON.status !== "success") {
print(`Error requesting contacts.`);
return reject({success: false, message: "Unknown error", response: responseJSON});
}

contactsLib.contacts = responseJSON.data.users;
resolve({success: true, message: "Contacts have been updated", contacts: contactsLib.contacts});
}
});
},
getContactByUsername: (username, refreshContactList = false) => {
return new Promise(async (resolve, reject) => {
if (refreshContactList) await contactsLib.getContactList();

const contactSingle = contactsLib.contacts.find((contact) => contact.username === username);

return resolve({success: true, contact: contactSingle});
});
}
}

module.exports = contactsLib;
51 changes: 51 additions & 0 deletions scripts/system/people/libs/helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// helper.js
//
// A small library that provides helper functions used throughout this application.
//
// Created by Armored Dragon, 2025.
// Copyright 2025 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
"use strict";

let helper = {
removeCurlyBracesFromUuid: (Uuid) => {
return Uuid.slice(1, -1);
},
request: (url, method = "GET", body) => {
return new Promise((resolve) => {
let req = new XMLHttpRequest();
req.onreadystatechange = function () {
if (req.readyState === req.DONE) {
if (req.status === 200) {
resolve(req.responseText);
}
else {
print("Error", req.status, req.statusText);
}
}
};

req.open(method, url);
if (method == `POST`) req.setRequestHeader("Content-Type", "application/json");
req.send(JSON.stringify(body));
})
},
makeJSON: (string) => {
if (typeof string === "object") return string;
try {
return JSON.parse(string);
} catch {
print(`Could not turn into JSON:\n${string}`);
return {};
}
},
logJSON: (obj) => {
print(JSON.stringify(obj, null, 4));

}
}

module.exports = helper;
40 changes: 40 additions & 0 deletions scripts/system/people/libs/profiles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// contacts.js
//
// A small library to help with viewing and parsing user profiles
//
// Created by Armored Dragon, 2025.
// Copyright 2025 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
"use strict";

let helper = Script.require("./helper.js");

const directoryBase = Account.metaverseServerURL;

let profilesLib = {
getProfile: (username) => {
return new Promise((resolve, reject) => {
print(`Getting profile for '${username}'.`);

const url = `${directoryBase}/api/v1/users?filter=connections&per_page=10&search=${encodeURIComponent(username)}`

helper.request(url).then(onResponse);

function onResponse(response) {
response = helper.makeJSON(response);

if (response.status !== "success") {
print(`Error requesting profile for ${username}.`);
return reject({success: false, message: "Unknown error", response: response});
}

return resolve({success: true, message: `Found ${username}'s profile.`, profile: response.data.users[0]});
}
})
}
}

module.exports = profilesLib;
Loading