Implemented initial search in room
This commit is contained in:
parent
999d298f8f
commit
d4df1b6ffd
5 changed files with 225 additions and 29 deletions
4
TODO
4
TODO
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
63
src/app.rs
63
src/app.rs
|
@ -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
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
18
src/util.rs
18
src/util.rs
|
@ -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(""));
|
||||
|
||||
|
|
Loading…
Reference in a new issue