Commit b68242c8 authored by Christopher Davis's avatar Christopher Davis

widgets: speed up initial load by loading timeline in bg

Previously on startup we would fetch the timeline
as we build the app. This had two issues:

* However long it took for the timeline to be fetched
is how long it would take for our window to show
* The app would crash if the timeline was not fetched.

This commit makes Social more resilient, using a spinner
for the timeline while it's fetched, then switching to the
list of posts.
parent 6df97068
Pipeline #84029 passed with stage
in 10 minutes and 32 seconds
......@@ -61,6 +61,6 @@ impl MainContentPage {
}
pub fn init(&self) {
self.home_timeline.init().unwrap();
self.home_timeline.init();
}
}
......@@ -26,26 +26,40 @@ use elefren::prelude::*;
use std::cell::RefCell;
use std::rc::Rc;
use crate::error::Error;
use crate::utils::lazy_load;
use crate::widgets::TootWidget;
#[derive(Clone, Debug)]
pub struct Home {
pub container: gtk::ListBox,
pub container: gtk::Stack,
listbox: gtk::ListBox,
client: Rc<elefren::Mastodon>,
timeline: RefCell<Option<OwnedPage<Status, HttpSender>>>,
timeline: Rc<RefCell<Option<OwnedPage<Status, HttpSender>>>>,
}
impl Home {
pub fn new(client: Rc<Mastodon>) -> Rc<Self> {
let container = gtk::ListBox::new();
container.set_selection_mode(gtk::SelectionMode::None);
let listbox = gtk::ListBox::new();
listbox.set_selection_mode(gtk::SelectionMode::None);
listbox.show_all();
let spinner = gtk::Spinner::new();
spinner.start();
spinner.show();
let container = gtk::Stack::new();
container.set_homogeneous(false);
container.add_named(&listbox, "list");
container.add_named(&spinner, "spinner");
container.set_visible_child_name("spinner");
container.set_transition_type(gtk::StackTransitionType::Crossfade);
container.show_all();
let widget = Home {
container,
listbox,
client,
timeline: RefCell::new(None),
timeline: Rc::new(RefCell::new(None)),
};
keep!(widget);
......@@ -53,20 +67,34 @@ impl Home {
Rc::new(widget)
}
pub fn init(&self) -> Result<(), Error> {
let timeline = self.client.get_home_timeline()?;
let items = timeline.initial_items;
let page: Vec<(Rc<Mastodon>, Status)> = items
.iter()
.map(move |status| (self.client.clone(), status.clone()))
.collect();
pub fn init(&self) {
let constructor = move |tuple: (Rc<Mastodon>, Status)| {
TootWidget::new(tuple.0, tuple.1).container.clone()
};
lazy_load(page, self.container.downgrade(), constructor, || {});
Ok(())
let client = self.client.clone();
let weak_lb = self.listbox.downgrade();
let weak_stack = self.container.downgrade();
let tl = self.timeline.clone();
// Fetch inital timeline; Retry after 2 seconds on failure.
gtk::timeout_add_seconds(2, move || match client.get_home_timeline() {
Ok(timeline) => {
tl.replace(Some(timeline.clone().to_owned()));
let items = timeline.initial_items;
let page: Vec<(Rc<Mastodon>, Status)> = items
.iter()
.map(|status| (client.clone(), status.clone()))
.collect();
let w = weak_stack.clone();
lazy_load(page, weak_lb.clone(), constructor, move || {
upgrade_weak!(w).set_visible_child_name("list");
});
glib::Continue(false)
}
Err(e) => {
eprintln!("Failed to get timeline: {:#?}", e);
glib::Continue(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