Commit 353fe135 authored by Daniel García Moreno's avatar Daniel García Moreno

gtk: split App in several rs modules

parent eed33282
use gio;
use gio::SimpleActionExt;
use gio::ActionMapExt;
use appop::AppState;
use app::App;
impl App {
pub fn create_actions(&self) {
let settings = gio::SimpleAction::new("settings", None);
let dir = gio::SimpleAction::new("directory", None);
let chat = gio::SimpleAction::new("start_chat", None);
let newr = gio::SimpleAction::new("new_room", None);
let joinr = gio::SimpleAction::new("join_room", None);
let logout = gio::SimpleAction::new("logout", None);
let room = gio::SimpleAction::new("room_details", None);
let inv = gio::SimpleAction::new("room_invite", None);
let search = gio::SimpleAction::new("search", None);
let leave = gio::SimpleAction::new("leave_room", None);
let quit = gio::SimpleAction::new("quit", None);
let shortcuts = gio::SimpleAction::new("shortcuts", None);
let about = gio::SimpleAction::new("about", None);
let op = &self.op;
op.lock().unwrap().gtk_app.add_action(&settings);
op.lock().unwrap().gtk_app.add_action(&dir);
op.lock().unwrap().gtk_app.add_action(&chat);
op.lock().unwrap().gtk_app.add_action(&newr);
op.lock().unwrap().gtk_app.add_action(&joinr);
op.lock().unwrap().gtk_app.add_action(&logout);
op.lock().unwrap().gtk_app.add_action(&room);
op.lock().unwrap().gtk_app.add_action(&inv);
op.lock().unwrap().gtk_app.add_action(&search);
op.lock().unwrap().gtk_app.add_action(&leave);
op.lock().unwrap().gtk_app.add_action(&quit);
op.lock().unwrap().gtk_app.add_action(&shortcuts);
op.lock().unwrap().gtk_app.add_action(&about);
quit.connect_activate(clone!(op => move |_, _| op.lock().unwrap().quit() ));
about.connect_activate(clone!(op => move |_, _| op.lock().unwrap().about_dialog() ));
settings.connect_activate(move |_, _| { println!("SETTINGS"); });
settings.set_enabled(false);
dir.connect_activate(clone!(op => move |_, _| op.lock().unwrap().set_state(AppState::Directory) ));
logout.connect_activate(clone!(op => move |_, _| op.lock().unwrap().logout() ));
room.connect_activate(clone!(op => move |_, _| op.lock().unwrap().show_room_dialog() ));
inv.connect_activate(clone!(op => move |_, _| op.lock().unwrap().show_invite_user_dialog() ));
chat.connect_activate(clone!(op => move |_, _| op.lock().unwrap().show_direct_chat_dialog() ));
search.connect_activate(clone!(op => move |_, _| op.lock().unwrap().toggle_search() ));
leave.connect_activate(clone!(op => move |_, _| op.lock().unwrap().leave_active_room() ));
newr.connect_activate(clone!(op => move |_, _| op.lock().unwrap().new_room_dialog() ));
joinr.connect_activate(clone!(op => move |_, _| op.lock().unwrap().join_to_room_dialog() ));
}
}
use app::App;
use appop::MsgPos;
use appop::LastViewed;
use appop::RoomPanel;
use std::thread;
use std::sync::mpsc::Receiver;
use glib;
use types::Message;
use types::Room;
use types::Member;
#[derive(Debug)]
pub enum InternalCommand {
AddRoomMessage(Message, MsgPos, Option<Message>, bool, LastViewed),
SetPanel(RoomPanel),
NotifyClicked(Message),
SelectRoom(Room),
LoadMoreNormal,
RemoveInv(String),
ToInvite(Member),
RmInvite(String),
}
pub fn appop_loop(rx: Receiver<InternalCommand>) {
thread::spawn(move || {
loop {
let recv = rx.recv();
match recv {
Ok(InternalCommand::AddRoomMessage(msg, pos, prev, force_full, last)) => {
APPOP!(add_room_message, (msg, pos, prev, force_full, last));
}
Ok(InternalCommand::ToInvite(member)) => {
APPOP!(add_to_invite, (member));
}
Ok(InternalCommand::RmInvite(uid)) => {
APPOP!(rm_from_invite, (uid));
}
Ok(InternalCommand::SetPanel(st)) => {
APPOP!(room_panel, (st));
}
Ok(InternalCommand::NotifyClicked(msg)) => {
APPOP!(notification_cliked, (msg));
}
Ok(InternalCommand::SelectRoom(r)) => {
let id = r.id;
APPOP!(set_active_room_by_id, (id));
}
Ok(InternalCommand::LoadMoreNormal) => {
APPOP!(load_more_normal);
}
Ok(InternalCommand::RemoveInv(rid)) => {
APPOP!(remove_inv, (rid));
}
Err(_) => {
break;
}
};
}
});
}
use app::App;
use appop::RoomPanel;
use appop::AppState;
use std::thread;
use std::sync::mpsc::Receiver;
use std::process::Command;
use glib;
use backend::BKResponse;
use std::sync::mpsc::RecvError;
pub fn backend_loop(rx: Receiver<BKResponse>) {
thread::spawn(move || {
let mut shutting_down = false;
loop {
let recv = rx.recv();
if let Err(RecvError) = recv {
// stopping this backend loop thread
break;
}
if shutting_down {
// ignore this event, we're shutting down this thread
continue;
}
match recv {
Err(RecvError) => { break; }
Ok(BKResponse::ShutDown) => { shutting_down = true; }
Ok(BKResponse::Token(uid, tk)) => {
APPOP!(bk_login, (uid, tk));
// after login
APPOP!(sync);
}
Ok(BKResponse::Logout) => {
APPOP!(bk_logout);
}
Ok(BKResponse::Name(username)) => {
let u = Some(username);
APPOP!(set_username, (u));
}
Ok(BKResponse::Avatar(path)) => {
let av = Some(path);
APPOP!(set_avatar, (av));
}
Ok(BKResponse::Sync(since)) => {
println!("SYNC");
let s = Some(since);
APPOP!(synced, (s));
}
Ok(BKResponse::Rooms(rooms, default)) => {
APPOP!(update_rooms, (rooms, default));
}
Ok(BKResponse::NewRooms(rooms)) => {
APPOP!(new_rooms, (rooms));
}
Ok(BKResponse::RoomDetail(room, key, value)) => {
let v = Some(value);
APPOP!(set_room_detail, (room, key, v));
}
Ok(BKResponse::RoomAvatar(room, avatar)) => {
let a = Some(avatar);
APPOP!(set_room_avatar, (room, a));
}
Ok(BKResponse::RoomMembers(members)) => {
APPOP!(set_room_members, (members));
}
Ok(BKResponse::RoomMessages(msgs)) => {
let init = false;
APPOP!(show_room_messages, (msgs, init));
}
Ok(BKResponse::RoomMessagesInit(msgs)) => {
let init = true;
APPOP!(show_room_messages, (msgs, init));
}
Ok(BKResponse::RoomMessagesTo(msgs)) => {
APPOP!(show_room_messages_top, (msgs));
}
Ok(BKResponse::SendMsg) => {
APPOP!(sync);
}
Ok(BKResponse::DirectoryProtocols(protocols)) => {
APPOP!(set_protocols, (protocols));
}
Ok(BKResponse::DirectorySearch(rooms)) => {
if rooms.len() == 0 {
let error = "No rooms found".to_string();
APPOP!(show_error, (error));
APPOP!(enable_directory_search);
}
for room in rooms {
APPOP!(set_directory_room, (room));
}
}
Ok(BKResponse::JoinRoom) => {
APPOP!(reload_rooms);
}
Ok(BKResponse::LeaveRoom) => { }
Ok(BKResponse::SetRoomName) => { }
Ok(BKResponse::SetRoomTopic) => { }
Ok(BKResponse::SetRoomAvatar) => { }
Ok(BKResponse::MarkedAsRead(r, _)) => {
APPOP!(clear_room_notifications, (r));
}
Ok(BKResponse::RoomNotifications(r, n, h)) => {
APPOP!(set_room_notifications, (r, n, h));
}
Ok(BKResponse::RoomName(roomid, name)) => {
let n = Some(name);
APPOP!(room_name_change, (roomid, n));
}
Ok(BKResponse::RoomTopic(roomid, topic)) => {
let t = Some(topic);
APPOP!(room_topic_change, (roomid, t));
}
Ok(BKResponse::NewRoomAvatar(roomid)) => {
APPOP!(new_room_avatar, (roomid));
}
Ok(BKResponse::RoomMemberEvent(ev)) => {
APPOP!(room_member_event, (ev));
}
Ok(BKResponse::Media(fname)) => {
Command::new("xdg-open")
.arg(&fname)
.spawn()
.expect("failed to execute process");
}
Ok(BKResponse::AttachedFile(msg)) => {
APPOP!(add_tmp_room_message, (msg));
}
Ok(BKResponse::SearchEnd) => {
APPOP!(search_end);
}
Ok(BKResponse::NewRoom(r, internal_id)) => {
let id = Some(internal_id);
APPOP!(new_room, (r, id));
}
Ok(BKResponse::AddedToFav(r, tofav)) => {
APPOP!(added_to_fav, (r, tofav));
}
Ok(BKResponse::UserSearch(users)) => {
APPOP!(user_search_finished, (users));
}
// errors
Ok(BKResponse::NewRoomError(err, internal_id)) => {
println!("ERROR: {:?}", err);
let error = "Can't create the room, try again".to_string();
let panel = RoomPanel::NoRoom;
APPOP!(remove_room, (internal_id));
APPOP!(show_error, (error));
APPOP!(room_panel, (panel));
},
Ok(BKResponse::JoinRoomError(err)) => {
println!("ERROR: {:?}", err);
let error = format!("Can't join to the room, try again.");
let panel = RoomPanel::NoRoom;
APPOP!(show_error, (error));
APPOP!(room_panel, (panel));
},
Ok(BKResponse::LoginError(_)) => {
let error = "Can't login, try again".to_string();
let st = AppState::Login;
APPOP!(show_error, (error));
APPOP!(set_state, (st));
},
Ok(BKResponse::SendMsgError(_)) => {
let error = "Error sending message".to_string();
APPOP!(show_error, (error));
}
Ok(BKResponse::DirectoryError(_)) => {
let error = "Error searching for rooms".to_string();
APPOP!(show_error, (error));
APPOP!(enable_directory_search);
}
Ok(BKResponse::SyncError(err)) => {
println!("SYNC Error: {:?}", err);
APPOP!(sync_error);
}
Ok(err) => {
println!("Query error: {:?}", err);
}
};
}
});
}
extern crate gtk;
use self::gtk::prelude::*;
use app::App;
impl App {
pub fn connect_attach(&self) {
let attach_button: gtk::Button = self.ui.builder
.get_object("attach_button")
.expect("Couldn't find attach_button in ui file.");
let op = self.op.clone();
attach_button.connect_clicked(move |_| {
op.lock().unwrap().attach_file();
});
}
}
extern crate gtk;
use widgets;
use app::App;
impl App {
pub fn connect_autocomplete(&self) {
let msg_entry: gtk::Entry = self.ui.builder
.get_object("msg_entry")
.expect("Couldn't find msg_entry in ui file.");
let popover = self.ui.builder
.get_object::<gtk::Popover>("autocomplete_popover")
.expect("Can't find autocomplete_popover in ui file.");
let listbox = self.ui.builder
.get_object::<gtk::ListBox>("autocomplete_listbox")
.expect("Can't find autocomplete_listbox in ui file.");
let window: gtk::Window = self.ui.builder
.get_object("main_window")
.expect("Can't find main_window in ui file.");
let op = self.op.clone();
widgets::Autocomplete::new(op, window, msg_entry, popover, listbox).connect();
}
}
extern crate gtk;
use self::gtk::prelude::*;
use glib;
use std::sync::{Arc, Mutex};
use app::App;
impl App {
pub fn connect_direct_chat(&self) {
let op = &self.op;
let cancel = self.ui.builder
.get_object::<gtk::Button>("cancel_direct_chat")
.expect("Can't find cancel_direct_chat in ui file.");
let invite = self.ui.builder
.get_object::<gtk::Button>("direct_chat_button")
.expect("Can't find direct_chat_button in ui file.");
let entry = self.ui.builder
.get_object::<gtk::Entry>("to_chat_entry")
.expect("Can't find to_chat_entry in ui file.");
let dialog = self.ui.builder
.get_object::<gtk::Dialog>("direct_chat_dialog")
.expect("Can't find direct_chat_dialog in ui file.");
// this is used to cancel the timeout and not search for every key input. We'll wait 500ms
// without key release event to launch the search
let source_id: Arc<Mutex<Option<glib::source::SourceId>>> = Arc::new(Mutex::new(None));
entry.connect_key_release_event(clone!(op => move |entry, _| {
{
let mut id = source_id.lock().unwrap();
if let Some(sid) = id.take() {
glib::source::source_remove(sid);
}
}
let sid = gtk::timeout_add(500, clone!(op, entry, source_id => move || {
op.lock().unwrap().search_invite_user(entry.get_text());
*(source_id.lock().unwrap()) = None;
gtk::Continue(false)
}));
*(source_id.lock().unwrap()) = Some(sid);
glib::signal::Inhibit(false)
}));
dialog.connect_delete_event(clone!(op => move |_, _| {
op.lock().unwrap().close_direct_chat_dialog();
glib::signal::Inhibit(true)
}));
cancel.connect_clicked(clone!(op => move |_| {
op.lock().unwrap().close_direct_chat_dialog();
}));
invite.set_sensitive(false);
invite.connect_clicked(clone!(op => move |_| {
op.lock().unwrap().start_chat();
}));
}
}
extern crate gtk;
use self::gtk::prelude::*;
use app::App;
impl App {
pub fn connect_directory(&self) {
let btn = self.ui.builder
.get_object::<gtk::Button>("directory_search_button")
.expect("Can't find directory_search_button in ui file.");
let q = self.ui.builder
.get_object::<gtk::Entry>("directory_search_entry")
.expect("Can't find directory_search_entry in ui file.");
let scroll = self.ui.builder
.get_object::<gtk::ScrolledWindow>("directory_scroll")
.expect("Can't find directory_scroll in ui file.");
let mut op = self.op.clone();
btn.connect_clicked(move |_| { op.lock().unwrap().search_rooms(false); });
op = self.op.clone();
scroll.connect_edge_reached(move |_, dir| if dir == gtk::PositionType::Bottom {
op.lock().unwrap().load_more_rooms();
});
op = self.op.clone();
q.connect_activate(move |_| { op.lock().unwrap().search_rooms(false); });
}
}
extern crate gtk;
use self::gtk::prelude::*;
use appop::AppState;
use app::App;
impl App {
pub fn connect_headerbars(&self) {
let op = self.op.clone();
let btn = self.ui.builder
.get_object::<gtk::Button>("back_button")
.expect("Can't find back_button in ui file.");
btn.connect_clicked(move |_| {
op.lock().unwrap().set_state(AppState::Chat);
});
}
}
extern crate gtk;
use self::gtk::prelude::*;
use std::sync::{Arc, Mutex};
use glib;
use app::App;
impl App {
pub fn connect_invite_dialog(&self) {
let op = self.op.clone();
let dialog = self.ui.builder
.get_object::<gtk::MessageDialog>("invite_dialog")
.expect("Can't find invite_dialog in ui file.");
let accept = self.ui.builder
.get_object::<gtk::Button>("invite_accept")
.expect("Can't find invite_accept in ui file.");
let reject = self.ui.builder
.get_object::<gtk::Button>("invite_reject")
.expect("Can't find invite_reject in ui file.");
reject.connect_clicked(clone!(dialog, op => move |_| {
op.lock().unwrap().accept_inv(false);
dialog.hide();
}));
dialog.connect_delete_event(clone!(dialog, op => move |_, _| {
op.lock().unwrap().accept_inv(false);
dialog.hide();
glib::signal::Inhibit(true)
}));
accept.connect_clicked(clone!(dialog, op => move |_| {
op.lock().unwrap().accept_inv(true);
dialog.hide();
}));
}
pub fn connect_invite_user(&self) {
let op = &self.op;
let cancel = self.ui.builder
.get_object::<gtk::Button>("cancel_invite")
.expect("Can't find cancel_invite in ui file.");
let invite = self.ui.builder
.get_object::<gtk::Button>("invite_button")
.expect("Can't find invite_button 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.");
// this is used to cancel the timeout and not search for every key input. We'll wait 500ms
// without key release event to launch the search
let source_id: Arc<Mutex<Option<glib::source::SourceId>>> = Arc::new(Mutex::new(None));
entry.connect_key_release_event(clone!(op => move |entry, _| {
{
let mut id = source_id.lock().unwrap();
if let Some(sid) = id.take() {
glib::source::source_remove(sid);
}
}
let sid = gtk::timeout_add(500, clone!(op, entry, source_id => move || {
op.lock().unwrap().search_invite_user(entry.get_text());
*(source_id.lock().unwrap()) = None;
gtk::Continue(false)
}));
*(source_id.lock().unwrap()) = Some(sid);
glib::signal::Inhibit(false)
}));
dialog.connect_delete_event(clone!(op => move |_, _| {
op.lock().unwrap().close_invite_dialog();
glib::signal::Inhibit(true)
}));
cancel.connect_clicked(clone!(op => move |_| {
op.lock().unwrap().close_invite_dialog();
}));
invite.set_sensitive(false);
invite.connect_clicked(clone!(op => move |_| {
op.lock().unwrap().invite();
}));
}
}
extern crate gtk;
use self::gtk::prelude::*;
use glib;
use app::App;
impl App {
pub fn connect_join_room_dialog(&self) {
let dialog = self.ui.builder
.get_object::<gtk::Dialog>("join_room_dialog")
.expect("Can't find join_room_dialog in ui file.");
let cancel = self.ui.builder
.get_object::<gtk::Button>("cancel_join_room")
.expect("Can't find cancel_join_room in ui file.");
let confirm = self.ui.builder
.get_object::<gtk::Button>("join_room_button")
.expect("Can't find join_room_button in ui file.");
let entry = self.ui.builder
.get_object::<gtk::Entry>("join_room_name")
.expect("Can't find join_room_name in ui file.");
cancel.connect_clicked(clone!(entry, dialog => move |_| {
dialog.hide();
entry.set_text("");
}));
dialog.connect_delete_event(clone!(entry, dialog => move |_, _| {
dialog.hide();
entry.set_text("");
glib::signal::Inhibit(true)
}));
let op = self.op.clone();
confirm.connect_clicked(clone!(entry, dialog => move |_| {
dialog.hide();
op.lock().unwrap().join_to_room();
entry.set_text("");
}));
let op = self.op.clone();
entry.connect_activate(clone!(dialog => move |entry| {
dialog.hide();
op.lock().unwrap().join_to_room();
entry.set_text("");
}));
entry.connect_changed(clone!(confirm => move |entry| {
confirm.set_sensitive(entry.get_buffer().get_length() > 0);
}));
}
}
extern crate gtk;
use self::gtk::prelude::*;
use glib;
use app::App;
impl App {
pub fn connect_leave_room_dialog(&self) {
let dialog = self.ui.builder
.get_object::<gtk::Dialog>("leave_room_dialog")
.expect("Can't find leave_room_dialog in ui file.");
let cancel = self.ui.builder
.get_object::<gtk::Button>("leave_room_cancel")
.expect("Can't find leave_room_cancel in ui file.");
let confirm = self.ui.builder
.get_object::<gtk::Button>("leave_room_confirm")
.expect("Can't find leave_room_confirm in ui file.");
cancel.connect_clicked(clone!(dialog => move |_| {
dialog.hide();
}));
dialog.connect_delete_event(clone!(dialog => move |_, _| {
dialog.hide();
glib::signal::Inhibit(true)
}));
let op = self.op.clone();
confirm.connect_clicked(clone!(dialog => move |_| {
dialog.hide();
op.lock().unwrap().really_leave_active_room();
}));
}
}
extern crate gtk;
use self::gtk::prelude::*;
use app::App;
impl App {
pub fn create_load_more_spn(&self) {
let messages = self.ui.builder
.get_object::<gtk::ListBox>("message_list")
.expect("Can't find message_list in ui file.");
let row = gtk::ListBoxRow::new();
row.set_activatable(false);
row.set_selectable(false);
let btn = self.op.lock().unwrap().load_more_spn.clone();
btn.set_halign(gtk::Align::Center);
btn.set_margin_top (12);
btn.set_margin_bottom (12);
btn.show();
row.add(&btn);
row.show();
messages.add(&row);
}
}
extern crate gtk;
use self::gtk::prelude::*;
use app::App;
impl App {
pub fn connect_login_view(&self) {
let advbtn: gtk::Button = self.ui.builder
.get_object("login_advanced_button")
.expect("Couldn't find login_advanced_button in ui file.");