Commit 0dd81820 authored by Daniel García Moreno's avatar Daniel García Moreno

gtk: Split appop into several modules

parent 353fe135
Pipeline #10466 passed with stage
in 13 minutes and 42 seconds
extern crate gtk;
use self::gtk::prelude::*;
use appop::AppOp;
use globals;
impl AppOp {
pub fn about_dialog(&self) {
let window: gtk::ApplicationWindow = self.ui.builder
.get_object("main_window")
.expect("Can't find main_window in ui file.");
let dialog = gtk::AboutDialog::new();
dialog.set_logo_icon_name(globals::APP_ID);
dialog.set_comments("A Matrix.org client for GNOME");
dialog.set_copyright("© 2017–2018 Daniel García Moreno, et al.");
dialog.set_license_type(gtk::License::Gpl30);
dialog.set_modal(true);
dialog.set_version(env!("CARGO_PKG_VERSION"));
dialog.set_program_name("Fractal");
dialog.set_website("https://wiki.gnome.org/Fractal");
dialog.set_website_label("Learn more about Fractal");
dialog.set_transient_for(&window);
dialog.set_artists(&[
"Tobias Bernard",
]);
dialog.set_authors(&[
"Daniel García Moreno",
"Jordan Petridis",
"Alexandre Franke",
"Saurav Sachidanand",
"Julian Sparber",
]);
dialog.add_credit_section("Name by", &["Regina Bíró"]);
dialog.show();
}
}
extern crate gdk;
extern crate gdk_pixbuf;
extern crate gtk;
use self::gtk::prelude::*;
use appop::AppOp;
use backend::BKCommand;
use self::gdk_pixbuf::Pixbuf;
use self::gdk_pixbuf::PixbufExt;
use util::get_pixbuf_data;
impl AppOp {
pub fn paste(&self) {
if let Some(display) = gdk::Display::get_default() {
if let Some(clipboard) = gtk::Clipboard::get_default(&display) {
if clipboard.wait_is_image_available() {
if let Some(pixb) = clipboard.wait_for_image() {
self.draw_image_paste_dialog(&pixb);
// removing text from clipboard
clipboard.set_text("");
clipboard.set_image(&pixb);
}
} else {
// TODO: manage code pasting
}
}
}
}
fn draw_image_paste_dialog(&self, pixb: &Pixbuf) {
let w = pixb.get_width();
let h = pixb.get_height();
let scaled;
if w > 600 {
scaled = pixb.scale_simple(600, h*600/w, gdk_pixbuf::InterpType::Bilinear);
} else {
scaled = Some(pixb.clone());
}
if let Some(pb) = scaled {
let window: gtk::ApplicationWindow = self.ui.builder
.get_object("main_window")
.expect("Can't find main_window in ui file.");
let img = gtk::Image::new();
let dialog = gtk::Dialog::new_with_buttons(
Some("Image from Clipboard"),
Some(&window),
gtk::DialogFlags::MODAL|
gtk::DialogFlags::USE_HEADER_BAR|
gtk::DialogFlags::DESTROY_WITH_PARENT,
&[]);
img.set_from_pixbuf(&pb);
img.show();
dialog.get_content_area().add(&img);
dialog.present();
if let Some(hbar) = dialog.get_header_bar() {
let bar = hbar.downcast::<gtk::HeaderBar>().unwrap();
let closebtn = gtk::Button::new_with_label("Cancel");
let okbtn = gtk::Button::new_with_label("Send");
okbtn.get_style_context().unwrap().add_class("suggested-action");
bar.set_show_close_button(false);
bar.pack_start(&closebtn);
bar.pack_end(&okbtn);
bar.show_all();
closebtn.connect_clicked(clone!(dialog => move |_| {
dialog.destroy();
}));
let room = self.active_room.clone().unwrap_or_default();
let bk = self.backend.clone();
okbtn.connect_clicked(clone!(pixb, dialog => move |_| {
if let Ok(data) = get_pixbuf_data(&pixb) {
bk.send(BKCommand::AttachImage(room.clone(), data)).unwrap();
}
dialog.destroy();
}));
okbtn.grab_focus();
}
}
}
}
extern crate gtk;
use self::gtk::prelude::*;
use appop::AppOp;
use widgets;
use backend::BKCommand;
use types::Protocol;
use types::Room;
impl AppOp {
pub fn init_protocols(&self) {
self.backend.send(BKCommand::DirectoryProtocols).unwrap();
}
pub fn set_protocols(&self, protocols: Vec<Protocol>) {
let combo = self.ui.builder
.get_object::<gtk::ListStore>("protocol_model")
.expect("Can't find protocol_model in ui file.");
combo.clear();
for p in protocols {
combo.insert_with_values(None, &[0, 1], &[&p.desc, &p.id]);
}
self.ui.builder
.get_object::<gtk::ComboBox>("directory_combo")
.expect("Can't find directory_combo in ui file.")
.set_active(0);
}
pub fn search_rooms(&self, more: bool) {
let combo_store = self.ui.builder
.get_object::<gtk::ListStore>("protocol_model")
.expect("Can't find protocol_model in ui file.");
let combo = self.ui.builder
.get_object::<gtk::ComboBox>("directory_combo")
.expect("Can't find directory_combo in ui file.");
let active = combo.get_active();
let protocol: String = match combo_store.iter_nth_child(None, active) {
Some(it) => {
let v = combo_store.get_value(&it, 1);
v.get().unwrap()
}
None => String::from(""),
};
let q = self.ui.builder
.get_object::<gtk::Entry>("directory_search_entry")
.expect("Can't find directory_search_entry in ui file.");
let btn = self.ui.builder
.get_object::<gtk::Button>("directory_search_button")
.expect("Can't find directory_search_button in ui file.");
btn.set_label("Searching...");
btn.set_sensitive(false);
if !more {
let directory = self.ui.builder
.get_object::<gtk::ListBox>("directory_room_list")
.expect("Can't find directory_room_list in ui file.");
for ch in directory.get_children() {
directory.remove(&ch);
}
}
self.backend
.send(BKCommand::DirectorySearch(q.get_text().unwrap(), protocol, more))
.unwrap();
}
pub fn load_more_rooms(&self) {
self.search_rooms(true);
}
pub fn set_directory_room(&self, room: Room) {
let directory = self.ui.builder
.get_object::<gtk::ListBox>("directory_room_list")
.expect("Can't find directory_room_list in ui file.");
let rb = widgets::RoomBox::new(&room, &self);
let room_widget = rb.widget();
directory.add(&room_widget);
self.enable_directory_search();
}
pub fn enable_directory_search(&self) {
let btn = self.ui.builder
.get_object::<gtk::Button>("directory_search_button")
.expect("Can't find directory_search_button in ui file.");
btn.set_label("Search");
btn.set_sensitive(true);
}
}
extern crate gtk;
use self::gtk::prelude::*;
use appop::AppOp;
use appop::member::SearchType;
use app::InternalCommand;
use backend::BKCommand;
use widgets;
use types::Member;
use types::Room;
impl AppOp {
pub fn add_to_invite(&mut self, u: Member) {
let listboxid = match self.search_type {
SearchType::Invite => "to_invite",
SearchType::DirectChat => "to_chat",
};
let to_invite = self.ui.builder
.get_object::<gtk::ListBox>(listboxid)
.expect("Can't find to_invite in ui file.");
if self.invite_list.contains(&u) {
return;
}
if let SearchType::DirectChat = self.search_type {
self.invite_list = vec![];
for ch in to_invite.get_children().iter() {
to_invite.remove(ch);
}
}
self.invite_list.push(u.clone());
self.ui.builder
.get_object::<gtk::Button>("direct_chat_button")
.map(|btn| btn.set_sensitive(true));
self.ui.builder
.get_object::<gtk::Button>("invite_button")
.map(|btn| btn.set_sensitive(true));
let w;
{
let mb = widgets::MemberBox::new(&u, &self);
w = mb.widget(true);
}
let mbox;
mbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
let btn = gtk::Button::new();
let img = gtk::Image::new_from_icon_name("window-close-symbolic", 2);
btn.get_style_context().unwrap().add_class("circular");
btn.set_image(&img);
mbox.pack_start(&w, true, true, 0);
mbox.pack_start(&btn, false, false, 0);
mbox.show_all();
let tx = self.internal.clone();
let uid = u.uid.clone();
btn.connect_clicked(move |_| {
tx.send(InternalCommand::RmInvite(uid.clone())).unwrap();
});
let size = (self.invite_list.len() - 1) as i32;
to_invite.insert(&mbox, size);
}
pub fn rm_from_invite(&mut self, uid: String) {
let invid;
let dialogid;
match self.search_type {
SearchType::Invite => {
invid = "to_invite";
dialogid = "invite_user_dialog";
}
SearchType::DirectChat => {
invid = "to_chat";
dialogid = "direct_chat_dialog";
}
};
let to_invite = self.ui.builder
.get_object::<gtk::ListBox>(invid)
.expect("Can't find to_invite in ui file.");
let dialog = self.ui.builder
.get_object::<gtk::Dialog>(dialogid)
.expect("Can't find invite_user_dialog in ui file.");
let idx = self.invite_list.iter().position(|x| x.uid == uid);
if let Some(i) = idx {
self.invite_list.remove(i);
if let Some(r) = to_invite.get_row_at_index(i as i32) {
to_invite.remove(&r);
}
}
if self.invite_list.is_empty() {
self.ui.builder
.get_object::<gtk::Button>("direct_chat_button")
.map(|btn| btn.set_sensitive(false));
self.ui.builder
.get_object::<gtk::Button>("invite_button")
.map(|btn| btn.set_sensitive(false));
}
dialog.resize(300, 200);
}
pub fn show_invite_user_dialog(&mut self) {
let dialog = self.ui.builder
.get_object::<gtk::Dialog>("invite_user_dialog")
.expect("Can't find invite_user_dialog in ui file.");
let scroll = self.ui.builder
.get_object::<gtk::Widget>("user_search_scroll")
.expect("Can't find user_search_scroll in ui file.");
let title = self.ui.builder
.get_object::<gtk::Label>("invite_title")
.expect("Can't find invite_title in ui file.");
self.search_type = SearchType::Invite;
if let Some(aroom) = self.active_room.clone() {
if let Some(r) = self.rooms.get(&aroom) {
if let &Some(ref name) = &r.name {
title.set_text(&format!("Invite to {}", name));
} else {
title.set_text("Invite");
}
}
}
dialog.present();
scroll.hide();
}
pub fn invite(&mut self) {
if let &Some(ref r) = &self.active_room {
for user in &self.invite_list {
self.backend.send(BKCommand::Invite(r.clone(), user.uid.clone())).unwrap();
}
}
self.close_invite_dialog();
}
pub fn close_invite_dialog(&mut self) {
let listbox = self.ui.builder
.get_object::<gtk::ListBox>("user_search_box")
.expect("Can't find user_search_box in ui file.");
let scroll = self.ui.builder
.get_object::<gtk::Widget>("user_search_scroll")
.expect("Can't find user_search_scroll in ui file.");
let to_invite = self.ui.builder
.get_object::<gtk::ListBox>("to_invite")
.expect("Can't find to_invite in ui file.");
let entry = self.ui.builder
.get_object::<gtk::Entry>("invite_entry")
.expect("Can't find invite_entry in ui file.");
let dialog = self.ui.builder
.get_object::<gtk::Dialog>("invite_user_dialog")
.expect("Can't find invite_user_dialog in ui file.");
self.invite_list = vec![];
for ch in to_invite.get_children().iter() {
to_invite.remove(ch);
}
for ch in listbox.get_children().iter() {
listbox.remove(ch);
}
scroll.hide();
entry.set_text("");
dialog.hide();
dialog.resize(300, 200);
}
pub fn remove_inv(&mut self, roomid: String) {
self.rooms.remove(&roomid);
self.roomlist.remove_room(roomid);
}
pub fn accept_inv(&mut self, accept: bool) {
if let Some(ref rid) = self.invitation_roomid {
match accept {
true => self.backend.send(BKCommand::AcceptInv(rid.clone())).unwrap(),
false => self.backend.send(BKCommand::RejectInv(rid.clone())).unwrap(),
}
self.internal.send(InternalCommand::RemoveInv(rid.clone())).unwrap();
}
self.invitation_roomid = None;
}
pub fn show_inv_dialog(&mut self, r: &Room) {
let dialog = self.ui.builder
.get_object::<gtk::MessageDialog>("invite_dialog")
.expect("Can't find invite_dialog in ui file.");
let room_name = r.name.clone().unwrap_or_default();
let title = format!("Join {}?", room_name);
let secondary;
if let Some(ref sender) = r.inv_sender {
let sender_name = sender.get_alias();
secondary = format!("You've been invited to join to <b>{}</b> room by <b>{}</b>",
room_name, sender_name);
} else {
secondary = format!("You've been invited to join to <b>{}</b>", room_name);
}
dialog.set_property_text(Some(&title));
dialog.set_property_secondary_use_markup(true);
dialog.set_property_secondary_text(Some(&secondary));
self.invitation_roomid = Some(r.id.clone());
dialog.present();
}
}
extern crate gtk;
use self::gtk::prelude::*;
use appop::AppOp;
use appop::state::AppState;
use cache;
use backend::Backend;
use backend::BKCommand;
use backend::BKResponse;
use std::sync::mpsc::channel;
use std::sync::mpsc::{Sender, Receiver};
use app::backend_loop;
use passwd::PasswordStorage;
impl AppOp {
pub fn bk_login(&mut self, uid: String, token: String) {
self.logged_in = true;
self.clean_login();
if let Err(_) = self.store_token(uid.clone(), token) {
println!("Error: Can't store the token using libsecret");
}
self.set_state(AppState::Chat);
self.set_uid(Some(uid.clone()));
/* Do we need to set the username to uid
self.set_username(Some(uid));*/
self.get_username();
// initial sync, we're shoing some feedback to the user
self.initial_sync(true);
self.sync();
self.init_protocols();
}
pub fn bk_logout(&mut self) {
self.set_rooms(&vec![], None);
if let Err(_) = cache::destroy() {
println!("Error removing cache file");
}
self.logged_in = false;
self.syncing = false;
self.set_state(AppState::Login);
self.set_uid(None);
self.set_username(None);
self.set_avatar(None);
// stoping the backend and starting again, we don't want to receive more messages from
// backend
self.backend.send(BKCommand::ShutDown).unwrap();
let (tx, rx): (Sender<BKResponse>, Receiver<BKResponse>) = channel();
let bk = Backend::new(tx);
self.backend = bk.run();
backend_loop(rx);
}
pub fn clean_login(&self) {
let user_entry: gtk::Entry = self.ui.builder
.get_object("login_username")
.expect("Can't find login_username in ui file.");
let pass_entry: gtk::Entry = self.ui.builder
.get_object("login_password")
.expect("Can't find login_password in ui file.");
let server_entry: gtk::Entry = self.ui.builder
.get_object("login_server")
.expect("Can't find login_server in ui file.");
let idp_entry: gtk::Entry = self.ui.builder
.get_object("login_idp")
.expect("Can't find login_idp in ui file.");
user_entry.set_text("");
pass_entry.set_text("");
server_entry.set_text("https://matrix.org");
idp_entry.set_text("https://vector.im");
}
pub fn login(&mut self) {
let user_entry: gtk::Entry = self.ui.builder
.get_object("login_username")
.expect("Can't find login_username in ui file.");
let pass_entry: gtk::Entry = self.ui.builder
.get_object("login_password")
.expect("Can't find login_password in ui file.");
let server_entry: gtk::Entry = self.ui.builder
.get_object("login_server")
.expect("Can't find login_server in ui file.");
let login_error: gtk::Label = self.ui.builder
.get_object("login_error_msg")
.expect("Can't find login_error_msg in ui file.");
let username = user_entry.get_text();
let password = pass_entry.get_text();
if username.clone().unwrap_or_default().is_empty() ||
password.clone().unwrap_or_default().is_empty() {
login_error.set_text("Invalid username or password");
login_error.show();
return;
} else {
login_error.set_text("Unknown Error");
login_error.hide();
}
self.set_state(AppState::Loading);
self.since = None;
self.connect(username, password, server_entry.get_text());
}
pub fn set_login_pass(&self, username: &str, password: &str, server: &str) {
let user_entry: gtk::Entry = self.ui.builder
.get_object("login_username")
.expect("Can't find login_username in ui file.");
let pass_entry: gtk::Entry = self.ui.builder
.get_object("login_password")
.expect("Can't find login_password in ui file.");
let server_entry: gtk::Entry = self.ui.builder
.get_object("login_server")
.expect("Can't find login_server in ui file.");
user_entry.set_text(username);
pass_entry.set_text(password);
server_entry.set_text(server);
}
#[allow(dead_code)]
pub fn register(&mut self) {
let user_entry: gtk::Entry = self.ui.builder
.get_object("register_username")
.expect("Can't find register_username in ui file.");
let pass_entry: gtk::Entry = self.ui.builder
.get_object("register_password")
.expect("Can't find register_password in ui file.");
let pass_conf: gtk::Entry = self.ui.builder
.get_object("register_password_confirm")
.expect("Can't find register_password_confirm in ui file.");
let server_entry: gtk::Entry = self.ui.builder
.get_object("register_server")
.expect("Can't find register_server in ui file.");
let username = match user_entry.get_text() {
Some(s) => s,
None => String::from(""),
};
let password = match pass_entry.get_text() {
Some(s) => s,
None => String::from(""),
};
let passconf = match pass_conf.get_text() {
Some(s) => s,
None => String::from(""),
};
if password != passconf {
self.show_error("Passwords didn't match, try again".to_string());
return;
}
self.server_url = match server_entry.get_text() {
Some(s) => s,
None => String::from("https://matrix.org"),
};
//self.store_pass(username.clone(), password.clone(), server_url.clone())
// .unwrap_or_else(|_| {
// // TODO: show an error
// println!("Error: Can't store the password using libsecret");
// });
let uname = username.clone();
let pass = password.clone();
let ser = self.server_url.clone();
self.backend.send(BKCommand::Register(uname, pass, ser)).unwrap();
}
pub fn connect(&mut self, username: Option<String>, password: Option<String>, server: Option<String>) -> Option<()> {
self.server_url = match server {
Some(s) => s,
None => String::from("https://matrix.org"),
};
self.store_pass(username.clone()?, password.clone()?, self.server_url.clone())
.unwrap_or_else(|_| {
// TODO: show an error
println!("Error: Can't store the password using libsecret");
});
let uname = username?;
let pass = password?;
let ser = self.server_url.clone();
self.backend.send(BKCommand::Login(uname, pass, ser)).unwrap();
Some(())
}
pub fn set_token(&mut self, token: Option<String>, uid: Option<String>, server: Option<String>) -> Option<()> {
self.server_url = match server {
Some(s) => s,
None => String::from("https://matrix.org"),
};
let ser = self.server_url.clone();
self.backend.send(BKCommand::SetToken(token?, uid?, ser)).unwrap();
Some(())
}
#[allow(dead_code)]
pub fn connect_guest(&mut self, server: Option<String>) {
self.server_url = match server {
Some(s) => s,
None => String::from("https://matrix.org"),
};
self.backend.send(BKCommand::Guest(self.server_url.clone())).unwrap();
}
pub fn disconnect(&self) {
self.backend.send(BKCommand::ShutDown).unwrap();
}
pub fn logout(&mut self) {
let _ = self.delete_pass("fractal");
self.backend.send(BKCommand::Logout).unwrap();
self.bk_logout();
}
}
extern crate gtk;
use self::gtk::prelude::*;
use std::collections::HashMap;
use appop::AppOp;
use app::InternalCommand;
use glib;
use widgets;
use backend::BKCommand;
use types::Member;
use types::Event;
#[derive(Debug, Clone)]
pub enum SearchType {
Invite,
DirectChat,
}
impl AppOp {