v0.3.4: Comment edit/delete, native notifications, forward-compatible protocol, UI fixes

Comment edit & delete:
- EditComment/DeleteComment BlobHeaderDiffOps with upstream+downstream propagation
- Trust-based: comment author can edit/delete, post author can delete
- Storage: edit_comment(), delete_comment() methods
- Frontend: inline edit (Enter/Escape), delete with confirm

Native notifications:
- tauri-plugin-notification for system notifications on all platforms
- Triggers for messages, new posts, reactions, and comments
- notif_reacts setting added, button-group toggles replace dropdowns
- _notifReady flag prevents startup spam

Protocol hardening:
- BlobHeaderDiffOp::Unknown variant with #[serde(other)] for forward compatibility
- Old nodes silently skip unknown ops instead of crashing

UI fixes:
- Self removed from Following list
- Offline follows in lightbox popup (auto-show if no one online)
- Sent DMs filtered from My Posts
- Comment threading scoped to closest .post (fixes duplicate ID issue)
- Select dropdown text legible in WebKitGTK (black on white options)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Scott Reimers 2026-03-18 00:47:53 -04:00
parent ce176a2299
commit 0abc244ee9
18 changed files with 1616 additions and 67 deletions

View file

@ -3918,6 +3918,24 @@ impl Storage {
Ok(())
}
/// Edit a comment (must match author + post_id + timestamp_ms).
pub fn edit_comment(&self, author: &NodeId, post_id: &PostId, timestamp_ms: u64, new_content: &str) -> anyhow::Result<bool> {
let updated = self.conn.execute(
"UPDATE comments SET content = ?4 WHERE author = ?1 AND post_id = ?2 AND timestamp_ms = ?3",
params![author.as_slice(), post_id.as_slice(), timestamp_ms as i64, new_content],
)?;
Ok(updated > 0)
}
/// Delete a comment (must match author + post_id + timestamp_ms).
pub fn delete_comment(&self, author: &NodeId, post_id: &PostId, timestamp_ms: u64) -> anyhow::Result<bool> {
let deleted = self.conn.execute(
"DELETE FROM comments WHERE author = ?1 AND post_id = ?2 AND timestamp_ms = ?3",
params![author.as_slice(), post_id.as_slice(), timestamp_ms as i64],
)?;
Ok(deleted > 0)
}
/// Get all comments for a post, ordered by timestamp.
pub fn get_comments(&self, post_id: &PostId) -> anyhow::Result<Vec<InlineComment>> {
let mut stmt = self.conn.prepare(