article-row: fix bold on initial load, add right-click menu

Set unread bold state directly in bind() instead of relying on
obj.notify("unread"), which was unreliable during list factory binding
(GLib may defer or drop notifications during initial bind).

Also add a right-click context menu on each article row with a single
"Mark as Unread" item. The menu is a GtkPopover positioned at the
cursor. Clicking it activates the new win.mark-article-unread action,
which takes the article ID as a string parameter and reuses the
existing mark-unread logic.

Refactor do_mark_unread() to delegate to the new do_mark_article_unread()
so the behaviour is consistent whether triggered from the toolbar button,
keyboard shortcut, or right-click menu.
This commit is contained in:
Jeena 2026-03-22 01:51:12 +00:00
parent 571d80fa6b
commit 9a4bf4b9f8
2 changed files with 86 additions and 7 deletions

View file

@ -77,6 +77,11 @@ pub mod imp {
klass.install_action("win.reload", None, |win, _, _| win.imp().do_reload());
klass.install_action("win.logout", None, |win, _, _| win.imp().do_logout());
klass.install_action("win.mark-unread", None, |win, _, _| win.imp().do_mark_unread());
klass.install_action("win.mark-article-unread", Some(glib::VariantTy::STRING), |win, _, param| {
if let Some(id) = param.and_then(|p| p.get::<String>()) {
win.imp().do_mark_article_unread(id);
}
});
klass.install_action("win.open-in-browser", None, |win, _, _| {
win.imp().do_open_in_browser()
});
@ -750,8 +755,11 @@ pub mod imp {
fn do_mark_unread(&self) {
let id = self.current_article_id.borrow().clone();
let Some(id) = id else { return };
self.do_mark_article_unread(id);
}
// Find the ArticleObject in the store and set unread=true
fn do_mark_article_unread(&self, id: String) {
// Find the ArticleObject in the store and set unread=true.
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::<ArticleObject>() {
@ -762,7 +770,11 @@ pub mod imp {
}
}
*self.mark_unread_guard.borrow_mut() = true;
// If this is the currently displayed article, guard against it
// being immediately re-marked read when the selection fires.
if self.current_article_id.borrow().as_deref() == Some(&*id) {
*self.mark_unread_guard.borrow_mut() = true;
}
let api = self.api.borrow().clone();
let wt = self.write_token.borrow().clone();