diff --git a/src/window.rs b/src/window.rs index a863fdb..8139c95 100644 --- a/src/window.rs +++ b/src/window.rs @@ -137,7 +137,6 @@ pub mod imp { self.setup_capture_keys(); self.restore_from_cache(); self.auto_login(); - self.web_view.grab_focus(); } } @@ -206,8 +205,6 @@ pub mod imp { fn setup_list(&self) { let store = gio::ListStore::new::(); let selection = gtk4::SingleSelection::new(Some(store.clone())); - selection.set_autoselect(false); - selection.set_can_unselect(true); *self.article_store.borrow_mut() = Some(store); let factory = gtk4::SignalListItemFactory::new(); @@ -246,12 +243,10 @@ pub mod imp { } fn on_article_selected(&self, obj: ArticleObject) { - // Mark the previous article as read — both on the server and in the - // sidebar — now that the user has navigated away from it. + // Mark previous article as read (unless guard is set) if !*self.mark_unread_guard.borrow() { if let Some(prev_id) = self.current_article_id.borrow().clone() { if prev_id != obj.article().id { - self.mark_read_in_list(&prev_id); self.bg_mark_read(prev_id); } } @@ -259,30 +254,13 @@ pub mod imp { *self.mark_unread_guard.borrow_mut() = false; let article = obj.article().clone(); - let same_article = self.current_article_id.borrow().as_deref() == Some(&*article.id); *self.current_article_id.borrow_mut() = Some(article.id.clone()); self.article_menu_button.set_visible(true); - // Skip WebView reload when re-selecting the same article (e.g. after - // a server refresh) so the user's scroll position is preserved. - if !same_article { - self.load_article_in_webview(&article); - } - } - - /// Mark an article as read in the sidebar list (UI only). - fn mark_read_in_list(&self, article_id: &str) { - if let Some(store) = self.article_store.borrow().as_ref() { - for i in 0..store.n_items() { - if let Some(obj) = store.item(i).and_downcast::() { - if obj.article().id == article_id { - obj.set_unread(false); - break; - } - } - } - } + // Load in webview + self.load_article_in_webview(&article); + obj.set_unread(false); } fn reload_current_article(&self) { @@ -736,64 +714,39 @@ pub mod imp { store.append(&ArticleObject::new(a.clone())); } + // Save cache and clean up unreferenced images. + let sel_id = saved_id.as_deref().unwrap_or(""); + crate::cache::save(&articles, sel_id); crate::image_cache::cleanup(&articles); - let n = store.n_items(); - if n == 0 { + if store.n_items() == 0 { imp.sidebar_content.set_visible_child_name("empty"); *imp.current_article_id.borrow_mut() = None; imp.article_menu_button.set_visible(false); imp.content_stack.set_visible_child_name("empty"); - crate::cache::save(&articles, ""); } else { - // Try to re-select the same article the user was reading. - let found_idx = saved_id.as_ref().and_then(|id| { - (0..n).find(|&i| { - store.item(i).and_downcast::() + // Try to re-select the same article; fall back to first. + let mut select_idx = 0u32; + if let Some(ref id) = saved_id { + for i in 0..store.n_items() { + if store.item(i).and_downcast::() .map(|o| o.article().id == *id) .unwrap_or(false) - }) - }); - - if let Some(idx) = found_idx { - // Article still unread — re-select it without - // reloading the WebView (preserves scroll position). - *imp.mark_unread_guard.borrow_mut() = true; - sel.set_selected(idx); - imp.article_list_view.scroll_to( - idx, - gtk4::ListScrollFlags::SELECT, - None, - ); - crate::cache::save(&articles, - saved_id.as_deref().unwrap_or("")); - } else if saved_id.is_some() { - // Article was read elsewhere — keep it in the - // WebView so the user can finish reading but - // leave the sidebar list unselected. - crate::cache::save(&articles, ""); - } else { - // No previous article (first load) — select the - // first article. - sel.set_selected(0); - imp.article_list_view.scroll_to( - 0, - gtk4::ListScrollFlags::SELECT, - None, - ); - crate::cache::save(&articles, ""); + { + select_idx = i; + break; + } + } } + *imp.mark_unread_guard.borrow_mut() = true; + sel.set_selected(select_idx); + imp.article_list_view.scroll_to( + select_idx, + gtk4::ListScrollFlags::SELECT, + None, + ); imp.sidebar_content.set_visible_child_name("list"); } - - // Always notify the user that the fetch finished. - let msg = if n == 1 { - String::from("1 unread article") - } else { - format!("{n} unread articles") - }; - let toast = libadwaita::Toast::new(&msg); - imp.toast_overlay.add_toast(toast); } Err(e) => { // If we already have cached articles, just show a toast. @@ -892,10 +845,7 @@ pub mod imp { let n = sel.n_items(); if n == 0 { return } let current = sel.selected(); - let next = if current == gtk4::INVALID_LIST_POSITION { - // Nothing selected — pick the first or last article. - if delta > 0 { 0 } else { n - 1 } - } else if delta > 0 { + let next = if delta > 0 { (current + 1).min(n - 1) } else { current.saturating_sub(1)