Ring bell when mentioned
This commit is contained in:
parent
496cdde18d
commit
a17630aeaa
6 changed files with 65 additions and 9 deletions
|
|
@ -15,6 +15,10 @@ Procedure when bumping the version number:
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `bell_on_mention` config option
|
||||||
|
|
||||||
## v0.9.1 - 2025-03-01
|
## v0.9.1 - 2025-03-01
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
||||||
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -1646,8 +1646,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toss"
|
name = "toss"
|
||||||
version = "0.3.3"
|
version = "0.3.4"
|
||||||
source = "git+https://github.com/Garmelon/toss.git?tag=v0.3.3#96b2e13c4a4b0174601d90246d92d148c4230eeb"
|
source = "git+https://github.com/Garmelon/toss.git?tag=v0.3.4#57aa8c59308f6f0aa82bde415a42b56c3d6f7c4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ features = ["bot"]
|
||||||
|
|
||||||
[workspace.dependencies.toss]
|
[workspace.dependencies.toss]
|
||||||
git = "https://github.com/Garmelon/toss.git"
|
git = "https://github.com/Garmelon/toss.git"
|
||||||
tag = "v0.3.3"
|
tag = "v0.3.4"
|
||||||
|
|
||||||
[workspace.dependencies.vault]
|
[workspace.dependencies.vault]
|
||||||
git = "https://github.com/Garmelon/vault.git"
|
git = "https://github.com/Garmelon/vault.git"
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,10 @@ pub struct Config {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub rooms_sort_order: RoomsSortOrder,
|
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.
|
/// Time zone that chat timestamps should be displayed in.
|
||||||
///
|
///
|
||||||
/// This option can either be the string `"localtime"`, a [POSIX TZ string],
|
/// This option can either be the string `"localtime"`, a [POSIX TZ string],
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use cove_config::{Config, Keys};
|
||||||
use cove_input::InputEvent;
|
use cove_input::InputEvent;
|
||||||
use crossterm::style::Stylize;
|
use crossterm::style::Stylize;
|
||||||
use euphoxide::{
|
use euphoxide::{
|
||||||
api::{Data, Message, MessageId, PacketType, SessionId},
|
api::{Data, Message, MessageId, PacketType, SessionId, packet::ParsedPacket},
|
||||||
bot::instance::{Event, ServerConfig},
|
bot::instance::{ConnSnapshot, Event, ServerConfig},
|
||||||
conn::{self, Joined, Joining, SessionInfo},
|
conn::{self, Joined, Joining, SessionInfo},
|
||||||
};
|
};
|
||||||
use jiff::tz::TimeZone;
|
use jiff::tz::TimeZone;
|
||||||
|
|
@ -19,7 +19,7 @@ use toss::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
euph,
|
euph::{self, SpanType},
|
||||||
macros::logging_unwrap,
|
macros::logging_unwrap,
|
||||||
ui::{
|
ui::{
|
||||||
UiError, UiEvent,
|
UiError, UiEvent,
|
||||||
|
|
@ -73,6 +73,8 @@ pub struct EuphRoom {
|
||||||
last_msg_sent: Option<oneshot::Receiver<MessageId>>,
|
last_msg_sent: Option<oneshot::Receiver<MessageId>>,
|
||||||
|
|
||||||
nick_list: ListState<SessionId>,
|
nick_list: ListState<SessionId>,
|
||||||
|
|
||||||
|
mentioned: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EuphRoom {
|
impl EuphRoom {
|
||||||
|
|
@ -96,6 +98,7 @@ impl EuphRoom {
|
||||||
chat: ChatState::new(vault, tz),
|
chat: ChatState::new(vault, tz),
|
||||||
last_msg_sent: None,
|
last_msg_sent: None,
|
||||||
nick_list: ListState::new(),
|
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 {
|
pub async fn unseen_msgs_count(&self) -> usize {
|
||||||
logging_unwrap!(self.vault().unseen_msgs_count().await)
|
logging_unwrap!(self.vault().unseen_msgs_count().await)
|
||||||
}
|
}
|
||||||
|
|
@ -557,6 +566,35 @@ impl EuphRoom {
|
||||||
return false;
|
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
|
// We handle the packet internally first because the room event handling
|
||||||
// will consume it while we only need a reference.
|
// will consume it while we only need a reference.
|
||||||
let handled = if let Event::Packet(_, packet, _) = &event {
|
let handled = if let Event::Packet(_, packet, _) = &event {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use jiff::tz::TimeZone;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use toss::{
|
use toss::{
|
||||||
Style, Styled, Widget, WidgetExt,
|
Style, Styled, Widget, WidgetExt,
|
||||||
widgets::{BoxedAsync, Empty, Join2, Text},
|
widgets::{BellState, BoxedAsync, Empty, Join2, Text},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -95,6 +95,7 @@ pub struct Rooms {
|
||||||
|
|
||||||
list: ListState<RoomIdentifier>,
|
list: ListState<RoomIdentifier>,
|
||||||
order: Order,
|
order: Order,
|
||||||
|
bell: BellState,
|
||||||
|
|
||||||
euph_servers: HashMap<String, EuphServer>,
|
euph_servers: HashMap<String, EuphServer>,
|
||||||
euph_rooms: HashMap<RoomIdentifier, EuphRoom>,
|
euph_rooms: HashMap<RoomIdentifier, EuphRoom>,
|
||||||
|
|
@ -115,6 +116,7 @@ impl Rooms {
|
||||||
state: State::ShowList,
|
state: State::ShowList,
|
||||||
list: ListState::new(),
|
list: ListState::new(),
|
||||||
order: Order::from_rooms_sort_order(config.rooms_sort_order),
|
order: Order::from_rooms_sort_order(config.rooms_sort_order),
|
||||||
|
bell: BellState::new(),
|
||||||
euph_servers: HashMap::new(),
|
euph_servers: HashMap::new(),
|
||||||
euph_rooms: HashMap::new(),
|
euph_rooms: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
@ -244,7 +246,9 @@ impl Rooms {
|
||||||
.retain(|n, r| !r.stopped() || rooms_set.contains(n));
|
.retain(|n, r| !r.stopped() || rooms_set.contains(n));
|
||||||
|
|
||||||
for room in rooms_set {
|
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,
|
_ => self.stabilize_rooms().await,
|
||||||
}
|
}
|
||||||
|
|
||||||
match &mut self.state {
|
let widget = match &mut self.state {
|
||||||
State::ShowList => Self::rooms_widget(
|
State::ShowList => Self::rooms_widget(
|
||||||
&self.vault,
|
&self.vault,
|
||||||
self.config,
|
self.config,
|
||||||
|
|
@ -297,6 +301,12 @@ impl Rooms {
|
||||||
.below(delete.widget())
|
.below(delete.widget())
|
||||||
.desync()
|
.desync()
|
||||||
.boxed_async(),
|
.boxed_async(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.config.bell_on_mention {
|
||||||
|
widget.above(self.bell.widget().desync()).boxed_async()
|
||||||
|
} else {
|
||||||
|
widget
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue