~nicohman/signal-rs

9efdf4d81a95e7159e4893b8618a1e8b412ceac0 — nicohman 7 months ago 414f67a
Fix contact bug and live-update chats in the UI when contacts are updated
M qml/SignalState.qml => qml/SignalState.qml +2 -0
@@ 12,6 12,7 @@ Item {
    property var headerItems: []
    property var editGroupMembersModel: ListModel {}
    property var currentGroup
    property bool currentIsGroup: false
    property bool desktopView: false
    function openView(viewName) {
        signalState.currentView = viewName;


@@ 38,6 39,7 @@ Item {
                break;
            case "editContact":
                let contact = signalState.contact(signalState.current);
                console.log(JSON.stringify(contact));
                signalState.currentTel = contact.Tel;
                window.pageStack.layers.push(Qt.resolvedUrl("EditContact.qml"));
                break;

M qml/chats/ChatList.qml => qml/chats/ChatList.qml +5 -0
@@ 27,6 27,11 @@ Kirigami.ScrollablePage {
                console.log("ChatList clicked");
                console.log(tel);
                signalState.currentChat = model;
                if (model.is_group) {
                    signalState.currentIsGroup = true;
                } else {
                    signalState.currentIsGroup = false;
                }
                signalState.setCurrent(tel);
                signal.show_chat(tel);
                signalState.openView("chatHistory");

M qml/chats/CreateChat.qml => qml/chats/CreateChat.qml +1 -0
@@ 17,6 17,7 @@ Kirigami.ScrollablePage {
                signalState.currentChat = {
                	is_group: false
                };
                signalState.currentIsGroup = false;
                console.log(model.tel);
                signalState.currentName = model.name;
                signalState.setCurrent(model.tel);

M qml/messages/ChatHistory.qml => qml/messages/ChatHistory.qml +6 -4
@@ 15,7 15,7 @@ Kirigami.ScrollablePage {
        icon.name: "document-edit"
        text: "Edit Chat"
        onTriggered: {
            if (signalState.currentChat.is_group) {
            if (signalState.currentIsGroup) {
                signalState.editGroup(signalState.currentChat.tel);
                signalState.openView("editGroup");
            } else {


@@ 25,7 25,7 @@ Kirigami.ScrollablePage {
    }
    function sendMessage() {
        console.log("Sending "+ msgTextInput.text +" to "+signalState.current);
        if (signalState.currentChat.is_group) {
        if (signalState.currentIsGroup) {
            signal.send_group_message(signalState.current, msgTextInput.text, "");
        } else {
            signal.send_message(signalState.current, msgTextInput.text, "");


@@ 34,7 34,9 @@ Kirigami.ScrollablePage {
    }
    Connections {
        target: signal
        function msgs_changed() {}
        function onChats_changed () {
            signalState.setCurrent(signalState.current);
        }
    }
    FileDialog {
        id: fd


@@ 44,7 46,7 @@ Kirigami.ScrollablePage {
        selectMultiple: false
        onAccepted: {
            var path = fd.fileUrl.toString().replace("file://", "");
            if (signalState.currentChat.is_group) {
            if (signalState.currentIsGroup) {
            signal.send_group_message(signalState.current, msgTextInput.text, path);

                } else {

M qml/messages/MessageUI.qml => qml/messages/MessageUI.qml +1 -1
@@ 147,7 147,7 @@ ItemDelegate {
                	leftPadding: 5
                	Label {
                		text: signal.resolve_name(message.message.source)
                		visible: signalState.currentChat && signalState.currentChat.is_group
                		visible: signalState.currentIsGroup
                	}
                }
                Row {

M src/main.rs => src/main.rs +20 -9
@@ 30,6 30,7 @@ use std::collections::*;
mod config;
mod util;
use config::*;
use futures::StreamExt;
use notify_rust::Notification;
use serde_json::json;
use std::cell::*;


@@ 274,10 275,12 @@ impl SignalUI {
                slf.state.as_mut().unwrap().process_response(res.clone());
                match res {
                    SignalResponse::ChatList(ref chats) => {
                        println!("Updating chats");
                        slf.chats.borrow_mut().reset_data(chats.clone());
                        slf.chats_changed();
                    }
                    SignalResponse::ContactList(_) => {
                        println!("Received ContactList");
                        slf.update_chats();
                    }
                    SignalResponse::ModelContactList(contacts) => {


@@ 348,8 351,7 @@ impl SignalUI {
                };
            });
        });
        let (res_sender, res_receiver) =
            glib::MainContext::channel::<SignalResponse>(glib::PRIORITY_DEFAULT);
        let (res_sender, mut res_receiver) = unbounded_channel::<SignalResponse>();
        let l_res_sender = res_sender.clone();
        let (req_sender, req_receiver) = unbounded_channel::<SignalRequest>();



@@ 357,9 359,15 @@ impl SignalUI {
            Presage::new(l_res_sender, config.clone(), req_sender.clone())
                .expect("Couldn't create Presage"),
        );
        res_receiver.attach(None, move |value| {
            process_res(value);
            glib::Continue(true)
        // Spawn a tokio task to receive the SignalResponses and call the Qt callback w/ them
        tokio::task::spawn(async move {
            loop {
                let next = res_receiver
                    .recv()
                    .await
                    .expect("SignalResponse channel dropped");
                process_res(next);
            }
        });
        res_sender
            .send(SignalResponse::Groups(vec![]))


@@ 406,14 414,14 @@ impl SignalUI {
            .values()
            .enumerate()
            .filter_map(|(i, contact)| {
                if let Some(msgs) = self.state.as_ref().unwrap().messages_id(&contact.tel).ok() {
                if let Some(msgs) = self.state.as_ref().unwrap().messages_id(&contact.uuid).ok() {
                    if msgs.len() > 0 {
                        let latest = msgs.values().max_by_key(|x| x.sent_at).unwrap();
                        constructed.push(contact.tel.clone());
                        constructed.push(contact.uuid.clone());
                        return Some(Chat {
                            ID: i as i32,
                            name: contact.name.clone(),
                            tel: contact.tel.clone(),
                            name: self.resolve_name(contact.uuid.clone()),
                            tel: contact.uuid.clone(),
                            is_group: false,
                            last: latest.message.clone(),
                            timestamp: latest.sent_at,


@@ 533,10 541,12 @@ async fn main() -> Result<(), std::boxed::Box<dyn std::error::Error>> {
        PathBuf::from(data_dir).join(PathBuf::from("cstore")),
    )
    .unwrap();
    // Check if the user is registered or not
    let registered = match config_store.state(&ProtocolContext::default())? {
        State::Registered { .. } => true,
        _ => false,
    };
    // Manually drop config store so that it doesn't block when starting the actual config store for the RegistrationController/SignalUI
    drop(config_store);
    unsafe {
        cpp! { {


@@ 562,6 572,7 @@ async fn main() -> Result<(), std::boxed::Box<dyn std::error::Error>> {
        engine.load_file("qrc:/qml/main.qml".into());
        engine.exec();
    } else {
        // Init webengine for the captcha page
        webengine::initialize();
        qml_register_type::<registration::RegistrationController>(
            CStr::from_bytes_with_nul(b"RegistrationController\0").unwrap(),

M src/presage_manager.rs => src/presage_manager.rs +17 -7
@@ 13,13 13,13 @@ pub struct Presage {
    pub group_store: Store<Group>,
    pub req_sender: UnboundedSender<SignalRequest>,
    pub whoami: Option<Uuid>,
    pub res_sender: glib::Sender<SignalResponse>,
    pub res_sender: UnboundedSender<SignalResponse>,
    pub data_dir: String,
}
impl Presage {
    pub async fn run(
        config_store: SledConfigStore,
        res_sender: glib::Sender<SignalResponse>,
        res_sender: UnboundedSender<SignalResponse>,
        mut req_receiver: UnboundedReceiver<SignalRequest>,
    ) {
        let (tx, mut rx) = futures::channel::mpsc::channel::<(Metadata, ContentBody)>(100);


@@ 245,7 245,7 @@ impl Presage {

    // Makes a new Presage struct.
    pub fn new(
        res_sender: glib::Sender<SignalResponse>,
        res_sender: UnboundedSender<SignalResponse>,
        config: Config,
        req_sender: UnboundedSender<SignalRequest>,
    ) -> Result<Presage> {


@@ 330,7 330,6 @@ impl Presage {
        return Ok(pre);
    }

    // TODO
    pub fn avatar(&self, id: &str) -> Option<String> {
        let opts = vec![
            "profile".to_string(),


@@ 347,7 346,6 @@ impl Presage {
        None
    }

    // TODO
    pub fn set_avatar(&self, id: String, data: &[u8]) -> String {
        let path = Path::new(self.data_dir.as_str())
            .join("avatars")


@@ 385,7 383,9 @@ impl Presage {
                }
            }
            SignalResponse::Metadata(meta) => {
                if let Ok(mut cont) = self.contact_doc(meta.sender.identifier().as_str()) {
                if let Ok(mut cont) =
                    self.contact_doc(meta.sender.identifier().to_uppercase().as_str())
                {
                    if let Some(uuid) = meta.sender.uuid {
                        if uuid.to_string().to_uppercase() != cont.inner.uuid {
                            cont.inner.uuid = uuid.to_string().to_uppercase();


@@ 407,7 407,7 @@ impl Presage {
                        .sender
                        .e164()
                        .map(|x| x.to_string())
                        .unwrap_or(meta.sender.uuid.unwrap().to_string())
                        .unwrap_or(meta.sender.uuid.unwrap().to_string().to_uppercase())
                        .to_uppercase();
                    let contact = Contact {
                        name,


@@ 427,7 427,17 @@ impl Presage {
                if let Some(v) = self.messages_id(&msg.chat_id).ok() {
                    if v.len() > 0 {
                        id = v.values().map(|msg| msg.ID).max().unwrap() + 1;
                    } else {
                        println!("No previous messages");
                        self.res_sender
                            .send(SignalResponse::ContactList(vec![]))
                            .expect("Couldn't send ContactList");
                    }
                } else {
                    println!("No previous messages");
                    self.res_sender
                        .send(SignalResponse::ContactList(vec![]))
                        .expect("Couldn't send ContactList");
                }
                msg.ID = id;
                self.add_message(msg, true);