window: prefetch images and queue offline read/unread actions

After a successful article refresh, all images referenced in article
content are downloaded in the background so articles can be read
offline. The prefetch only runs when the cache-images setting is
enabled and the connection is not metered.

Read/unread state changes that fail to reach the server (e.g. when
offline) are now persisted to a local queue in
~/.cache/net.jeena.FeedTheMonkey/pending_sync.json. The queue is
flushed at the start of the next successful fetch.
This commit is contained in:
Jeena 2026-03-21 02:45:45 +00:00
parent 3f759bce2e
commit 9bed643023
4 changed files with 123 additions and 5 deletions

View file

@ -592,12 +592,19 @@ pub mod imp {
let cache_images = settings.boolean("cache-images")
&& !gio::NetworkMonitor::default().is_network_metered();
let write_token = self.write_token.borrow().clone();
let win_weak = self.obj().downgrade();
crate::runtime::spawn(
async move {
// Flush any read/unread actions that failed to sync earlier.
if let Some(ref wt) = write_token {
crate::pending_actions::flush(&api, wt).await;
}
let articles = api.fetch_unread().await?;
let articles = if cache_images {
crate::image_cache::process(articles)
let processed = crate::image_cache::process(articles);
crate::runtime::spawn_bg(crate::image_cache::prefetch(processed.clone()));
processed
} else {
articles
};
@ -677,10 +684,19 @@ pub mod imp {
let wt = self.write_token.borrow().clone();
if let (Some(api), Some(wt)) = (api, wt) {
crate::runtime::spawn_bg(async move {
if let Err(e) = api.mark_read(&wt, &item_id).await {
eprintln!("mark_read error: {e}");
if api.mark_read(&wt, &item_id).await.is_err() {
crate::pending_actions::add(
crate::pending_actions::Action::Read,
&item_id,
);
}
});
} else {
// Offline or write token not yet available — queue for later.
crate::pending_actions::add(
crate::pending_actions::Action::Read,
&item_id,
);
}
}
@ -706,10 +722,18 @@ pub mod imp {
if let (Some(api), Some(wt)) = (api, wt) {
let id_clone = id.clone();
crate::runtime::spawn_bg(async move {
if let Err(e) = api.mark_unread(&wt, &id_clone).await {
eprintln!("mark_unread error: {e}");
if api.mark_unread(&wt, &id_clone).await.is_err() {
crate::pending_actions::add(
crate::pending_actions::Action::Unread,
&id_clone,
);
}
});
} else {
crate::pending_actions::add(
crate::pending_actions::Action::Unread,
&id,
);
}
let toast = libadwaita::Toast::new("Marked as unread");