Commit 75d12677 authored by Eisha Chen-yen-su's avatar Eisha Chen-yen-su

MediaViewer: Add unlimited access to previous media

This adds the possibility to go back (with the previous button) beyond the loaded messages. See #265
parent d2999f85
extern crate glib;
extern crate gtk;
use self::gtk::prelude::*;
use i18n::i18n;
use uibuilder;
use app::App;
use appop::AppOp;
use appop::AppState;
use widgets::image;
use types::Message;
use types::Room;
use backend::BKCommand;
use std::sync::mpsc::channel;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc::RecvError;
const FLOATING_POINT_ERROR: f64 = 0.01;
#[derive(Clone)]
pub struct MediaViewer {
media_names: Vec<String>,
media_urls: Vec<String>,
media_list: Vec<Message>,
prev_batch: Option<String>,
current_media_index: usize,
image: image::Image,
......@@ -23,16 +33,23 @@ pub struct MediaViewer {
}
impl MediaViewer {
pub fn new(room: &Room, current_media_url: &str, image: image::Image) -> MediaViewer {
let img_msgs = room.messages.iter().filter(|msg| msg.mtype == "m.image");
let media_names: Vec<String> = img_msgs.clone().map(|msg| msg.body.clone()).collect();
let media_urls: Vec<String> = img_msgs.map(|msg| msg.url.clone().unwrap_or_default()).collect();
let current_media_index = media_urls.iter().position(|url| url == current_media_url).unwrap_or_default();
pub fn new(room: &Room, current_media_msg: &Message, image: image::Image) -> MediaViewer {
let media_list: Vec<Message> = room.messages.clone()
.into_iter()
.filter(|msg| msg.mtype == "m.image")
.collect();
let current_media_index = media_list.iter().position(|media| {
media.id.clone().map_or(false, |media_id| {
current_media_msg.id.clone().map_or(false, |current_media_id| {
media_id == current_media_id
})
})
}).unwrap_or_default();
MediaViewer {
media_names,
media_urls,
media_list,
prev_batch: None,
current_media_index,
image,
zoom_levels: vec![0.025, 0.05, 0.1, 0.25, 0.5, 0.75, 1.0],
......@@ -43,10 +60,34 @@ impl MediaViewer {
*self.image.zoom_level.lock().unwrap() = Some(zlvl);
self.image.widget.queue_draw();
}
pub fn load_more_media(&mut self, backend: Sender<BKCommand>) -> Result<(), RecvError> {
let msg = self.media_list[self.current_media_index].clone();
let roomid = msg.room.clone();
let first_media_id = msg.id.clone();
let prev_batch = self.prev_batch.clone();
let (tx, rx): (Sender<(Vec<Message>, String)>, Receiver<(Vec<Message>, String)>) = channel();
backend.send(BKCommand::GetMediaListAsync(roomid, first_media_id, prev_batch, tx)).unwrap();
let (msgs, prev_batch) = rx.recv()?;
let img_msgs: Vec<Message> = msgs.into_iter().filter(|msg| msg.mtype == "m.image").collect();
let img_msgs_count = img_msgs.len();
let new_media_list: Vec<Message> = img_msgs.into_iter()
.chain(self.media_list.clone().into_iter())
.collect();
self.media_list = new_media_list;
self.prev_batch = Some(prev_batch);
self.current_media_index += img_msgs_count;
Ok(())
}
}
impl AppOp {
pub fn display_media_viewer(&mut self, name: String, url: String, room_id: String) {
pub fn display_media_viewer(&mut self, media_msg: Message, room_id: String) {
let rooms = self.rooms.clone();
let r = rooms.get(&room_id).unwrap();
......@@ -62,20 +103,20 @@ impl AppOp {
self.set_state(AppState::MediaViewer);
set_header_title(&self.ui, &name);
set_header_title(&self.ui, &media_msg.body);
let media_viewport = self.ui.builder
.get_object::<gtk::Viewport>("media_viewport")
.expect("Cant find media_viewport in ui file.");
let image = image::Image::new(&self.backend, &url)
let image = image::Image::new(&self.backend, &media_msg.url.clone().unwrap_or_default())
.fit_to_width(true)
.fixed(true).center(true).build();
media_viewport.add(&image.widget);
media_viewport.show_all();
self.media_viewer = Some(MediaViewer::new(r, &url, image.clone()));
self.media_viewer = Some(MediaViewer::new(r, &media_msg, image.clone()));
let ui = self.ui.clone();
let zoom_level = image.zoom_level.clone();
......@@ -107,11 +148,26 @@ impl AppOp {
pub fn previous_media(&mut self) {
if let Some(ref mut mv) = self.media_viewer {
if mv.current_media_index == 0 {
match mv.load_more_media(self.backend.clone()) {
Err(_) => {
let err = i18n("Error while loading previous media");
APPOP!(show_error, (err));
},
Ok(_) if mv.current_media_index == 0 => {
let next_media_button = self.ui.builder
.get_object::<gtk::Button>("next_media_button")
.expect("Cant find next_media_button in ui file.");
next_media_button.set_sensitive(false);
return;
},
_ => {},
}
}
mv.current_media_index -= 1;
let name = &mv.media_names[mv.current_media_index];
let name = &mv.media_list[mv.current_media_index].body;
set_header_title(&self.ui, name);
}
......@@ -120,12 +176,12 @@ impl AppOp {
pub fn next_media(&mut self) {
if let Some(ref mut mv) = self.media_viewer {
if mv.current_media_index >= mv.media_urls.len() - 1 {
if mv.current_media_index >= mv.media_list.len() - 1 {
return;
}
mv.current_media_index += 1;
let name = &mv.media_names[mv.current_media_index];
let name = &mv.media_list[mv.current_media_index].body;
set_header_title(&self.ui, name);
}
......@@ -142,13 +198,11 @@ impl AppOp {
.get_object::<gtk::Button>("next_media_button")
.expect("Cant find next_media_button in ui file.");
if mv.current_media_index == 0 {
previous_media_button.set_sensitive(false);
} else {
if mv.current_media_index > 0 {
previous_media_button.set_sensitive(true);
}
if mv.current_media_index >= mv.media_urls.len() - 1 {
if mv.current_media_index >= mv.media_list.len() - 1 {
next_media_button.set_sensitive(false);
} else {
next_media_button.set_sensitive(true);
......@@ -293,7 +347,8 @@ impl AppOp {
pub fn save_media(&self) {
if let Some(ref mv) = self.media_viewer {
self.save_file_as(mv.image.local_path.lock().unwrap().clone().unwrap_or_default(), mv.media_names[mv.current_media_index].clone());
self.save_file_as(mv.image.local_path.lock().unwrap().clone().unwrap_or_default(),
mv.media_list[mv.current_media_index].body.clone());
}
}
......@@ -359,7 +414,7 @@ impl AppOp {
media_viewport.remove(&child);
}
let url = &mv.media_urls[mv.current_media_index];
let url = mv.media_list[mv.current_media_index].url.clone().unwrap_or_default();
let image = image::Image::new(&self.backend, &url)
.fit_to_width(true)
......
......@@ -259,7 +259,6 @@ impl<'a> MessageBox<'a> {
fn build_room_msg_image(&self) -> gtk::Box {
let msg = self.msg;
let bx = gtk::Box::new(gtk::Orientation::Horizontal, 0);
let url = msg.url.clone().unwrap_or_default();
let backend = self.op.backend.clone();
let img_path = match msg.thumb {
......@@ -269,13 +268,12 @@ impl<'a> MessageBox<'a> {
let image = widgets::image::Image::new(&backend, &img_path)
.size(Some((600, 400))).build();
let image_name = msg.body.clone();
let msg = msg.clone();
let room_id = self.room.id.clone();
image.widget.connect_button_press_event(move |_, _| {
let image_name = image_name.clone();
let image_url = url.clone();
let msg = msg.clone();
let rid = room_id.clone();
APPOP!(display_media_viewer, (image_name, image_url, rid));
APPOP!(display_media_viewer, (msg, rid));
Inhibit(true)
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment