diff --git a/src/feed_event.rs b/src/feed_event.rs deleted file mode 100644 index 1ec7e4fd..00000000 --- a/src/feed_event.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::db::DbEvent; -use crate::error::Error; -use nostr_types::{Event, EventKind, Id}; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct Reactions { - pub upvotes: u64, - pub downvotes: u64, - pub emojis: Vec<(char, u64)>, -} - -/// This contains event-related data that is relevant at the time of -/// rendering the event, most of which is gathered from other related -/// events. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct FeedEvent { - pub id: Id, - pub event: Option, - pub feed_related: bool, - pub replies: Vec, - pub in_reply_to: Option, - pub reactions: Reactions, - pub deleted_reason: Option, - pub client: Option, - pub hashtags: Vec, - pub subject: Option, - pub urls: Vec, - pub last_reply_at: Option, -} - -impl FeedEvent { - #[allow(dead_code)] - pub fn new(id: Id) -> FeedEvent { - FeedEvent { - id, - event: None, - feed_related: false, - replies: Vec::new(), - in_reply_to: None, - reactions: Default::default(), - deleted_reason: None, - client: None, - hashtags: Vec::new(), - subject: None, - urls: Vec::new(), - last_reply_at: None, - } - } -} - -impl From<&Event> for FeedEvent { - fn from(event: &Event) -> FeedEvent { - FeedEvent { - id: event.id, - event: Some(event.to_owned()), - feed_related: event.kind == EventKind::TextNote, - replies: Vec::new(), - in_reply_to: None, - reactions: Default::default(), - deleted_reason: None, - client: None, - hashtags: Vec::new(), - subject: None, - urls: Vec::new(), - last_reply_at: Some(event.created_at.0), - } - } -} - -impl TryFrom<&DbEvent> for FeedEvent { - type Error = Error; - - fn try_from(dbevent: &DbEvent) -> Result { - Ok(FeedEvent { - id: dbevent.id.clone().try_into()?, - event: serde_json::from_str(&dbevent.raw)?, - feed_related: dbevent.kind == 1, - replies: Vec::new(), - in_reply_to: None, - reactions: Default::default(), - deleted_reason: None, - client: None, - hashtags: Vec::new(), - subject: None, - urls: Vec::new(), - last_reply_at: Some(dbevent.created_at), - }) - } -} diff --git a/src/globals.rs b/src/globals.rs index 750e8e24..2e1fcabc 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -1,7 +1,6 @@ use crate::comms::BusMessage; use crate::db::{DbPerson, DbPersonRelay, DbRelay}; use crate::error::Error; -use crate::feed_event::FeedEvent; use crate::relationship::Relationship; use crate::settings::Settings; use async_recursion::async_recursion; @@ -29,15 +28,10 @@ pub struct Globals { /// and stolen away when the Overlord is created. pub from_minions: Mutex>>, - /// All nostr event related data, keyed by the event Id - pub feed_events: Mutex>, - /// All nostr events, keyed by the event Id - /// This will replace feed_events. pub events: Mutex>, /// All relationships between events - /// This will also replace feed_events. pub relationships: Mutex>>, /// The date of the latest reply. Only reply relationships count, not reactions, @@ -73,7 +67,6 @@ lazy_static! { to_minions, to_overlord, from_minions: Mutex::new(Some(from_minions)), - feed_events: Mutex::new(HashMap::new()), events: Mutex::new(HashMap::new()), relationships: Mutex::new(HashMap::new()), last_reply: Mutex::new(HashMap::new()), @@ -88,20 +81,20 @@ lazy_static! { impl Globals { #[allow(dead_code)] pub async fn get_feed(threaded: bool) -> Vec { - let feed: Vec = GLOBALS - .feed_events + let feed: Vec = GLOBALS + .events .lock() .await .iter() .map(|(_, e)| e) - .filter(|e| e.event.is_some() && e.event.as_ref().unwrap().kind == EventKind::TextNote) + .filter(|e| e.kind == EventKind::TextNote) .filter(|e| { if threaded { - e.in_reply_to.is_none() + e.replies_to().is_none() } else { true } - }) // only root events + }) .cloned() .collect(); @@ -110,44 +103,36 @@ impl Globals { #[allow(dead_code)] pub fn blocking_get_feed(threaded: bool) -> Vec { - let feed: Vec = GLOBALS - .feed_events + let feed: Vec = GLOBALS + .events .blocking_lock() .iter() .map(|(_, e)| e) - .filter(|e| e.event.is_some() && e.event.as_ref().unwrap().kind == EventKind::TextNote) + .filter(|e| e.kind == EventKind::TextNote) .filter(|e| { if threaded { - e.in_reply_to.is_none() + e.replies_to().is_none() } else { true } - }) // only root events + }) .cloned() .collect(); Self::sort_feed(feed, threaded) } - fn sort_feed(mut feed: Vec, threaded: bool) -> Vec { + fn sort_feed(mut feed: Vec, threaded: bool) -> Vec { if threaded { - feed.sort_unstable_by(|a, b| b.last_reply_at.cmp(&a.last_reply_at)); - } else { feed.sort_unstable_by(|a, b| { - if a.event.is_some() && b.event.is_some() { - b.event - .as_ref() - .unwrap() - .created_at - .cmp(&a.event.as_ref().unwrap().created_at) - } else if a.event.is_some() { - std::cmp::Ordering::Greater - } else if b.event.is_some() { - std::cmp::Ordering::Less - } else { - std::cmp::Ordering::Equal - } + let a_last = GLOBALS.last_reply.blocking_lock().get(&a.id).cloned(); + let b_last = GLOBALS.last_reply.blocking_lock().get(&b.id).cloned(); + let a_time = a_last.unwrap_or(a.created_at); + let b_time = b_last.unwrap_or(b.created_at); + b_time.cmp(&a_time) }); + } else { + feed.sort_unstable_by(|a, b| b.created_at.cmp(&a.created_at)); } feed.iter().map(|e| e.id).collect() @@ -203,13 +188,25 @@ impl Globals { } } + pub fn get_replies_sync(id: Id) -> Vec { + let mut output: Vec = Vec::new(); + if let Some(vec) = GLOBALS.relationships.blocking_lock().get(&id) { + for (id, relationship) in vec.iter() { + if *relationship == Relationship::Reply { + output.push(*id); + } + } + } + + output + } + // FIXME - this allows people to react many times to the same event, and // it counts them all! - #[allow(dead_code)] - pub async fn get_reactions(id: Id) -> HashMap { + pub fn get_reactions_sync(id: Id) -> HashMap { let mut output: HashMap = HashMap::new(); - if let Some(relationships) = GLOBALS.relationships.lock().await.get(&id).cloned() { + if let Some(relationships) = GLOBALS.relationships.blocking_lock().get(&id).cloned() { for (_id, relationship) in relationships.iter() { if let Relationship::Reaction(reaction) = relationship { if let Some(ch) = reaction.chars().next() { diff --git a/src/main.rs b/src/main.rs index 5715be9d..d64c01dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,6 @@ mod comms; mod date_ago; mod db; mod error; -mod feed_event; mod globals; mod overlord; mod process; diff --git a/src/ui/feed.rs b/src/ui/feed.rs index b0b1580e..77191b99 100644 --- a/src/ui/feed.rs +++ b/src/ui/feed.rs @@ -1,5 +1,5 @@ use super::GossipUi; -use crate::globals::Globals; +use crate::globals::{Globals, GLOBALS}; use eframe::egui; use egui::{Align, Color32, Context, Layout, RichText, ScrollArea, TextStyle, Ui, Vec2}; use nostr_types::{EventKind, Id, PublicKey}; @@ -46,31 +46,21 @@ fn render_post( id: Id, indent: usize, ) { - let maybe_fevent = crate::globals::GLOBALS - .feed_events - .blocking_lock() - .get(&id) - .cloned(); - if maybe_fevent.is_none() { + let maybe_event = GLOBALS.events.blocking_lock().get(&id).cloned(); + if maybe_event.is_none() { return; } - let fevent = maybe_fevent.unwrap(); - - if fevent.event.is_none() { - return; - } // don't render related info w/o nostr event. - let event = fevent.event.as_ref().unwrap().to_owned(); + let event = maybe_event.unwrap(); // Only render TextNote events if event.kind != EventKind::TextNote { return; } - let maybe_person = crate::globals::GLOBALS - .people - .blocking_lock() - .get(&event.pubkey) - .cloned(); + let maybe_person = GLOBALS.people.blocking_lock().get(&event.pubkey).cloned(); + + let reactions = Globals::get_reactions_sync(event.id); + let replies = Globals::get_replies_sync(event.id); // Person Things we can render: // pubkey @@ -149,19 +139,25 @@ fn render_post( // Second row ui.horizontal(|ui| { - if fevent.reactions.upvotes > 0 { - ui.label( - RichText::new(&format!("+{}", fevent.reactions.upvotes)) - .text_style(TextStyle::Name("Bold".into())) - .color(Color32::DARK_GREEN), - ); - } - if fevent.reactions.downvotes > 0 { - ui.label( - RichText::new(&format!("-{}", fevent.reactions.downvotes)) - .text_style(TextStyle::Name("Bold".into())) - .color(Color32::DARK_RED), - ); + for (ch, count) in reactions.iter() { + if *ch == '+' { + ui.label( + RichText::new(&format!("{} {}", ch, count)) + .text_style(TextStyle::Name("Bold".into())) + .color(Color32::DARK_GREEN), + ); + } else if *ch == '-' { + ui.label( + RichText::new(&format!("{} {}", ch, count)) + .text_style(TextStyle::Name("Bold".into())) + .color(Color32::DARK_RED), + ); + } else { + ui.label( + RichText::new(&format!("{} {}", ch, count)) + .text_style(TextStyle::Name("Bold".into())), + ); + } } }); @@ -172,7 +168,7 @@ fn render_post( ui.separator(); if app.settings.view_threaded { - for reply_id in fevent.replies { + for reply_id in replies { render_post(app, _ctx, _frame, ui, reply_id, indent + 1); } }