Skip to content

Commit

Permalink
Unread messages in the room list
Browse files Browse the repository at this point in the history
  • Loading branch information
danigm committed Aug 29, 2017
1 parent 81bab87 commit f46c163
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 37 deletions.
13 changes: 13 additions & 0 deletions res/main_window.glade
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
<column type="gchararray"/>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name unread -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkApplicationWindow" id="main_window">
Expand Down Expand Up @@ -71,6 +73,17 @@
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<child>
<object class="GtkCellRendererText">
</object>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
Expand Down
63 changes: 51 additions & 12 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,31 +298,37 @@ impl AppOp {
self.backend.send(BKCommand::Sync).unwrap();
}

pub fn set_rooms(&mut self, rooms: HashMap<String, String>, def: Option<(String, String)>) {
pub fn set_rooms(&mut self, rooms: Vec<Room>, def: Option<Room>) {
let store: gtk::TreeStore = self.gtk_builder.get_object("rooms_tree_store")
.expect("Couldn't find rooms_tree_store in ui file.");

let mut array: Vec<(String, String)> = vec![];
for (id, name) in rooms {
array.push((name, id));
let mut array: Vec<Room> = vec![];

for r in rooms {
array.push(r);
}

array.sort_by(|x, y| x.0.to_lowercase().cmp(&y.0.to_lowercase()));
array.sort_by(|x, y| x.name.to_lowercase().cmp(&y.name.to_lowercase()));

let mut default: Option<(String, String)> = def;
let mut default: Option<Room> = def;

for v in array {
if default.is_none() {
default = Some((v.0.clone(), v.1.clone()));
default = Some(v.clone());
}

let ns = match v.notifications {
0 => String::new(),
i => format!("{}", i),
};

store.insert_with_values(None, None,
&[0, 1],
&[&v.0, &v.1]);
&[0, 1, 2],
&[&v.name, &v.id, &ns]);
}

if let Some(def) = default {
self.set_active_room(def.1, def.0);
self.set_active_room(def.id, def.name);
} else {
self.room_panel(RoomPanel::NoRoom);
}
Expand Down Expand Up @@ -434,9 +440,38 @@ impl AppOp {
MsgPos::Bottom => messages.add(&msg),
MsgPos::Top => messages.insert(&msg, 1),
};

} else {
// TODO: update the unread messages count in room list
self.update_room_notifications(&msg.room, |n| n + 1);
}
}

pub fn update_room_notifications(&self, roomid: &str, f: fn(i32) -> i32) {
let store: gtk::TreeStore = self.gtk_builder.get_object("rooms_tree_store")
.expect("Couldn't find rooms_tree_store in ui file.");

if let Some(iter) = store.get_iter_first() {
loop {
let v1 = store.get_value(&iter, 1);
let id: &str = v1.get().unwrap();
let v2 = store.get_value(&iter, 2);
let ns: &str = v2.get().unwrap();
let res: Result<i32, _> = ns.parse();
let n: i32 = f(res.unwrap_or(0));
let formatted = match n {
0 => String::from(""),
i => format!("{}", i),
};
if id == roomid {
store.set_value(&iter, 2, &gtk::Value::from(&formatted));
}
if !store.iter_next(&iter) { break; }
}
}
}

pub fn mark_as_read(&self, msgs: Vec<Message>) {
if let Some(msg) = msgs.iter().filter(|x| x.room == self.active_room).last() {
self.backend.send(BKCommand::MarkAsRead(msg.room.clone(), msg.id.clone())).unwrap();
}
}

Expand Down Expand Up @@ -641,6 +676,7 @@ impl App {

if !msgs.is_empty() {
theop.lock().unwrap().scroll_down();
theop.lock().unwrap().mark_as_read(msgs);
}

theop.lock().unwrap().room_panel(RoomPanel::Room);
Expand Down Expand Up @@ -671,6 +707,9 @@ impl App {
Ok(BKResponse::JoinRoom) => {
theop.lock().unwrap().reload_rooms();
},
Ok(BKResponse::MarkedAsRead(r, _)) => {
theop.lock().unwrap().update_room_notifications(&r, |_| 0);
},
// errors
Ok(err) => {
println!("Query error: {:?}", err);
Expand Down
54 changes: 38 additions & 16 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use self::serde_json::Value as JsonValue;

use std::sync::{Arc, Mutex};
use std::thread;
use std::collections::HashMap;
use self::url::Url;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc::channel;
Expand Down Expand Up @@ -62,6 +61,7 @@ pub enum BKCommand {
DirectoryProtocols,
DirectorySearch(String, String, bool),
JoinRoom(String),
MarkAsRead(String, String),
}

#[derive(Debug)]
Expand All @@ -70,7 +70,7 @@ pub enum BKResponse {
Name(String),
Avatar(String),
Sync,
Rooms(HashMap<String, String>, Option<(String, String)>),
Rooms(Vec<Room>, Option<Room>),
RoomDetail(String, String),
RoomAvatar(String),
RoomMessages(Vec<Message>),
Expand All @@ -80,6 +80,7 @@ pub enum BKResponse {
DirectoryProtocols(Vec<Protocol>),
DirectorySearch(Vec<Room>),
JoinRoom,
MarkedAsRead(String, String),

//errors
UserNameError(Error),
Expand All @@ -96,6 +97,7 @@ pub enum BKResponse {
CommandError(Error),
DirectoryError(Error),
JoinRoomError(Error),
MarkAsReadError(Error),
}


Expand Down Expand Up @@ -194,6 +196,10 @@ impl Backend {
let r = self.join_room(roomid);
bkerror!(r, tx, BKResponse::JoinRoomError);
},
Ok(BKCommand::MarkAsRead(roomid, evid)) => {
let r = self.mark_as_read(roomid, evid);
bkerror!(r, tx, BKResponse::MarkAsReadError);
},
Ok(BKCommand::ShutDown) => {
return false;
},
Expand Down Expand Up @@ -390,11 +396,11 @@ impl Backend {
if since.is_empty() {
let rooms = get_rooms_from_json(r, &userid).unwrap();

let mut def: Option<(String, String)> = None;
let mut def: Option<Room> = None;
let jtr = data.lock().unwrap().join_to_room.clone();
if !jtr.is_empty() {
if let Some(name) = rooms.iter().find(|x| *(x.0) == jtr) {
def = Some((name.1.clone(), name.0.clone()));
if let Some(r) = rooms.iter().find(|x| x.id == jtr) {
def = Some(r.clone());
}
}

Expand Down Expand Up @@ -487,7 +493,6 @@ impl Backend {
}
url = url.join(&params)?;


let tx = self.tx.clone();
let data = self.data.clone();
get!(&url,
Expand Down Expand Up @@ -688,16 +693,15 @@ impl Backend {
let mut rooms: Vec<Room> = vec![];
for room in r["chunk"].as_array().unwrap() {
let alias = String::from(room["canonical_alias"].as_str().unwrap_or(""));
let r = Room {
alias: alias,
id: String::from(room["room_id"].as_str().unwrap_or("")),
avatar: String::from(room["avatar_url"].as_str().unwrap_or("")),
name: String::from(room["name"].as_str().unwrap_or("")),
topic: String::from(room["topic"].as_str().unwrap_or("")),
members: room["num_joined_members"].as_i64().unwrap_or(0) as i32,
world_readable: room["world_readable"].as_bool().unwrap_or(false),
guest_can_join: room["guest_can_join"].as_bool().unwrap_or(false),
};
let id = String::from(room["room_id"].as_str().unwrap_or(""));
let name = String::from(room["name"].as_str().unwrap_or(""));
let mut r = Room::new(id, name);
r.alias = alias;
r.avatar = String::from(room["avatar_url"].as_str().unwrap_or(""));
r.topic = String::from(room["topic"].as_str().unwrap_or(""));
r.members = room["num_joined_members"].as_i64().unwrap_or(0) as i32;
r.world_readable = room["world_readable"].as_bool().unwrap_or(false);
r.guest_can_join = room["guest_can_join"].as_bool().unwrap_or(false);
rooms.push(r);
}

Expand Down Expand Up @@ -727,4 +731,22 @@ impl Backend {

Ok(())
}

pub fn mark_as_read(&self, roomid: String, eventid: String) -> Result<(), Error> {
let baseu = self.get_base_url()?;
let tk = self.data.lock().unwrap().access_token.clone();
let mut url = baseu.join("/_matrix/client/r0/rooms/")?;
url = url.join(&format!("{}/receipt/m.read/{}", roomid, eventid))?;
url = url.join(&format!("?access_token={}", tk))?;

let tx = self.tx.clone();
let r = roomid.clone();
let e = eventid.clone();
post!(&url,
move |_: JsonValue| { tx.send(BKResponse::MarkedAsRead(r, e)).unwrap(); },
|err| { tx.send(BKResponse::MarkAsReadError(err)).unwrap(); }
);

Ok(())
}
}
40 changes: 37 additions & 3 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct Message {
pub room: String,
pub thumb: String,
pub url: String,
pub id: String,
}

#[derive(Debug)]
Expand Down Expand Up @@ -40,9 +41,42 @@ pub struct Room {
pub id: String,
pub avatar: String,
pub name: String,
pub guest_can_join: bool,
pub topic: String,
pub members: i32,
pub world_readable: bool,
pub alias: String,
pub guest_can_join: bool,
pub world_readable: bool,
pub members: i32,
pub notifications: i32,
}

impl Room {
pub fn new(id: String, name: String) -> Room {
Room {
id: id,
name: name,
avatar: String::new(),
topic: String::new(),
alias: String::new(),
guest_can_join: true,
world_readable: true,
members: 0,
notifications: 0,
}
}
}

impl Clone for Room {
fn clone(&self) -> Room {
Room {
id: self.id.clone(),
name: self.name.clone(),
avatar: self.avatar.clone(),
topic: self.topic.clone(),
alias: self.alias.clone(),
guest_can_join: self.guest_can_join,
world_readable: self.world_readable,
members: self.members,
notifications: self.notifications,
}
}
}
33 changes: 27 additions & 6 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use self::regex::Regex;

use self::serde_json::Value as JsonValue;

use std::collections::HashMap;
use self::url::Url;
use std::io::Read;
use std::path::Path;
Expand All @@ -27,6 +26,7 @@ use self::time::Duration;

use error::Error;
use types::Message;
use types::Room;


// from https://stackoverflow.com/a/43992218/1592377
Expand Down Expand Up @@ -134,22 +134,41 @@ macro_rules! thumb {
};
}

pub fn get_rooms_from_json(r: JsonValue, userid: &str) -> Result<HashMap<String, String>, Error> {
pub fn evc(events: &JsonValue, t: &str, field: &str) -> String {
if let Some(arr) = events.as_array() {
return match arr.iter().find(|x| x["type"] == t) {
Some(js) => String::from(js["content"][field].as_str().unwrap_or("")),
None => String::new(),
};
}

String::new()
}

pub fn get_rooms_from_json(r: JsonValue, userid: &str) -> Result<Vec<Room>, Error> {
let rooms = &r["rooms"];
// TODO: do something with invite and leave
//let invite = rooms["invite"].as_object().ok_or(Error::BackendError)?;
//let leave = rooms["leave"].as_object().ok_or(Error::BackendError)?;

let join = rooms["join"].as_object().ok_or(Error::BackendError)?;

let mut rooms_map: HashMap<String, String> = HashMap::new();
let mut rooms: Vec<Room> = vec![];
for k in join.keys() {
let room = join.get(k).ok_or(Error::BackendError)?;
let name = calculate_room_name(&room["state"]["events"], userid)?;
rooms_map.insert(k.clone(), name);
let stevents = &room["state"]["events"];
let name = calculate_room_name(stevents, userid)?;
let mut r = Room::new(k.clone(), name);

r.avatar = evc(stevents, "m.room.avatar", "url");
r.alias = evc(stevents, "m.room.canonical_alias", "alias");
r.topic = evc(stevents, "m.room.topic", "topic");
r.notifications = room["unread_notifications"]["notification_count"]
.as_i64().unwrap_or(0) as i32;
rooms.push(r);
}

Ok(rooms_map)
Ok(rooms)
}

pub fn get_rooms_timeline_from_json(baseu: &Url, r: JsonValue) -> Result<Vec<Message>, Error> {
Expand Down Expand Up @@ -417,6 +436,7 @@ pub fn calculate_room_name(roomst: &JsonValue, userid: &str) -> Result<String, E
pub fn parse_room_message(baseu: &Url, roomid: String, msg: &JsonValue) -> Message {
let sender = msg["sender"].as_str().unwrap_or("");
let age = msg["age"].as_i64().unwrap_or(0);
let id = msg["id"].as_str().unwrap_or("");

let c = &msg["content"];
let mtype = c["msgtype"].as_str().unwrap_or("");
Expand All @@ -442,6 +462,7 @@ pub fn parse_room_message(baseu: &Url, roomid: String, msg: &JsonValue) -> Messa
room: roomid.clone(),
url: url,
thumb: thumb,
id: String::from(id),
}
}

Expand Down

0 comments on commit f46c163

Please sign in to comment.