Ring bell when mentioned

This commit is contained in:
Joscha 2025-03-08 19:21:01 +01:00
parent 496cdde18d
commit a17630aeaa
6 changed files with 65 additions and 9 deletions

View file

@ -15,6 +15,10 @@ Procedure when bumping the version number:
## Unreleased
### Added
- `bell_on_mention` config option
## v0.9.1 - 2025-03-01
### Fixed

4
Cargo.lock generated
View file

@ -1646,8 +1646,8 @@ dependencies = [
[[package]]
name = "toss"
version = "0.3.3"
source = "git+https://github.com/Garmelon/toss.git?tag=v0.3.3#96b2e13c4a4b0174601d90246d92d148c4230eeb"
version = "0.3.4"
source = "git+https://github.com/Garmelon/toss.git?tag=v0.3.4#57aa8c59308f6f0aa82bde415a42b56c3d6f7c4d"
dependencies = [
"async-trait",
"crossterm",

View file

@ -39,7 +39,7 @@ features = ["bot"]
[workspace.dependencies.toss]
git = "https://github.com/Garmelon/toss.git"
tag = "v0.3.3"
tag = "v0.3.4"
[workspace.dependencies.vault]
git = "https://github.com/Garmelon/vault.git"

View file

@ -100,6 +100,10 @@ pub struct Config {
#[serde(default)]
pub rooms_sort_order: RoomsSortOrder,
/// Ring the bell (character 0x07) when you are mentioned in a room.
#[serde(default)]
pub bell_on_mention: bool,
/// Time zone that chat timestamps should be displayed in.
///
/// This option can either be the string `"localtime"`, a [POSIX TZ string],

View file

@ -4,8 +4,8 @@ use cove_config::{Config, Keys};
use cove_input::InputEvent;
use crossterm::style::Stylize;
use euphoxide::{
api::{Data, Message, MessageId, PacketType, SessionId},
bot::instance::{Event, ServerConfig},
api::{Data, Message, MessageId, PacketType, SessionId, packet::ParsedPacket},
bot::instance::{ConnSnapshot, Event, ServerConfig},
conn::{self, Joined, Joining, SessionInfo},
};
use jiff::tz::TimeZone;
@ -19,7 +19,7 @@ use toss::{
};
use crate::{
euph,
euph::{self, SpanType},
macros::logging_unwrap,
ui::{
UiError, UiEvent,
@ -73,6 +73,8 @@ pub struct EuphRoom {
last_msg_sent: Option<oneshot::Receiver<MessageId>>,
nick_list: ListState<SessionId>,
mentioned: bool,
}
impl EuphRoom {
@ -96,6 +98,7 @@ impl EuphRoom {
chat: ChatState::new(vault, tz),
last_msg_sent: None,
nick_list: ListState::new(),
mentioned: false,
}
}
@ -164,6 +167,12 @@ impl EuphRoom {
}
}
pub fn retrieve_mentioned(&mut self) -> bool {
let mentioned = self.mentioned;
self.mentioned = false;
mentioned
}
pub async fn unseen_msgs_count(&self) -> usize {
logging_unwrap!(self.vault().unseen_msgs_count().await)
}
@ -557,6 +566,35 @@ impl EuphRoom {
return false;
}
if let Event::Packet(
_,
ParsedPacket {
content: Ok(Data::SendEvent(send)),
..
},
ConnSnapshot {
state: conn::State::Joined(joined),
..
},
) = &event
{
let normalized_name = euphoxide::nick::normalize(&joined.session.name);
let content = &*send.0.content;
for (rtype, rspan) in euph::find_spans(content) {
if rtype != SpanType::Mention {
continue;
}
let Some(mention) = content[rspan].strip_prefix('@') else {
continue;
};
let normalized_mention = euphoxide::nick::normalize(mention);
if normalized_name == normalized_mention {
self.mentioned = true;
break;
}
}
}
// We handle the packet internally first because the room event handling
// will consume it while we only need a reference.
let handled = if let Event::Packet(_, packet, _) = &event {

View file

@ -17,7 +17,7 @@ use jiff::tz::TimeZone;
use tokio::sync::mpsc;
use toss::{
Style, Styled, Widget, WidgetExt,
widgets::{BoxedAsync, Empty, Join2, Text},
widgets::{BellState, BoxedAsync, Empty, Join2, Text},
};
use crate::{
@ -95,6 +95,7 @@ pub struct Rooms {
list: ListState<RoomIdentifier>,
order: Order,
bell: BellState,
euph_servers: HashMap<String, EuphServer>,
euph_rooms: HashMap<RoomIdentifier, EuphRoom>,
@ -115,6 +116,7 @@ impl Rooms {
state: State::ShowList,
list: ListState::new(),
order: Order::from_rooms_sort_order(config.rooms_sort_order),
bell: BellState::new(),
euph_servers: HashMap::new(),
euph_rooms: HashMap::new(),
};
@ -244,7 +246,9 @@ impl Rooms {
.retain(|n, r| !r.stopped() || rooms_set.contains(n));
for room in rooms_set {
self.get_or_insert_room(room).await.retain();
let room = self.get_or_insert_room(room).await;
room.retain();
self.bell.ring |= room.retrieve_mentioned();
}
}
@ -254,7 +258,7 @@ impl Rooms {
_ => self.stabilize_rooms().await,
}
match &mut self.state {
let widget = match &mut self.state {
State::ShowList => Self::rooms_widget(
&self.vault,
self.config,
@ -297,6 +301,12 @@ impl Rooms {
.below(delete.widget())
.desync()
.boxed_async(),
};
if self.config.bell_on_mention {
widget.above(self.bell.widget().desync()).boxed_async()
} else {
widget
}
}