diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d87d77..76fa94a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ Procedure when bumping the version number: ## Unreleased +### Changed + +- Display emoji user id hashes in the nick list + ## v0.9.3 - 2025-05-31 ### Added diff --git a/cove/src/euph/small_message.rs b/cove/src/euph/small_message.rs index d306226..5db1790 100644 --- a/cove/src/euph/small_message.rs +++ b/cove/src/euph/small_message.rs @@ -1,5 +1,3 @@ -use std::hash::{DefaultHasher, Hash, Hasher}; - use crossterm::style::Stylize; use euphoxide::api::{MessageId, Snowflake, Time, UserId}; use jiff::Timestamp; @@ -77,11 +75,7 @@ impl Msg for SmallMessage { } fn nick_emoji(&self) -> Option { - let mut hasher = DefaultHasher::new(); - self.user_id.0.hash(&mut hasher); - let hash = hasher.finish(); - let emoji = &util::EMOJI_LIST[hash as usize % util::EMOJI_LIST.len()]; - Some(emoji.clone()) + Some(util::user_id_emoji(&self.user_id)) } } diff --git a/cove/src/euph/util.rs b/cove/src/euph/util.rs index ecea304..ea1782a 100644 --- a/cove/src/euph/util.rs +++ b/cove/src/euph/util.rs @@ -1,7 +1,11 @@ -use std::{collections::HashSet, sync::LazyLock}; +use std::{ + collections::HashSet, + hash::{DefaultHasher, Hash, Hasher}, + sync::LazyLock, +}; use crossterm::style::{Color, Stylize}; -use euphoxide::Emoji; +use euphoxide::{Emoji, api::UserId}; use toss::{Style, Styled}; pub static EMOJI: LazyLock = LazyLock::new(Emoji::load); @@ -82,3 +86,11 @@ pub fn style_mention_exact(mention: &str, base: Style) -> Styled { .expect("mention must start with @"); Styled::new(mention, nick_style(nick, base)) } + +pub fn user_id_emoji(user_id: &UserId) -> String { + let mut hasher = DefaultHasher::new(); + user_id.0.hash(&mut hasher); + let hash = hasher.finish(); + let emoji = &EMOJI_LIST[hash as usize % EMOJI_LIST.len()]; + emoji.clone() +} diff --git a/cove/src/ui/chat.rs b/cove/src/ui/chat.rs index 02adeb7..1116935 100644 --- a/cove/src/ui/chat.rs +++ b/cove/src/ui/chat.rs @@ -58,6 +58,10 @@ impl + Clone> ChatState { store, } } + + pub fn nick_emoji(&self) -> bool { + self.nick_emoji + } } impl> ChatState { diff --git a/cove/src/ui/euph/nick_list.rs b/cove/src/ui/euph/nick_list.rs index e1e4e3d..8fbdb7b 100644 --- a/cove/src/ui/euph/nick_list.rs +++ b/cove/src/ui/euph/nick_list.rs @@ -22,9 +22,10 @@ pub fn widget<'a>( list: &'a mut ListState, joined: &Joined, focused: bool, + nick_emoji: bool, ) -> impl Widget + use<'a> { let mut list_builder = ListBuilder::new(); - render_rows(&mut list_builder, joined, focused); + render_rows(&mut list_builder, joined, focused, nick_emoji); list_builder.build(list) } @@ -70,6 +71,7 @@ fn render_rows( list_builder: &mut ListBuilder<'_, SessionId, Background>, joined: &Joined, focused: bool, + nick_emoji: bool, ) { let mut people = vec![]; let mut bots = vec![]; @@ -95,10 +97,38 @@ fn render_rows( lurkers.sort_unstable(); nurkers.sort_unstable(); - render_section(list_builder, "People", &people, &joined.session, focused); - render_section(list_builder, "Bots", &bots, &joined.session, focused); - render_section(list_builder, "Lurkers", &lurkers, &joined.session, focused); - render_section(list_builder, "Nurkers", &nurkers, &joined.session, focused); + render_section( + list_builder, + "People", + &people, + &joined.session, + focused, + nick_emoji, + ); + render_section( + list_builder, + "Bots", + &bots, + &joined.session, + focused, + nick_emoji, + ); + render_section( + list_builder, + "Lurkers", + &lurkers, + &joined.session, + focused, + nick_emoji, + ); + render_section( + list_builder, + "Nurkers", + &nurkers, + &joined.session, + focused, + nick_emoji, + ); } fn render_section( @@ -107,6 +137,7 @@ fn render_section( sessions: &[HalfSession], own_session: &SessionView, focused: bool, + nick_emoji: bool, ) { if sessions.is_empty() { return; @@ -124,7 +155,7 @@ fn render_section( list_builder.add_unsel(Text::new(row).background()); for session in sessions { - render_row(list_builder, session, own_session, focused); + render_row(list_builder, session, own_session, focused, nick_emoji); } } @@ -133,6 +164,7 @@ fn render_row( session: &HalfSession, own_session: &SessionView, focused: bool, + nick_emoji: bool, ) { let (name, style, style_inv, perms_style_inv) = if session.name.is_empty() { let name = "lurk".to_string(); @@ -166,16 +198,24 @@ fn render_row( " " }; + let emoji = if nick_emoji { + format!(" ({})", euph::user_id_emoji(&session.id)) + } else { + "".to_string() + }; + list_builder.add_sel(session.session_id.clone(), move |selected| { if focused && selected { let text = Styled::new_plain(owner) .then(name, style_inv) - .then(perms, perms_style_inv); + .then(perms, perms_style_inv) + .then(emoji, perms_style_inv); Text::new(text).background().with_style(style_inv) } else { let text = Styled::new_plain(owner) .then(&name, style) - .then_plain(perms); + .then_plain(perms) + .then_plain(emoji); Text::new(text).background() } }); diff --git a/cove/src/ui/euph/room.rs b/cove/src/ui/euph/room.rs index ebae5a8..fe1f768 100644 --- a/cove/src/ui/euph/room.rs +++ b/cove/src/ui/euph/room.rs @@ -291,11 +291,16 @@ impl EuphRoom { joined: &Joined, focus: Focus, ) -> BoxedAsync<'a, UiError> { - let nick_list_widget = nick_list::widget(nick_list, joined, focus == Focus::NickList) - .padding() - .with_right(1) - .border() - .desync(); + let nick_list_widget = nick_list::widget( + nick_list, + joined, + focus == Focus::NickList, + chat.nick_emoji(), + ) + .padding() + .with_right(1) + .border() + .desync(); let chat_widget = chat.widget(joined.session.name.clone(), focus == Focus::Chat);