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; extern crate gtk;
use self::gtk::prelude::*; use self::gtk::prelude::*;
use i18n::i18n;
use uibuilder; use uibuilder;
use app::App;
use appop::AppOp; use appop::AppOp;
use appop::AppState; use appop::AppState;
use widgets::image; use widgets::image;
use types::Message;
use types::Room; 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; const FLOATING_POINT_ERROR: f64 = 0.01;
#[derive(Clone)] #[derive(Clone)]
pub struct MediaViewer { pub struct MediaViewer {
media_names: Vec<String>, media_list: Vec<Message>,
media_urls: Vec<String>, prev_batch: Option<String>,
current_media_index: usize, current_media_index: usize,
image: image::Image, image: image::Image,
...@@ -23,16 +33,23 @@ pub struct MediaViewer { ...@@ -23,16 +33,23 @@ pub struct MediaViewer {
} }
impl MediaViewer { impl MediaViewer {
pub fn new(room: &Room, current_media_url: &str, image: image::Image) -> MediaViewer { pub fn new(room: &Room, current_media_msg: &Message, image: image::Image) -> MediaViewer {
let img_msgs = room.messages.iter().filter(|msg| msg.mtype == "m.image"); let media_list: Vec<Message> = room.messages.clone()
let media_names: Vec<String> = img_msgs.clone().map(|msg| msg.body.clone()).collect(); .into_iter()
let media_urls: Vec<String> = img_msgs.map(|msg| msg.url.clone().unwrap_or_default()).collect(); .filter(|msg| msg.mtype == "m.image")
.collect();
let current_media_index = media_urls.iter().position(|url| url == current_media_url).unwrap_or_default();
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 { MediaViewer {
media_names, media_list,
media_urls, prev_batch: None,
current_media_index, current_media_index,
image, image,
zoom_levels: vec![0.025, 0.05, 0.1, 0.25, 0.5, 0.75, 1.0], zoom_levels: vec![0.025, 0.05, 0.1, 0.25, 0.5, 0.75, 1.0],
...@@ -43,10 +60,34 @@ impl MediaViewer { ...@@ -43,10 +60,34 @@ impl MediaViewer {
*self.image.zoom_level.lock().unwrap() = Some(zlvl); *self.image.zoom_level.lock().unwrap() = Some(zlvl);
self.image.widget.queue_draw(); 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 { 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 rooms = self.rooms.clone();
let r = rooms.get(&room_id).unwrap(); let r = rooms.get(&room_id).unwrap();
...@@ -62,20 +103,20 @@ impl AppOp { ...@@ -62,20 +103,20 @@ impl AppOp {
self.set_state(AppState::MediaViewer); 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 let media_viewport = self.ui.builder
.get_object::<gtk::Viewport>("media_viewport") .get_object::<gtk::Viewport>("media_viewport")
.expect("Cant find media_viewport in ui file."); .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) .fit_to_width(true)
.fixed(true).center(true).build(); .fixed(true).center(true).build();
media_viewport.add(&image.widget); media_viewport.add(&image.widget);
media_viewport.show_all(); 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 ui = self.ui.clone();
let zoom_level = image.zoom_level.clone(); let zoom_level = image.zoom_level.clone();
...@@ -107,11 +148,26 @@ impl AppOp { ...@@ -107,11 +148,26 @@ impl AppOp {
pub fn previous_media(&mut self) { pub fn previous_media(&mut self) {
if let Some(ref mut mv) = self.media_viewer { if let Some(ref mut mv) = self.media_viewer {
if mv.current_media_index == 0 { if mv.current_media_index == 0 {
return; 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; 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); set_header_title(&self.ui, name);
} }
...@@ -120,12 +176,12 @@ impl AppOp { ...@@ -120,12 +176,12 @@ impl AppOp {
pub fn next_media(&mut self) { pub fn next_media(&mut self) {
if let Some(ref mut mv) = self.media_viewer { 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; return;
} }
mv.current_media_index += 1; 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); set_header_title(&self.ui, name);
} }
...@@ -142,13 +198,11 @@ impl AppOp { ...@@ -142,13 +198,11 @@ impl AppOp {
.get_object::<gtk::Button>("next_media_button") .get_object::<gtk::Button>("next_media_button")
.expect("Cant find next_media_button in ui file."); .expect("Cant find next_media_button in ui file.");
if mv.current_media_index == 0 { if mv.current_media_index > 0 {
previous_media_button.set_sensitive(false);
} else {
previous_media_button.set_sensitive(true); 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); next_media_button.set_sensitive(false);
} else { } else {
next_media_button.set_sensitive(true); next_media_button.set_sensitive(true);
...@@ -293,7 +347,8 @@ impl AppOp { ...@@ -293,7 +347,8 @@ impl AppOp {
pub fn save_media(&self) { pub fn save_media(&self) {
if let Some(ref mv) = self.media_viewer { 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 { ...@@ -359,7 +414,7 @@ impl AppOp {
media_viewport.remove(&child); 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) let image = image::Image::new(&self.backend, &url)
.fit_to_width(true) .fit_to_width(true)
......
...@@ -259,7 +259,6 @@ impl<'a> MessageBox<'a> { ...@@ -259,7 +259,6 @@ impl<'a> MessageBox<'a> {
fn build_room_msg_image(&self) -> gtk::Box { fn build_room_msg_image(&self) -> gtk::Box {
let msg = self.msg; let msg = self.msg;
let bx = gtk::Box::new(gtk::Orientation::Horizontal, 0); let bx = gtk::Box::new(gtk::Orientation::Horizontal, 0);
let url = msg.url.clone().unwrap_or_default();
let backend = self.op.backend.clone(); let backend = self.op.backend.clone();
let img_path = match msg.thumb { let img_path = match msg.thumb {
...@@ -269,13 +268,12 @@ impl<'a> MessageBox<'a> { ...@@ -269,13 +268,12 @@ impl<'a> MessageBox<'a> {
let image = widgets::image::Image::new(&backend, &img_path) let image = widgets::image::Image::new(&backend, &img_path)
.size(Some((600, 400))).build(); .size(Some((600, 400))).build();
let image_name = msg.body.clone(); let msg = msg.clone();
let room_id = self.room.id.clone(); let room_id = self.room.id.clone();
image.widget.connect_button_press_event(move |_, _| { image.widget.connect_button_press_event(move |_, _| {
let image_name = image_name.clone(); let msg = msg.clone();
let image_url = url.clone();
let rid = room_id.clone(); let rid = room_id.clone();
APPOP!(display_media_viewer, (image_name, image_url, rid)); APPOP!(display_media_viewer, (msg, rid));
Inhibit(true) 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