~nicohman/signal-rs

526c539cb1fe23d3a9beafa59a6d39b4d36a14f3 — nicohman 9 months ago d2e4801
Add basic support for saving attachments
4 files changed, 42 insertions(+), 13 deletions(-)

M src/main.rs
M src/widgets/chat_history.rs
M src/widgets/chat_list.rs
M src/widgets/message.rs
M src/main.rs => src/main.rs +1 -3
@@ 6,6 6,7 @@ extern crate futures_util;
extern crate gdk_pixbuf;
extern crate gio;
extern crate glib;
extern crate glib_macros;
extern crate gtk;
extern crate libhandy;
extern crate mio;


@@ 16,7 17,6 @@ extern crate tokio;
extern crate tokio_tungstenite;
extern crate tungstenite;
extern crate url;
extern crate glib_macros;
#[macro_use]
extern crate lazy_static;
use futures_util::StreamExt;


@@ 291,7 291,6 @@ where
                history.insert_bottom(Element::Message(m.clone()));
            }
        }
        //history.listbox.invalidate_sort();
        self.current_chat.replace(Some(tel.clone()));
        self.last_id.replace(history.get_last_id());
        self.message_box.add(&history.listbox);


@@ 338,7 337,6 @@ where
                        }
                        self.last_id.replace(hist.get_last_id());
                    }
                    //hist.listbox.invalidate_sort();
                }
            }
            _ => {}

M src/widgets/chat_history.rs => src/widgets/chat_history.rs +6 -5
@@ 1,7 1,6 @@
use crate::*;
use std::collections::VecDeque;


/// A widget that displays and tracks
pub struct ChatHistory {
    pub list: VecDeque<Element>,


@@ 18,9 17,10 @@ impl ChatHistory {
            .selection_mode(SelectionMode::None)
            .activate_on_single_click(false)
            .build();
            listbox.set_sort_func(Some(std::boxed::Box::new(|a: &ListBoxRow, b: &ListBoxRow| {
                let a : String = a.get_property("name").unwrap().get().unwrap().unwrap();
                let b : String = b.get_property("name").unwrap().get().unwrap().unwrap();
        listbox.set_sort_func(Some(std::boxed::Box::new(
            |a: &ListBoxRow, b: &ListBoxRow| {
                let a: String = a.get_property("name").unwrap().get().unwrap().unwrap();
                let b: String = b.get_property("name").unwrap().get().unwrap().unwrap();
                let diff = a.parse::<i64>().unwrap() - b.parse::<i64>().unwrap();
                if diff < 0 {
                    -1


@@ 29,7 29,8 @@ impl ChatHistory {
                } else {
                    0
                }
            })));
            },
        )));
        listbox.get_style_context().add_class("history-listbox");
        ChatHistory {
            tel,

M src/widgets/chat_list.rs => src/widgets/chat_list.rs +8 -1
@@ 1,3 1,4 @@
use std::time::SystemTime;
use crate::util::parse_time;
use crate::*;
use gdk_pixbuf::*;


@@ 83,7 84,13 @@ fn build_chat_ui(chat: &Chat) -> ListBoxRow {
    let last_label = Label::new(Some(&chat.last.trim()));
    add_class(&last_label, "chat-last");
    add_class(&last_label, "small-text");
    let when_label = Label::new(Some(&parse_time(chat.timestamp as u128)));
    let now = SystemTime::now();
    let when_label = Label::new(Some(&parse_time(
        now.duration_since(SystemTime::UNIX_EPOCH)
            .expect("Couldn't get time since unix epoch")
            .as_millis()
            - chat.timestamp as u128,
    )));
    /*let avatar = Image::new();
        if let Some(buf) = self.avatars.get(&chat.tel) {
            avatar.set_from_pixbuf(Some(&buf));

M src/widgets/message.rs => src/widgets/message.rs +27 -4
@@ 4,6 4,7 @@ use core::fmt::Debug;
use regex::Regex;
use std::fmt;
use std::time::*;
use std::fs;
lazy_static! {
    static ref LINK_REG: Regex = Regex::new(
        r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+"


@@ 28,7 29,7 @@ impl MessageUi {
            .selectable(false)
            .activatable(false)
            .build();
            row.set_property("name", &msg.sent_at.to_string()).unwrap();
        row.set_property("name", &msg.sent_at.to_string()).unwrap();
        row.add(&ui);
        row.show_all();
        MessageUi { row, ui }


@@ 51,12 52,34 @@ impl MessageUi {
            for attachment in attachments.into_iter() {
                match attachment.c_type {
                    AttachmentType::Image => {
                        let image = Image::from_pixbuf(None);       
                        let image = Image::from_pixbuf(None);
                        msg_box.add(&image);
                        let pixbuf = gdk_pixbuf::Pixbuf::from_file_at_scale(&attachment.file, 300, 200, true).expect("Couldn't construct pixbuf from file");
                        let pixbuf = gdk_pixbuf::Pixbuf::from_file_at_scale(
                            &attachment.file,
                            300,
                            200,
                            true,
                        )
                        .expect("Couldn't construct pixbuf from file");
                        image.set_from_pixbuf(Some(&pixbuf));
                    }
                    _ => {}
                    _ => {
                        let but = Button::with_label(&format!("Save {}", attachment.file_name));
                        but.connect_clicked(clone!(@strong attachment => move |but| {
                            let window = but.get_toplevel().expect("Couldn't get save button's toplevel widget").downcast::<Window>().expect("Save button's toplevel widget wasn't a window");
                            let fcdialog = FileChooserDialog::new(Some("Save attachment"),Some(&window), FileChooserAction::Save);
                            fcdialog.set_current_name(attachment.file_name.as_str());
                             fcdialog.add_buttons(&[("Save As", gtk::ResponseType::Ok),("Cancel", gtk::ResponseType::Cancel)]);
                            fcdialog.connect_response(clone!(@strong attachment => move |file_chooser, response| {
                                if response == gtk::ResponseType::Ok {
                                    fs::copy(attachment.file.clone(), file_chooser.get_filename().expect("Couldn't get filename")).expect("Couldn't copy file");
                                }
                                file_chooser.close();
                            }));
                            fcdialog.show_all();
                        }));
                        msg_box.add(&but);
                    }
                }
            }
        }