Remove avatar button
This commit is contained in:
parent
8cc6f6b50f
commit
b3ae7ba703
@ -165,6 +165,8 @@ label {
|
||||
transform: translateX(26px);
|
||||
}
|
||||
#avatarContainer {
|
||||
position: relative;
|
||||
padding-bottom: 1.5em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
@ -191,6 +193,14 @@ label {
|
||||
#avatarContainer label:hover p {
|
||||
display: block;
|
||||
}
|
||||
#removeAvatar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
#removeAvatar:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
#profile_info section {
|
||||
display: block;
|
||||
margin-bottom: 20px;
|
||||
@ -199,12 +209,12 @@ label {
|
||||
#profile_info section:first-of-type {
|
||||
border-top: unset;
|
||||
}
|
||||
#profile_info section:first-of-type h3 {
|
||||
margin: 0;
|
||||
}
|
||||
#profile_info input {
|
||||
margin: 10px;
|
||||
}
|
||||
#profile_info span {
|
||||
font-weight: bold;
|
||||
}
|
||||
#profile_info>div>div p {
|
||||
font-weight: normal;
|
||||
font-size: 0.9em;
|
||||
@ -275,10 +285,6 @@ label {
|
||||
#me>div:hover p {
|
||||
color: var(--accent);
|
||||
}
|
||||
#identity_fingerprint {
|
||||
text-align: center;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#left_panel ul:last-of-type, #msg_log {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
@ -244,6 +244,7 @@ profile_div.onclick = function() {
|
||||
labelAvatar.setAttribute("for", "avatar_input");
|
||||
let inputAvatar = document.createElement("input");
|
||||
inputAvatar.type = "file";
|
||||
inputAvatar.accept = "image/*";
|
||||
inputAvatar.id = "avatar_input";
|
||||
inputAvatar.onchange = function(event) {
|
||||
let file = event.target.files[0];
|
||||
@ -253,11 +254,7 @@ profile_div.onclick = function() {
|
||||
fetch("/set_avatar", {method: "POST", body: formData}).then(response => {
|
||||
if (response.ok) {
|
||||
avatarTimestamps.set("self", Date.now());
|
||||
document.querySelector("#avatarContainer .avatar").src = "/avatar/self?"+avatarTimestamps.get("self");
|
||||
displayProfile();
|
||||
if (currentSessionId != -1) {
|
||||
displayHistory();
|
||||
}
|
||||
refreshSelfAvatar();
|
||||
} else {
|
||||
console.log(response);
|
||||
}
|
||||
@ -277,11 +274,14 @@ profile_div.onclick = function() {
|
||||
uploadP.textContent = "Upload";
|
||||
labelAvatar.appendChild(uploadP);
|
||||
avatarContainer.appendChild(labelAvatar);
|
||||
let removeAvatar = document.createElement("span");
|
||||
removeAvatar.id = "removeAvatar";
|
||||
removeAvatar.textContent = "Remove";
|
||||
removeAvatar.onclick = function() {
|
||||
socket.send("remove_avatar");
|
||||
};
|
||||
avatarContainer.appendChild(removeAvatar);
|
||||
mainDiv.appendChild(avatarContainer);
|
||||
let fingerprint = document.createElement("pre");
|
||||
fingerprint.id = "identity_fingerprint";
|
||||
fingerprint.textContent = beautifyFingerprint(identityFingerprint);
|
||||
mainDiv.appendChild(fingerprint);
|
||||
let sectionName = document.createElement("section");
|
||||
let titleName = document.createElement("h3");
|
||||
titleName.textContent = "Name:";
|
||||
@ -299,6 +299,14 @@ profile_div.onclick = function() {
|
||||
};
|
||||
sectionName.appendChild(saveNameButton);
|
||||
mainDiv.appendChild(sectionName);
|
||||
let sectionFingerprint = document.createElement("section");
|
||||
let titleFingerprint = document.createElement("h3");
|
||||
titleFingerprint.textContent = "Your fingerprint:";
|
||||
sectionFingerprint.appendChild(titleFingerprint);
|
||||
let fingerprint = document.createElement("pre");
|
||||
fingerprint.textContent = beautifyFingerprint(identityFingerprint);
|
||||
sectionFingerprint.appendChild(fingerprint);
|
||||
mainDiv.appendChild(sectionFingerprint);
|
||||
let sectionPadding = document.createElement("section");
|
||||
sectionPadding.appendChild(generateSwitchPreference("Use PSEC padding", "PSEC padding obfuscates the length of your messages but uses more network bandwidth.", usePadding, function(checked) {
|
||||
socket.send("set_use_padding "+checked);
|
||||
@ -499,8 +507,8 @@ socket.onmessage = function(msg) {
|
||||
case "name_told":
|
||||
onNameTold(args[1], msg.data.slice(args[0].length+args[1].length+2));
|
||||
break;
|
||||
case "avatar_set":
|
||||
onAvatarSet(args[1]);
|
||||
case "avatar_changed":
|
||||
onAvatarChanged(args[1]);
|
||||
break;
|
||||
case "is_contact":
|
||||
onIsContact(args[1], args[2] === "true", args[3], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+4));
|
||||
@ -554,12 +562,15 @@ function onNameTold(sessionId, name) {
|
||||
}
|
||||
displaySessions();
|
||||
}
|
||||
function onAvatarSet(sessionId) {
|
||||
avatarTimestamps.set(sessionId, Date.now());
|
||||
function onAvatarChanged(sessionIdOrSelf) {
|
||||
avatarTimestamps.set(sessionIdOrSelf, Date.now());
|
||||
displaySessions();
|
||||
if (sessionId === currentSessionId) {
|
||||
if (sessionIdOrSelf === currentSessionId) {
|
||||
displayHeader();
|
||||
displayHistory(false);
|
||||
refreshAvatar("#session_info .avatar", sessionIdOrSelf);
|
||||
} else if (sessionIdOrSelf === "self") {
|
||||
refreshSelfAvatar();
|
||||
}
|
||||
}
|
||||
function setNotSeen(strSessionIds) {
|
||||
@ -818,6 +829,23 @@ function sendNextLargeFile(sessionId) {
|
||||
}
|
||||
});
|
||||
}
|
||||
function refreshAvatar(selector, sessionId) {
|
||||
let avatar = document.querySelector(selector);
|
||||
if (typeof avatar !== "undefined") {
|
||||
if (typeof sessionId === "undefined") {
|
||||
avatar.src = "/avatar/self?"+avatarTimestamps.get("self");
|
||||
} else {
|
||||
avatar.src = "/avatar/"+sessionId+"/"+sessionsData.get(sessionId).name+"?"+avatarTimestamps.get(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
function refreshSelfAvatar() {
|
||||
refreshAvatar("#avatarContainer .avatar");
|
||||
displayProfile();
|
||||
if (currentSessionId != -1) {
|
||||
displayHistory(false);
|
||||
}
|
||||
}
|
||||
function beautifyFingerprint(f) {
|
||||
for (let i=4; i<f.length; i+=5) {
|
||||
f = f.slice(0, i)+" "+f.slice(i);
|
||||
@ -1032,12 +1060,11 @@ function generateMsgHeader(name, sessionId) {
|
||||
p.appendChild(document.createTextNode(name));
|
||||
let div = document.createElement("div");
|
||||
div.classList.add("header");
|
||||
let timestamp = avatarTimestamps.get(sessionId);
|
||||
let avatar;
|
||||
if (typeof sessionId === "undefined") {
|
||||
avatar = generateSelfAvatar(timestamp);
|
||||
avatar = generateSelfAvatar(avatarTimestamps.get("self"));
|
||||
} else {
|
||||
avatar = generateAvatar(sessionId, name, timestamp);
|
||||
avatar = generateAvatar(sessionId, name, avatarTimestamps.get(sessionId));
|
||||
}
|
||||
div.appendChild(avatar);
|
||||
div.appendChild(p);
|
||||
|
@ -113,9 +113,15 @@ impl Identity {
|
||||
db.execute(&format!("UPDATE {} SET name=?1 WHERE uuid=?2", CONTACTS_TABLE), [encrypted_name.as_slice(), uuid.as_bytes()])
|
||||
}
|
||||
|
||||
pub fn set_contact_avatar(&self, contact_uuid: &Uuid, avatar_uuid: &Uuid) -> Result<usize, rusqlite::Error> {
|
||||
pub fn set_contact_avatar(&self, contact_uuid: &Uuid, avatar_uuid: Option<&Uuid>) -> Result<usize, rusqlite::Error> {
|
||||
let db = Connection::open(get_database_path())?;
|
||||
db.execute(&format!("UPDATE {} SET avatar=?1 WHERE uuid=?2", CONTACTS_TABLE), params![&avatar_uuid.as_bytes()[..], &contact_uuid.as_bytes()[..]])
|
||||
match avatar_uuid {
|
||||
Some(avatar_uuid) => db.execute(&format!("UPDATE {} SET avatar=?1 WHERE uuid=?2", CONTACTS_TABLE), params![&avatar_uuid.as_bytes()[..], &contact_uuid.as_bytes()[..]]),
|
||||
None => {
|
||||
db.execute(&format!("DELETE FROM {} WHERE uuid=(SELECT avatar FROM {} WHERE uuid=?)", AVATARS_TABLE, CONTACTS_TABLE), params![&contact_uuid.as_bytes()[..]])?;
|
||||
db.execute(&format!("UPDATE {} SET avatar=NULL WHERE uuid=?", CONTACTS_TABLE), params![&contact_uuid.as_bytes()[..]])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_contact_seen(&self, uuid: &Uuid, seen: bool) -> Result<usize, rusqlite::Error> {
|
||||
@ -473,6 +479,11 @@ impl Identity {
|
||||
db.upsert(DBKeys::AVATAR, avatar)
|
||||
}
|
||||
|
||||
pub fn remove_identity_avatar() -> Result<usize, rusqlite::Error> {
|
||||
let db = KeyValueTable::new(&get_database_path(), MAIN_TABLE)?;
|
||||
db.del(DBKeys::AVATAR)
|
||||
}
|
||||
|
||||
pub fn get_identity_avatar() -> Result<Vec<u8>, rusqlite::Error> {
|
||||
let db = KeyValueTable::new(&get_database_path(), MAIN_TABLE)?;
|
||||
db.get(DBKeys::AVATAR)
|
||||
|
@ -22,9 +22,9 @@ impl<'a> KeyValueTable<'a> {
|
||||
None => Err(rusqlite::Error::QueryReturnedNoRows)
|
||||
}
|
||||
}
|
||||
/*pub fn del(&self, key: &str) -> Result<usize, Error> {
|
||||
self.db.execute(&format!("DELETE FROM {} WHERE key=\"{}\"", self.table_name, key), NO_PARAMS)
|
||||
}*/
|
||||
pub fn del(&self, key: &str) -> Result<usize, Error> {
|
||||
self.db.execute(&format!("DELETE FROM {} WHERE key=\"{}\"", self.table_name, key), [])
|
||||
}
|
||||
pub fn update(&self, key: &str, value: &[u8]) -> Result<usize, Error> {
|
||||
self.db.execute(&format!("UPDATE {} SET value=? WHERE key=\"{}\"", self.table_name, key), params![value])
|
||||
}
|
||||
|
10
src/main.rs
10
src/main.rs
@ -231,6 +231,12 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
|
||||
buff: protocol::ask_profile_info()
|
||||
}).await;
|
||||
}
|
||||
"remove_avatar" => {
|
||||
match session_manager.remove_avatar().await {
|
||||
Ok(_) => ui_connection.on_avatar_changed(None),
|
||||
Err(e) => print_error!(e)
|
||||
}
|
||||
}
|
||||
"set_use_padding" => {
|
||||
let use_padding: bool = args[1].parse().unwrap();
|
||||
if let Err(e) = session_manager.identity.write().unwrap().as_mut().unwrap().set_use_padding(use_padding) {
|
||||
@ -240,9 +246,7 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
|
||||
"change_name" => {
|
||||
let new_name = &msg[args[0].len()+1..];
|
||||
match session_manager.change_name(new_name.to_string()).await {
|
||||
Ok(_) => {
|
||||
ui_connection.set_name(new_name)
|
||||
}
|
||||
Ok(_) => ui_connection.set_name(new_name),
|
||||
Err(e) => print_error!(e)
|
||||
};
|
||||
}
|
||||
|
@ -9,11 +9,12 @@ impl Headers {
|
||||
pub const ASK_PROFILE_INFO: u8 = 0x02;
|
||||
pub const NAME: u8 = 0x03;
|
||||
pub const AVATAR: u8 = 0x04;
|
||||
pub const ASK_LARGE_FILES: u8 = 0x05;
|
||||
pub const ACCEPT_LARGE_FILES: u8 = 0x06;
|
||||
pub const LARGE_FILE_CHUNK: u8 = 0x07;
|
||||
pub const ACK_CHUNK: u8 = 0x08;
|
||||
pub const ABORT_FILES_TRANSFER: u8 = 0x09;
|
||||
pub const REMOVE_AVATAR: u8 = 0x05;
|
||||
pub const ASK_LARGE_FILES: u8 = 0x06;
|
||||
pub const ACCEPT_LARGE_FILES: u8 = 0x07;
|
||||
pub const LARGE_FILE_CHUNK: u8 = 0x08;
|
||||
pub const ACK_CHUNK: u8 = 0x09;
|
||||
pub const ABORT_FILES_TRANSFER: u8 = 0x0a;
|
||||
}
|
||||
|
||||
pub fn new_message(message: String) -> Vec<u8> {
|
||||
@ -84,4 +85,8 @@ pub fn parse_ask_files(buffer: &[u8]) -> Option<Vec<(u64, String)>> {
|
||||
|
||||
pub fn avatar(avatar: &[u8]) -> Vec<u8> {
|
||||
[&[Headers::AVATAR], avatar].concat()
|
||||
}
|
||||
|
||||
pub fn remove_avatar() -> Vec<u8> {
|
||||
vec![Headers::REMOVE_AVATAR]
|
||||
}
|
@ -136,6 +136,21 @@ impl SessionManager {
|
||||
self.not_seen.write().unwrap().retain(|x| x != session_id);
|
||||
}
|
||||
|
||||
fn set_avatar_uuid(&self, session_id: &usize, avatar_uuid: Option<Uuid>) {
|
||||
let mut loaded_contacts = self.loaded_contacts.write().unwrap();
|
||||
if let Some(contact) = loaded_contacts.get_mut(session_id) {
|
||||
contact.avatar = avatar_uuid;
|
||||
if let Err(e) = self.identity.read().unwrap().as_ref().unwrap().set_contact_avatar(&contact.uuid, avatar_uuid.as_ref()) {
|
||||
print_error!(e);
|
||||
}
|
||||
} else {
|
||||
self.sessions.write().unwrap().get_mut(session_id).unwrap().avatar = avatar_uuid;
|
||||
}
|
||||
self.with_ui_connection(|ui_connection| {
|
||||
ui_connection.on_avatar_changed(Some(session_id));
|
||||
});
|
||||
}
|
||||
|
||||
async fn send_msg(&self, session_id: usize, session_write: &mut SessionWriteHalf, buff: &[u8], is_sending: &mut bool, file_ack_sender: &mut Option<Sender<bool>>) -> Result<(), PsecError> {
|
||||
self.encrypt_and_send(session_write, &buff).await?;
|
||||
if buff[0] == protocol::Headers::ACCEPT_LARGE_FILES {
|
||||
@ -342,23 +357,8 @@ impl SessionManager {
|
||||
match image::load_from_memory(&buffer[1..]) {
|
||||
Ok(image) => {
|
||||
drop(image);
|
||||
let identity_opt = self.identity.read().unwrap();
|
||||
let identity = identity_opt.as_ref().unwrap();
|
||||
match identity.store_avatar(&buffer[1..]) {
|
||||
Ok(avatar_uuid) => {
|
||||
let mut loaded_contacts = self.loaded_contacts.write().unwrap();
|
||||
if let Some(contact) = loaded_contacts.get_mut(&session_id) {
|
||||
contact.avatar = Some(avatar_uuid);
|
||||
if let Err(e) = identity.set_contact_avatar(&contact.uuid, &avatar_uuid) {
|
||||
print_error!(e);
|
||||
}
|
||||
} else {
|
||||
self.sessions.write().unwrap().get_mut(&session_id).unwrap().avatar = Some(avatar_uuid);
|
||||
}
|
||||
self.with_ui_connection(|ui_connection| {
|
||||
ui_connection.on_avatar_set(&session_id);
|
||||
});
|
||||
}
|
||||
match self.identity.read().unwrap().as_ref().unwrap().store_avatar(&buffer[1..]) {
|
||||
Ok(avatar_uuid) => self.set_avatar_uuid(&session_id, Some(avatar_uuid)),
|
||||
Err(e) => print_error!(e)
|
||||
}
|
||||
}
|
||||
@ -366,6 +366,7 @@ impl SessionManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
protocol::Headers::REMOVE_AVATAR => self.set_avatar_uuid(&session_id, None),
|
||||
_ => {
|
||||
let header = buffer[0];
|
||||
let buffer = match header {
|
||||
@ -691,6 +692,18 @@ impl SessionManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
pub async fn remove_avatar(&self) -> Result<(), rusqlite::Error> {
|
||||
Identity::remove_identity_avatar()?;
|
||||
let avatar_msg = protocol::remove_avatar();
|
||||
for sender in self.get_all_senders().into_iter() {
|
||||
sender.send(SessionCommand::Send {
|
||||
buff: avatar_msg.clone()
|
||||
}).await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
pub async fn change_name(&self, new_name: String) -> Result<usize, rusqlite::Error> {
|
||||
let telling_name = protocol::name(&new_name);
|
||||
|
@ -112,8 +112,11 @@ mod ui_messages {
|
||||
pub fn on_name_told(session_id: &usize, name: &str) -> Message {
|
||||
Message::from(format!("name_told {} {}", session_id, name))
|
||||
}
|
||||
pub fn on_avatar_set(session_id: &usize) -> Message {
|
||||
simple_event("avatar_set", session_id)
|
||||
pub fn on_avatar_changed(session_id: Option<&usize>) -> Message {
|
||||
match session_id {
|
||||
Some(session_id) => simple_event("avatar_changed", session_id),
|
||||
None => Message::from("avatar_changed self")
|
||||
}
|
||||
}
|
||||
pub fn set_as_contact(session_id: usize, name: &str, verified: bool, fingerprint: &str) -> Message {
|
||||
Message::from(format!("is_contact {} {} {} {}", session_id, verified, fingerprint, name))
|
||||
@ -182,8 +185,8 @@ impl UiConnection {
|
||||
pub fn on_name_told(&mut self, session_id: &usize, name: &str) {
|
||||
self.write_message(ui_messages::on_name_told(session_id, name));
|
||||
}
|
||||
pub fn on_avatar_set(&mut self, session_id: &usize) {
|
||||
self.write_message(ui_messages::on_avatar_set(session_id));
|
||||
pub fn on_avatar_changed(&mut self, session_id: Option<&usize>) {
|
||||
self.write_message(ui_messages::on_avatar_changed(session_id));
|
||||
}
|
||||
|
||||
pub fn inc_files_transfer(&mut self, session_id: &usize, chunk_size: u64) {
|
||||
|
Loading…
Reference in New Issue
Block a user