Implemented initial search in room

This commit is contained in:
Daniel García Moreno 2017-10-21 10:56:48 +02:00
parent 999d298f8f
commit d4df1b6ffd
5 changed files with 225 additions and 29 deletions

4
TODO
View file

@ -7,7 +7,11 @@ Fixs:
* Ignore launched threads when changing room...
* Sort rooms by last message or fav?
* Load more should work with search, currently loads the room messages,
but not continues with the search
Functionality:
* Show event messages in message list
* Register
* Room creation

View file

@ -177,7 +177,7 @@
</packing>
</child>
<child>
<object class="GtkButton">
<object class="GtkButton" id="search_button">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
@ -776,6 +776,20 @@ Join a room to start to chat</property>
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="room_dialog_close">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="room_dialog_set">
<property name="label">gtk-apply</property>
@ -793,20 +807,6 @@ Join a room to start to chat</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="room_dialog_close">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@ -965,6 +965,75 @@ Join a room to start to chat</property>
</object>
</child>
</object>
<object class="GtkPopover" id="search_popover">
<property name="can_focus">False</property>
<property name="relative_to">search_button</property>
<property name="position">bottom</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="spacing">3</property>
<child>
<object class="GtkSearchEntry" id="search_input">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStack" id="search_button_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="search">
<property name="label">gtk-find</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="name">normal</property>
<property name="title" translatable="yes">normal</property>
</packing>
</child>
<child>
<object class="GtkSpinner" id="search_spinner">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">searching</property>
<property name="title" translatable="yes">Searching</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkPopover" id="user_menu">
<property name="can_focus">False</property>
<property name="relative_to">user_button</property>

View file

@ -388,17 +388,20 @@ impl AppOp {
self.backend.send(BKCommand::SyncForced).unwrap();
}
pub fn set_active_room(&mut self, room: String, name: String) {
self.active_room = room;
self.room_panel(RoomPanel::Loading);
pub fn remove_messages(&mut self) {
let messages = self.gtk_builder
.get_object::<gtk::ListBox>("message_list")
.expect("Can't find message_list in ui file.");
for ch in messages.get_children().iter().skip(1) {
messages.remove(ch);
}
}
pub fn set_active_room(&mut self, room: String, name: String) {
self.active_room = room;
self.room_panel(RoomPanel::Loading);
self.remove_messages();
self.members.clear();
let members = self.gtk_builder
@ -965,6 +968,24 @@ impl AppOp {
None => {}
}
}
pub fn search(&mut self, term: Option<String>) {
let r = self.active_room.clone();
self.remove_messages();
self.backend.send(BKCommand::Search(r, term)).unwrap();
self.gtk_builder
.get_object::<gtk::Stack>("search_button_stack")
.expect("Can't find search_button_stack in ui file.")
.set_visible_child_name("searching");
}
pub fn search_end(&self) {
self.gtk_builder
.get_object::<gtk::Stack>("search_button_stack")
.expect("Can't find search_button_stack in ui file.")
.set_visible_child_name("normal");
}
}
/// State for the main thread.
@ -1108,6 +1129,9 @@ impl App {
Ok(BKResponse::AttachedFile(msg)) => {
theop.lock().unwrap().add_tmp_room_message(&msg);
}
Ok(BKResponse::SearchEnd) => {
theop.lock().unwrap().search_end();
}
// errors
Ok(BKResponse::SyncError(_)) => {
@ -1170,6 +1194,8 @@ impl App {
self.connect_directory();
self.connect_room_config();
self.connect_search();
}
fn connect_room_config(&self) {
@ -1328,6 +1354,33 @@ impl App {
user_button.connect_clicked(move |_| user_menu.show_all());
}
fn connect_search(&self) {
// Set up search popover
let search_button: gtk::Button = self.gtk_builder
.get_object("search_button")
.expect("Couldn't find search_button in ui file.");
let search_popover: gtk::Popover = self.gtk_builder
.get_object("search_popover")
.expect("Couldn't find search_popover in ui file.");
let input: gtk::Entry = self.gtk_builder
.get_object("search_input")
.expect("Couldn't find search_input in ui file.");
let btn: gtk::Button = self.gtk_builder
.get_object("search")
.expect("Couldn't find search in ui file.");
search_button.connect_clicked(move |_| search_popover.show_all());
let op = self.op.clone();
input.connect_activate(move |inp| op.lock().unwrap().search(inp.get_text()));
let op = self.op.clone();
btn.connect_clicked(move |_| op.lock().unwrap().search(input.get_text()));
}
fn connect_login_button(&self) {
// Login click
let login_btn: gtk::Button = self.gtk_builder

View file

@ -72,6 +72,7 @@ pub enum BKCommand {
SetRoomTopic(String, String),
SetRoomAvatar(String, String),
AttachFile(String, String),
Search(String, Option<String>),
}
#[derive(Debug)]
@ -102,6 +103,7 @@ pub enum BKResponse {
RoomTopic(String, String),
Media(String),
AttachedFile(Message),
SearchEnd,
//errors
UserNameError(Error),
@ -126,6 +128,7 @@ pub enum BKResponse {
GetRoomAvatarError(Error),
MediaError(Error),
AttachFileError(Error),
SearchError(Error),
}
@ -272,6 +275,10 @@ impl Backend {
let r = self.attach_file(roomid, fname);
bkerror!(r, tx, BKResponse::AttachFileError);
}
Ok(BKCommand::Search(roomid, term)) => {
let r = self.search(roomid, term);
bkerror!(r, tx, BKResponse::SearchError);
}
Ok(BKCommand::ShutDown) => {
return false;
}
@ -913,7 +920,7 @@ impl Backend {
Ok(js) => {
let uri = js["content_uri"].as_str().unwrap_or("");
let attrs = json!({ "url": uri });
match json_q("put", &roomurl, &attrs) {
match json_q("put", &roomurl, &attrs, 10) {
Ok(_) => {
tx.send(BKResponse::SetRoomAvatar).unwrap();
},
@ -985,4 +992,65 @@ impl Backend {
Ok(())
}
pub fn search(&self, roomid: String, term: Option<String>) -> Result<(), Error> {
let tx = self.tx.clone();
match term {
Some(ref t) if !t.is_empty() => {
self.make_search(roomid, t.clone())
}
_ => {
tx.send(BKResponse::SearchEnd).unwrap();
self.get_room_messages(roomid, false)
}
}
}
pub fn make_search(&self, roomid: String, term: String) -> Result<(), Error> {
let url = self.url("search", vec![])?;
let attrs = json!({
"search_categories": {
"room_events": {
"keys": ["content.body"],
"search_term": term,
"filter": {
"rooms": [ roomid.clone() ],
},
"order_by": "recent",
},
},
});
let tx = self.tx.clone();
let baseu = self.get_base_url()?;
thread::spawn(move || {
match json_q("post", &url, &attrs, 0) {
Ok(js) => {
tx.send(BKResponse::SearchEnd).unwrap();
let mut ms: Vec<Message> = vec![];
let res = &js["search_categories"]["room_events"]["results"];
for search in res.as_array().unwrap().iter().rev() {
let msg = &search["result"];
if msg["type"].as_str().unwrap_or("") != "m.room.message" {
continue;
}
let m = parse_room_message(&baseu, roomid.clone(), msg);
ms.push(m);
}
tx.send(BKResponse::RoomMessagesInit(ms)).unwrap();
}
Err(err) => {
tx.send(BKResponse::SearchEnd).unwrap();
tx.send(BKResponse::SearchError(err)).unwrap()
}
};
});
Ok(())
}
}

View file

@ -120,7 +120,7 @@ macro_rules! post {
macro_rules! query {
($method: expr, $url: expr, $attrs: expr, $okcb: expr, $errcb: expr) => {
thread::spawn(move || {
let js = json_q($method, $url, $attrs);
let js = json_q($method, $url, $attrs, 10);
match js {
Ok(r) => {
@ -338,10 +338,12 @@ pub fn age_to_datetime(age: i64) -> DateTime<Local> {
now - diff
}
pub fn json_q(method: &str, url: &Url, attrs: &JsonValue) -> Result<JsonValue, Error> {
let client = reqwest::ClientBuilder::new()?
.timeout(StdDuration::from_secs(10))
.build()?;
pub fn json_q(method: &str, url: &Url, attrs: &JsonValue, timeout: u64) -> Result<JsonValue, Error> {
let mut clientb = reqwest::ClientBuilder::new()?;
let client = match timeout {
0 => clientb.build()?,
n => clientb.timeout(StdDuration::from_secs(n)).build()?
};
let mut conn = match method {
"post" => client.post(url.as_str())?,
@ -367,7 +369,7 @@ pub fn get_user_avatar(baseu: &Url, userid: &str) -> Result<(String, String), Er
let url = client_url!(baseu, &format!("profile/{}", userid), vec![])?;
let attrs = json!(null);
match json_q("get", &url, &attrs) {
match json_q("get", &url, &attrs, 10) {
Ok(js) => {
let name = String::from(js["displayname"].as_str().unwrap_or("@"));
match js["avatar_url"].as_str() {
@ -383,7 +385,7 @@ pub fn get_room_st(base: &Url, tk: &str, roomid: &str) -> Result<JsonValue, Erro
let url = client_url!(base, &format!("rooms/{}/state", roomid), vec![("access_token", strn!(tk))])?;
let attrs = json!(null);
let st = json_q("get", &url, &attrs)?;
let st = json_q("get", &url, &attrs, 10)?;
Ok(st)
}
@ -600,7 +602,7 @@ pub fn get_initial_room_messages(baseu: &Url,
let path = format!("rooms/{}/messages", roomid);
let url = client_url!(baseu, &path, params)?;
let r = json_q("get", &url, &json!(null))?;
let r = json_q("get", &url, &json!(null), 10)?;
nend = String::from(r["end"].as_str().unwrap_or(""));
nstart = String::from(r["start"].as_str().unwrap_or(""));