image_view: Rework model loading and page navigation

Rework the model loading to not care about the edges.
Now we only care about where we are in the model and
the number of buffer pages. This algorithm handles
the edges without special casing.
This commit is contained in:
Christopher Davis 2022-06-28 18:52:52 -04:00
parent 2b63f57d5b
commit 3557b15034

View file

@ -29,7 +29,7 @@ use anyhow::{bail, Context};
use ashpd::desktop::wallpaper; use ashpd::desktop::wallpaper;
use ashpd::WindowIdentifier; use ashpd::WindowIdentifier;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::cell::RefCell; use std::cell::{Cell, RefCell};
use crate::file_model::LpFileModel; use crate::file_model::LpFileModel;
use crate::thumbnail::Thumbnail; use crate::thumbnail::Thumbnail;
@ -38,7 +38,7 @@ use crate::widgets::LpImagePage;
// Maximum number of pages to load // Maximum number of pages to load
// at any given time // at any given time
const N_PAGES: u32 = 3; const N_PAGES: u32 = 2;
mod imp { mod imp {
use super::*; use super::*;
@ -51,6 +51,7 @@ mod imp {
pub model: RefCell<Option<LpFileModel>>, pub model: RefCell<Option<LpFileModel>>,
pub filename: RefCell<Option<String>>, pub filename: RefCell<Option<String>>,
pub prev_index: Cell<u32>,
} }
#[glib::object_subclass] #[glib::object_subclass]
@ -187,42 +188,27 @@ impl LpImageView {
if let Some(model) = imp.model.borrow().as_ref() { if let Some(model) = imp.model.borrow().as_ref() {
let index = model.index_of(file).unwrap() as u32; let index = model.index_of(file).unwrap() as u32;
log::debug!("Currently at file {index} in the directory");
imp.filename.replace(util::get_file_display_name(file)); imp.filename.replace(util::get_file_display_name(file));
carousel.append(&LpImagePage::from_file(file)); carousel.append(&LpImagePage::from_file(file));
// Here we need to check if we're at the start or end of our directory. for i in 1..=N_PAGES {
// If we are, we try to add two files to the other side. Otherwise, if let Some(file) = model.item(index + i).and_then(|o| o.downcast().ok()) {
// add one file on each end of the current file. carousel.append(&LpImagePage::from_file(&file))
let iterations = if index == 0 || index == model.n_items() - 1 {
2
} else {
1
};
let mut next_file = file.clone();
for i in 0..iterations {
log::debug!("Loop to find next files: {}", i);
if let Some(f) = model.next(&next_file) {
log::debug!("Adding next image URI: {}", f.uri());
carousel.append(&LpImagePage::from_file(&f));
next_file = f;
} else {
// Return early if there are no files in this direction;
break;
} }
} }
let mut prev_file = file.clone(); for i in 1..=N_PAGES {
for i in 0..iterations { if let Some(file) = index
log::debug!("Loop to find prior files: {}", i); .checked_sub(i)
if let Some(f) = model.previous(&prev_file) { .and_then(|i| model.item(i))
log::debug!("Adding previous image URI: {}", f.uri()); .and_then(|o| o.downcast().ok())
carousel.prepend(&LpImagePage::from_file(&f)); {
prev_file = f; carousel.prepend(&LpImagePage::from_file(&file))
} else {
break;
} }
} }
imp.prev_index.set(index);
} }
} }
@ -257,33 +243,62 @@ impl LpImageView {
} }
#[template_callback] #[template_callback]
fn page_changed_cb(&self, index: u32, carousel: &adw::Carousel) { fn page_changed_cb(&self, _index: u32, carousel: &adw::Carousel) {
let imp = self.imp(); let imp = self.imp();
let b = imp.model.borrow(); let b = imp.model.borrow();
let model = b.as_ref().unwrap(); let model = b.as_ref().unwrap();
let current = self.current_page().and_then(|p| p.file()).unwrap(); let current = self.current_page().and_then(|p| p.file()).unwrap();
let model_index = model.index_of(&current).unwrap() as u32;
let prev_index = imp.prev_index.get();
if model_index != prev_index {
imp.filename.replace(util::get_file_display_name(&current)); imp.filename.replace(util::get_file_display_name(&current));
self.notify("filename"); self.notify("filename");
self.update_action_state(&current); self.update_action_state(&current);
// We've moved forward // We've moved forward
if index + 1 == N_PAGES { if let Some(diff) = model_index.checked_sub(prev_index) {
if let Some(ref next) = model.next(&current) { for i in 0..diff {
log::debug!("Next URI: {}", next.uri()); if prev_index
// Remove the page at index 0, add a new page at the end .checked_sub(N_PAGES)
.and_then(|r| r.checked_sub(i))
.is_some()
{
carousel.remove(&carousel.nth_page(0)); carousel.remove(&carousel.nth_page(0));
carousel.append(&LpImagePage::from_file(next)); }
let s = prev_index + N_PAGES + i + 1;
if s <= model.n_items() {
if let Some(ref file) =
model.item(s).and_then(|o| o.downcast::<gio::File>().ok())
{
carousel.append(&LpImagePage::from_file(file));
}
}
} }
} }
// We've moved backward // We've moved backward
if index == 0 { if let Some(diff) = prev_index.checked_sub(model_index) {
if let Some(ref prev) = model.previous(&current) { for i in 0..diff {
log::debug!("Previous URI: {}", prev.uri()); let s = prev_index + N_PAGES + i + 1;
// Remove the page at the front, add a new page at the back if s <= model.n_items() {
carousel.remove(&carousel.nth_page(carousel.n_pages() - 1)); carousel.remove(&carousel.nth_page(carousel.n_pages() - 1));
carousel.prepend(&LpImagePage::from_file(prev));
} }
if let Some(ref file) = prev_index
.checked_sub(N_PAGES)
.and_then(|d| d.checked_sub(i + 1))
.and_then(|d| model.item(d))
.and_then(|i| i.downcast::<gio::File>().ok())
{
carousel.prepend(&LpImagePage::from_file(file));
}
}
}
imp.prev_index.set(model_index);
} }
} }