Skip to content

Commit

Permalink
inbox indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedilger committed Dec 14, 2024
1 parent 9cffa10 commit 60932b3
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 64 deletions.
45 changes: 37 additions & 8 deletions gossip-bin/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1129,19 +1129,48 @@ impl GossipUi {
{
self.set_page(ctx, Page::Feed(FeedKind::Person(pubkey)));
}
if self
.add_selected_label(
ui,
self.page == Page::Feed(FeedKind::Inbox(self.inbox_include_indirect)),
"Inbox",
)
.clicked()
{

let response = self.add_selected_label(
ui,
self.page == Page::Feed(FeedKind::Inbox(self.inbox_include_indirect)),
"Inbox",
);
if response.clicked() {
self.set_page(
ctx,
Page::Feed(FeedKind::Inbox(self.inbox_include_indirect)),
);
}

// Add unread messages indicator for inbox
let count = GLOBALS.unread_inbox.load(Ordering::Relaxed);
if count > 0 {
let where_to_put_background = ui.painter().add(egui::Shape::Noop);
let pos = response.rect.right_center() + vec2(10.0, 1.0);
let text_color = if self.theme.dark_mode {
self.theme.neutral_900()
} else {
self.theme.neutral_100()
};
let bg_rect = ui
.painter()
.text(
pos,
egui::Align2::LEFT_CENTER,
format!("{}", count),
FontId::proportional(8.0),
text_color,
)
.expand2(vec2(5.0, 2.0))
.translate(vec2(0.0, -1.0)); // FIXME: Hack to fix the line height
let bg_shape = egui::Shape::rect_filled(
bg_rect,
egui::Rounding::same(bg_rect.height()),
self.theme.accent_color(),
);
ui.painter().set(where_to_put_background, bg_shape);
}

if self
.add_selected_label(
ui,
Expand Down
138 changes: 82 additions & 56 deletions gossip-lib/src/feed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub struct Feed {

current_feed_kind: Arc<RwLock<FeedKind>>,
current_feed_events: Arc<RwLock<Vec<Id>>>,
current_inbox_events: Arc<RwLock<Vec<Id>>>,
inbox_is_indirect: AtomicBool,
feed_anchors: DashMap<String, Unixtime>,

// We only recompute the feed at specified intervals (or when they switch)
Expand All @@ -53,6 +55,8 @@ impl Feed {
switching: AtomicBool::new(false),
current_feed_kind: Arc::new(RwLock::new(FeedKind::List(PersonList::Followed, false))),
current_feed_events: Arc::new(RwLock::new(Vec::new())),
current_inbox_events: Arc::new(RwLock::new(Vec::new())),
inbox_is_indirect: AtomicBool::new(false),
feed_anchors: DashMap::new(),
interval_ms: Arc::new(RwLock::new(10000)), // Every 10 seconds, until we load from settings
last_computed: Arc::new(RwLock::new(None)),
Expand All @@ -67,8 +71,15 @@ impl Feed {
/// This doesn't deal with minion subscriptions.
pub(crate) fn load_more(&self) -> Result<Unixtime, Error> {
let anchor_key = self.current_feed_kind.read_arc().anchor_key();

let current_events = if matches!(self.get_feed_kind(), FeedKind::Inbox(_)) {
&self.current_inbox_events
} else {
&self.current_feed_events
};

// Load the timestamp of the earliest event in the feed so far
if let Some(earliest_id) = self.current_feed_events.read_arc().iter().next_back() {
if let Some(earliest_id) = current_events.read_arc().iter().next_back() {
let earliest_event = GLOBALS.db().read_event(*earliest_id)?;
if let Some(event) = earliest_event {
// Move the anchor back to the earliest event we have so far
Expand Down Expand Up @@ -258,7 +269,16 @@ impl Feed {
/// Read the followed feed
pub fn get_feed_events(&self) -> Vec<Id> {
self.sync_maybe_periodic_recompute();
self.current_feed_events.read_arc().clone()
if matches!(self.get_feed_kind(), FeedKind::Inbox(_)) {
self.current_inbox_events.read_arc().clone()
} else {
self.current_feed_events.read_arc().clone()
}
}

/// Read the inbox
pub fn get_inbox_events(&self) -> Vec<Id> {
self.current_inbox_events.read_arc().clone()
}

pub fn get_last_computed_time(&self) -> Option<Instant> {
Expand Down Expand Up @@ -370,60 +390,8 @@ impl Feed {
*self.current_feed_events.write_arc() = GLOBALS.current_bookmarks.read().clone();
}
FeedKind::Inbox(indirect) => {
if let Some(my_pubkey) = GLOBALS.identity.public_key() {
// indirect = everything that 'p' tags me
// otherwise, only things that reply to my events
// (filter on Storage::is_my_event(id))
//
// We also might want to look where I am mentioned in the contents,
// BUT we would have to scan all events which is not cheap so we
// don't do this.

// All displayable events that 'p' tag me
let filter = {
let mut filter = Filter::new();
filter.kinds = feed_displayable_event_kinds(false);
filter.add_tag_value('p', my_pubkey.as_hex_string());
filter
};

let screen_spam = {
if GLOBALS.db().read_setting_apply_spam_filter_on_inbox() {
|event: &Event| {
use crate::spam_filter::{
filter_event, EventFilterAction, EventFilterCaller,
};
filter_event(event.clone(), EventFilterCaller::Inbox, false)
== EventFilterAction::Allow
}
} else {
|_: &Event| true
}
};

let screen = |e: &Event| {
screen_spam(e)
&& e.pubkey != my_pubkey
&& (indirect // don't screen further, keep all the 'p' tags
|| (
// Either it is a direct reply
match e.replies_to() {
None => false,
Some(EventReference::Id { id, .. }) =>
matches!(GLOBALS.db().is_my_event(id), Ok(true)),
Some(EventReference::Addr(NAddr { author, .. })) => author == my_pubkey,
}
|| // or we are referenced in the content
e.people_referenced_in_content()
.iter()
.any(|p| *p == my_pubkey)
))
};

let events =
Self::load_event_range(anchor, filter, true, false, screen).await?;
*self.current_feed_events.write_arc() = events;
}
// See below, we always recompute inbox
self.inbox_is_indirect.store(indirect, Ordering::Relaxed);
}
FeedKind::Thread { .. } => {
// Potentially update thread parent to a higher parent
Expand Down Expand Up @@ -476,6 +444,64 @@ impl Feed {
}
}

// We recompute the inbox always, because we need to watch for changes so we can update
// the notification light
if let Some(my_pubkey) = GLOBALS.identity.public_key() {
// indirect = everything that 'p' tags me
let indirect = self.inbox_is_indirect.load(Ordering::Relaxed);

// otherwise, only things that reply to my events
// (filter on Storage::is_my_event(id))
//
// We also might want to look where I am mentioned in the contents,
// BUT we would have to scan all events which is not cheap so we
// don't do this.

// All displayable events that 'p' tag me
let filter = {
let mut filter = Filter::new();
filter.kinds = feed_displayable_event_kinds(false);
filter.add_tag_value('p', my_pubkey.as_hex_string());
filter
};

let screen_spam = {
if GLOBALS.db().read_setting_apply_spam_filter_on_inbox() {
|event: &Event| {
use crate::spam_filter::{
filter_event, EventFilterAction, EventFilterCaller,
};
filter_event(event.clone(), EventFilterCaller::Inbox, false)
== EventFilterAction::Allow
}
} else {
|_: &Event| true
}
};

let screen = |e: &Event| {
screen_spam(e)
&& e.pubkey != my_pubkey
&& (indirect // don't screen further, keep all the 'p' tags
|| (
// Either it is a direct reply
match e.replies_to() {
None => false,
Some(EventReference::Id { id, .. }) =>
matches!(GLOBALS.db().is_my_event(id), Ok(true)),
Some(EventReference::Addr(NAddr { author, .. })) => author == my_pubkey,
}
|| // or we are referenced in the content
e.people_referenced_in_content()
.iter()
.any(|p| *p == my_pubkey)
))
};

let events = Self::load_event_range(anchor, filter, true, false, screen).await?;
*self.current_inbox_events.write_arc() = events;
}

*self.last_computed.write_arc() = Some(Instant::now());
self.recompute_lock.store(false, Ordering::Relaxed);
self.switching.store(false, Ordering::Relaxed);
Expand Down
4 changes: 4 additions & 0 deletions gossip-lib/src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ pub struct Globals {
/// How many unread direct messages
pub unread_dms: AtomicUsize,

/// Does inbox have new messages
pub unread_inbox: AtomicUsize,

/// Delegation handling
pub delegation: Delegation,

Expand Down Expand Up @@ -246,6 +249,7 @@ lazy_static! {
bytes_read: AtomicUsize::new(0),
open_subscriptions: AtomicUsize::new(0),
unread_dms: AtomicUsize::new(0),
unread_inbox: AtomicUsize::new(0),
delegation: Delegation::default(),
media: Media::new(),
events_being_searched_for: PRwLock::new(Vec::new()),
Expand Down
13 changes: 13 additions & 0 deletions gossip-lib/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,21 @@ async fn do_general_tasks(tick: usize) {
let unread = channels.iter().map(|c| c.unread_message_count).sum();
GLOBALS.unread_dms.store(unread, Ordering::Relaxed);
}

update_inbox_indicator().await;
}

// Update handlers for quick menu rendering
let _ = GLOBALS.update_handlers();
}

async fn update_inbox_indicator() {
let ids = GLOBALS.feed.get_inbox_events();
let mut count: usize = 0;
for id in ids {
if matches!(GLOBALS.db().is_event_viewed(id), Ok(false)) {
count += 1;
}
}
GLOBALS.unread_inbox.store(count, Ordering::Relaxed);
}

0 comments on commit 60932b3

Please sign in to comment.