mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-20 05:39:52 -07:00
Support hiding server part of username in message scrollback (#71)
This commit is contained in:
parent
61aba80be1
commit
64891ec68f
8 changed files with 164 additions and 37 deletions
13
src/base.rs
13
src/base.rs
|
@ -445,6 +445,9 @@ pub struct RoomInfo {
|
||||||
|
|
||||||
/// Users currently typing in this room, and when we received notification of them doing so.
|
/// Users currently typing in this room, and when we received notification of them doing so.
|
||||||
pub users_typing: Option<(Instant, Vec<OwnedUserId>)>,
|
pub users_typing: Option<(Instant, Vec<OwnedUserId>)>,
|
||||||
|
|
||||||
|
/// The display names for users in this room.
|
||||||
|
pub display_names: HashMap<OwnedUserId, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomInfo {
|
impl RoomInfo {
|
||||||
|
@ -583,13 +586,13 @@ impl RoomInfo {
|
||||||
match n {
|
match n {
|
||||||
0 => Spans(vec![]),
|
0 => Spans(vec![]),
|
||||||
1 => {
|
1 => {
|
||||||
let user = settings.get_user_span(typers[0].as_ref());
|
let user = settings.get_user_span(typers[0].as_ref(), self);
|
||||||
|
|
||||||
Spans(vec![user, Span::from(" is typing...")])
|
Spans(vec![user, Span::from(" is typing...")])
|
||||||
},
|
},
|
||||||
2 => {
|
2 => {
|
||||||
let user1 = settings.get_user_span(typers[0].as_ref());
|
let user1 = settings.get_user_span(typers[0].as_ref(), self);
|
||||||
let user2 = settings.get_user_span(typers[1].as_ref());
|
let user2 = settings.get_user_span(typers[1].as_ref(), self);
|
||||||
|
|
||||||
Spans(vec![
|
Spans(vec![
|
||||||
user1,
|
user1,
|
||||||
|
@ -835,11 +838,11 @@ impl<'de> Visitor<'de> for IambIdVisitor {
|
||||||
},
|
},
|
||||||
Some("members") => {
|
Some("members") => {
|
||||||
let Some(path) = url.path_segments() else {
|
let Some(path) = url.path_segments() else {
|
||||||
return Err(E::custom( "Invalid members window URL"));
|
return Err(E::custom("Invalid members window URL"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let &[room_id] = path.collect::<Vec<_>>().as_slice() else {
|
let &[room_id] = path.collect::<Vec<_>>().as_slice() else {
|
||||||
return Err(E::custom( "Invalid members window URL"));
|
return Err(E::custom("Invalid members window URL"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(room_id) = OwnedRoomId::try_from(room_id) else {
|
let Ok(room_id) = OwnedRoomId::try_from(room_id) else {
|
||||||
|
|
|
@ -19,7 +19,7 @@ use modalkit::tui::{
|
||||||
text::Span,
|
text::Span,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::base::IambId;
|
use super::base::{IambId, RoomInfo};
|
||||||
|
|
||||||
macro_rules! usage {
|
macro_rules! usage {
|
||||||
( $($args: tt)* ) => {
|
( $($args: tt)* ) => {
|
||||||
|
@ -227,6 +227,24 @@ fn merge_users(a: Option<UserOverrides>, b: Option<UserOverrides>) -> Option<Use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum UserDisplayStyle {
|
||||||
|
// The Matrix username for the sender (e.g., "@user:example.com").
|
||||||
|
#[default]
|
||||||
|
Username,
|
||||||
|
|
||||||
|
// The localpart of the Matrix username (e.g., "@user").
|
||||||
|
LocalPart,
|
||||||
|
|
||||||
|
// The display name for the Matrix user, calculated according to the rules from the spec.
|
||||||
|
//
|
||||||
|
// This is usually something like "Ada Lovelace" if the user has configured a display name, but
|
||||||
|
// it can wind up being the Matrix username if there are display name collisions in the room,
|
||||||
|
// in order to avoid any confusion.
|
||||||
|
DisplayName,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TunableValues {
|
pub struct TunableValues {
|
||||||
pub log_level: Level,
|
pub log_level: Level,
|
||||||
|
@ -238,6 +256,7 @@ pub struct TunableValues {
|
||||||
pub typing_notice_send: bool,
|
pub typing_notice_send: bool,
|
||||||
pub typing_notice_display: bool,
|
pub typing_notice_display: bool,
|
||||||
pub users: UserOverrides,
|
pub users: UserOverrides,
|
||||||
|
pub username_display: UserDisplayStyle,
|
||||||
pub default_room: Option<String>,
|
pub default_room: Option<String>,
|
||||||
pub open_command: Option<Vec<String>>,
|
pub open_command: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
@ -253,6 +272,7 @@ pub struct Tunables {
|
||||||
pub typing_notice_send: Option<bool>,
|
pub typing_notice_send: Option<bool>,
|
||||||
pub typing_notice_display: Option<bool>,
|
pub typing_notice_display: Option<bool>,
|
||||||
pub users: Option<UserOverrides>,
|
pub users: Option<UserOverrides>,
|
||||||
|
pub username_display: Option<UserDisplayStyle>,
|
||||||
pub default_room: Option<String>,
|
pub default_room: Option<String>,
|
||||||
pub open_command: Option<Vec<String>>,
|
pub open_command: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
@ -271,6 +291,7 @@ impl Tunables {
|
||||||
typing_notice_send: self.typing_notice_send.or(other.typing_notice_send),
|
typing_notice_send: self.typing_notice_send.or(other.typing_notice_send),
|
||||||
typing_notice_display: self.typing_notice_display.or(other.typing_notice_display),
|
typing_notice_display: self.typing_notice_display.or(other.typing_notice_display),
|
||||||
users: merge_users(self.users, other.users),
|
users: merge_users(self.users, other.users),
|
||||||
|
username_display: self.username_display.or(other.username_display),
|
||||||
default_room: self.default_room.or(other.default_room),
|
default_room: self.default_room.or(other.default_room),
|
||||||
open_command: self.open_command.or(other.open_command),
|
open_command: self.open_command.or(other.open_command),
|
||||||
}
|
}
|
||||||
|
@ -287,6 +308,7 @@ impl Tunables {
|
||||||
typing_notice_send: self.typing_notice_send.unwrap_or(true),
|
typing_notice_send: self.typing_notice_send.unwrap_or(true),
|
||||||
typing_notice_display: self.typing_notice_display.unwrap_or(true),
|
typing_notice_display: self.typing_notice_display.unwrap_or(true),
|
||||||
users: self.users.unwrap_or_default(),
|
users: self.users.unwrap_or_default(),
|
||||||
|
username_display: self.username_display.unwrap_or_default(),
|
||||||
default_room: self.default_room,
|
default_room: self.default_room,
|
||||||
open_command: self.open_command,
|
open_command: self.open_command,
|
||||||
}
|
}
|
||||||
|
@ -525,18 +547,45 @@ impl ApplicationSettings {
|
||||||
Span::styled(String::from(c), style)
|
Span::styled(String::from(c), style)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_user_span<'a>(&self, user_id: &'a UserId) -> Span<'a> {
|
pub fn get_user_overrides(
|
||||||
let (color, name) = self
|
&self,
|
||||||
.tunables
|
user_id: &UserId,
|
||||||
|
) -> (Option<Color>, Option<Cow<'static, str>>) {
|
||||||
|
self.tunables
|
||||||
.users
|
.users
|
||||||
.get(user_id)
|
.get(user_id)
|
||||||
.map(|user| (user.color.as_ref().map(|c| c.0), user.name.clone().map(Cow::Owned)))
|
.map(|user| (user.color.as_ref().map(|c| c.0), user.name.clone().map(Cow::Owned)))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
let user_id = user_id.as_str();
|
pub fn get_user_style(&self, user_id: &UserId) -> Style {
|
||||||
let color = color.unwrap_or_else(|| user_color(user_id));
|
let color = self
|
||||||
|
.tunables
|
||||||
|
.users
|
||||||
|
.get(user_id)
|
||||||
|
.and_then(|user| user.color.as_ref().map(|c| c.0))
|
||||||
|
.unwrap_or_else(|| user_color(user_id.as_str()));
|
||||||
|
|
||||||
|
user_style_from_color(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_user_span<'a>(&self, user_id: &'a UserId, info: &'a RoomInfo) -> Span<'a> {
|
||||||
|
let (color, name) = self.get_user_overrides(user_id);
|
||||||
|
|
||||||
|
let color = color.unwrap_or_else(|| user_color(user_id.as_str()));
|
||||||
let style = user_style_from_color(color);
|
let style = user_style_from_color(color);
|
||||||
let name = name.unwrap_or(Cow::Borrowed(user_id));
|
let name = match (name, &self.tunables.username_display) {
|
||||||
|
(Some(name), _) => name,
|
||||||
|
(None, UserDisplayStyle::Username) => Cow::Borrowed(user_id.as_str()),
|
||||||
|
(None, UserDisplayStyle::LocalPart) => Cow::Borrowed(user_id.localpart()),
|
||||||
|
(None, UserDisplayStyle::DisplayName) => {
|
||||||
|
if let Some(display) = info.display_names.get(user_id) {
|
||||||
|
Cow::Borrowed(display.as_str())
|
||||||
|
} else {
|
||||||
|
Cow::Borrowed(user_id.as_str())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
Span::styled(name, style)
|
Span::styled(name, style)
|
||||||
}
|
}
|
||||||
|
@ -641,6 +690,19 @@ mod tests {
|
||||||
assert_eq!(res.users, Some(users.into_iter().collect()));
|
assert_eq!(res.users, Some(users.into_iter().collect()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_tunables_username_display() {
|
||||||
|
let res: Tunables = serde_json::from_str("{\"username_display\": \"username\"}").unwrap();
|
||||||
|
assert_eq!(res.username_display, Some(UserDisplayStyle::Username));
|
||||||
|
|
||||||
|
let res: Tunables = serde_json::from_str("{\"username_display\": \"localpart\"}").unwrap();
|
||||||
|
assert_eq!(res.username_display, Some(UserDisplayStyle::LocalPart));
|
||||||
|
|
||||||
|
let res: Tunables =
|
||||||
|
serde_json::from_str("{\"username_display\": \"displayname\"}").unwrap();
|
||||||
|
assert_eq!(res.username_display, Some(UserDisplayStyle::DisplayName));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_layout() {
|
fn test_parse_layout() {
|
||||||
let user = WindowPath::UserId(user_id!("@user:example.com").to_owned());
|
let user = WindowPath::UserId(user_id!("@user:example.com").to_owned());
|
||||||
|
|
|
@ -644,7 +644,7 @@ impl Message {
|
||||||
{
|
{
|
||||||
let cols = MessageColumns::Four;
|
let cols = MessageColumns::Four;
|
||||||
let fill = width - USER_GUTTER - TIME_GUTTER - READ_GUTTER;
|
let fill = width - USER_GUTTER - TIME_GUTTER - READ_GUTTER;
|
||||||
let user = self.show_sender(prev, true, settings);
|
let user = self.show_sender(prev, true, info, settings);
|
||||||
let time = self.timestamp.show_time();
|
let time = self.timestamp.show_time();
|
||||||
let read = match info.receipts.get(self.event.event_id()) {
|
let read = match info.receipts.get(self.event.event_id()) {
|
||||||
Some(read) => read.iter(),
|
Some(read) => read.iter(),
|
||||||
|
@ -655,7 +655,7 @@ impl Message {
|
||||||
} else if USER_GUTTER + TIME_GUTTER + MIN_MSG_LEN <= width {
|
} else if USER_GUTTER + TIME_GUTTER + MIN_MSG_LEN <= width {
|
||||||
let cols = MessageColumns::Three;
|
let cols = MessageColumns::Three;
|
||||||
let fill = width - USER_GUTTER - TIME_GUTTER;
|
let fill = width - USER_GUTTER - TIME_GUTTER;
|
||||||
let user = self.show_sender(prev, true, settings);
|
let user = self.show_sender(prev, true, info, settings);
|
||||||
let time = self.timestamp.show_time();
|
let time = self.timestamp.show_time();
|
||||||
let read = [].iter();
|
let read = [].iter();
|
||||||
|
|
||||||
|
@ -663,7 +663,7 @@ impl Message {
|
||||||
} else if USER_GUTTER + MIN_MSG_LEN <= width {
|
} else if USER_GUTTER + MIN_MSG_LEN <= width {
|
||||||
let cols = MessageColumns::Two;
|
let cols = MessageColumns::Two;
|
||||||
let fill = width - USER_GUTTER;
|
let fill = width - USER_GUTTER;
|
||||||
let user = self.show_sender(prev, true, settings);
|
let user = self.show_sender(prev, true, info, settings);
|
||||||
let time = None;
|
let time = None;
|
||||||
let read = [].iter();
|
let read = [].iter();
|
||||||
|
|
||||||
|
@ -671,7 +671,7 @@ impl Message {
|
||||||
} else {
|
} else {
|
||||||
let cols = MessageColumns::One;
|
let cols = MessageColumns::One;
|
||||||
let fill = width.saturating_sub(2);
|
let fill = width.saturating_sub(2);
|
||||||
let user = self.show_sender(prev, false, settings);
|
let user = self.show_sender(prev, false, info, settings);
|
||||||
let time = None;
|
let time = None;
|
||||||
let read = [].iter();
|
let read = [].iter();
|
||||||
|
|
||||||
|
@ -700,7 +700,7 @@ impl Message {
|
||||||
if let Some(r) = &reply {
|
if let Some(r) = &reply {
|
||||||
let w = width.saturating_sub(2);
|
let w = width.saturating_sub(2);
|
||||||
let mut replied = r.show_msg(w, style, true);
|
let mut replied = r.show_msg(w, style, true);
|
||||||
let mut sender = r.sender_span(settings);
|
let mut sender = r.sender_span(info, settings);
|
||||||
let sender_width = UnicodeWidthStr::width(sender.content.as_ref());
|
let sender_width = UnicodeWidthStr::width(sender.content.as_ref());
|
||||||
let trailing = w.saturating_sub(sender_width + 1);
|
let trailing = w.saturating_sub(sender_width + 1);
|
||||||
|
|
||||||
|
@ -793,16 +793,21 @@ impl Message {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sender_span(&self, settings: &ApplicationSettings) -> Span {
|
fn sender_span<'a>(
|
||||||
settings.get_user_span(self.sender.as_ref())
|
&'a self,
|
||||||
|
info: &'a RoomInfo,
|
||||||
|
settings: &'a ApplicationSettings,
|
||||||
|
) -> Span<'a> {
|
||||||
|
settings.get_user_span(self.sender.as_ref(), info)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_sender(
|
fn show_sender<'a>(
|
||||||
&self,
|
&'a self,
|
||||||
prev: Option<&Message>,
|
prev: Option<&Message>,
|
||||||
align_right: bool,
|
align_right: bool,
|
||||||
settings: &ApplicationSettings,
|
info: &'a RoomInfo,
|
||||||
) -> Option<Span> {
|
settings: &'a ApplicationSettings,
|
||||||
|
) -> Option<Span<'a>> {
|
||||||
if let Some(prev) = prev {
|
if let Some(prev) = prev {
|
||||||
if self.sender == prev.sender &&
|
if self.sender == prev.sender &&
|
||||||
self.timestamp.same_day(&prev.timestamp) &&
|
self.timestamp.same_day(&prev.timestamp) &&
|
||||||
|
@ -812,7 +817,7 @@ impl Message {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Span { content, style } = self.sender_span(settings);
|
let Span { content, style } = self.sender_span(info, settings);
|
||||||
let stop = content.len().min(28);
|
let stop = content.len().min(28);
|
||||||
let s = &content[..stop];
|
let s = &content[..stop];
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ use crate::{
|
||||||
ProfileConfig,
|
ProfileConfig,
|
||||||
TunableValues,
|
TunableValues,
|
||||||
UserColor,
|
UserColor,
|
||||||
|
UserDisplayStyle,
|
||||||
UserDisplayTunables,
|
UserDisplayTunables,
|
||||||
},
|
},
|
||||||
message::{
|
message::{
|
||||||
|
@ -160,6 +161,7 @@ pub fn mock_room() -> RoomInfo {
|
||||||
fetch_id: RoomFetchStatus::NotStarted,
|
fetch_id: RoomFetchStatus::NotStarted,
|
||||||
fetch_last: None,
|
fetch_last: None,
|
||||||
users_typing: None,
|
users_typing: None,
|
||||||
|
display_names: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +191,7 @@ pub fn mock_tunables() -> TunableValues {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<HashMap<_, _>>(),
|
.collect::<HashMap<_, _>>(),
|
||||||
open_command: None,
|
open_command: None,
|
||||||
|
username_display: UserDisplayStyle::Username,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -409,7 +409,7 @@ impl WindowOps<IambInfo> for IambWindow {
|
||||||
|
|
||||||
if need_fetch {
|
if need_fetch {
|
||||||
if let Ok(mems) = store.application.worker.members(room_id.clone()) {
|
if let Ok(mems) = store.application.worker.members(room_id.clone()) {
|
||||||
let items = mems.into_iter().map(MemberItem::new);
|
let items = mems.into_iter().map(|m| MemberItem::new(m, room_id.clone()));
|
||||||
state.set(items.collect());
|
state.set(items.collect());
|
||||||
*last_fetch = Some(Instant::now());
|
*last_fetch = Some(Instant::now());
|
||||||
}
|
}
|
||||||
|
@ -1100,11 +1100,12 @@ impl Promptable<ProgramContext, ProgramStore, IambInfo> for VerifyItem {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MemberItem {
|
pub struct MemberItem {
|
||||||
member: RoomMember,
|
member: RoomMember,
|
||||||
|
room_id: OwnedRoomId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemberItem {
|
impl MemberItem {
|
||||||
fn new(member: RoomMember) -> Self {
|
fn new(member: RoomMember, room_id: OwnedRoomId) -> Self {
|
||||||
Self { member }
|
Self { member, room_id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1121,12 +1122,32 @@ impl ListItem<IambInfo> for MemberItem {
|
||||||
_: &ViewportContext<ListCursor>,
|
_: &ViewportContext<ListCursor>,
|
||||||
store: &mut ProgramStore,
|
store: &mut ProgramStore,
|
||||||
) -> Text {
|
) -> Text {
|
||||||
let mut user = store.application.settings.get_user_span(self.member.user_id());
|
let info = store.application.rooms.get_or_default(self.room_id.clone());
|
||||||
|
let user_id = self.member.user_id();
|
||||||
|
|
||||||
|
let (color, name) = store.application.settings.get_user_overrides(self.member.user_id());
|
||||||
|
let color = color.unwrap_or_else(|| super::config::user_color(user_id.as_str()));
|
||||||
|
let mut style = super::config::user_style_from_color(color);
|
||||||
|
|
||||||
if selected {
|
if selected {
|
||||||
user.style = user.style.add_modifier(StyleModifier::REVERSED);
|
style = style.add_modifier(StyleModifier::REVERSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut spans = vec![];
|
||||||
|
let mut parens = false;
|
||||||
|
|
||||||
|
if let Some(name) = name {
|
||||||
|
spans.push(Span::styled(name, style));
|
||||||
|
parens = true;
|
||||||
|
} else if let Some(display) = info.display_names.get(user_id) {
|
||||||
|
spans.push(Span::styled(display.clone(), style));
|
||||||
|
parens = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
spans.extend(parens.then_some(Span::styled(" (", style)));
|
||||||
|
spans.push(Span::styled(user_id.as_str(), style));
|
||||||
|
spans.extend(parens.then_some(Span::styled(")", style)));
|
||||||
|
|
||||||
let state = match self.member.membership() {
|
let state = match self.member.membership() {
|
||||||
MembershipState::Ban => Span::raw(" (banned)").into(),
|
MembershipState::Ban => Span::raw(" (banned)").into(),
|
||||||
MembershipState::Invite => Span::raw(" (invited)").into(),
|
MembershipState::Invite => Span::raw(" (invited)").into(),
|
||||||
|
@ -1136,11 +1157,9 @@ impl ListItem<IambInfo> for MemberItem {
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(state) = state {
|
spans.extend(state);
|
||||||
Spans(vec![user, state]).into()
|
|
||||||
} else {
|
return Spans(spans).into();
|
||||||
user.into()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_word(&self) -> Option<String> {
|
fn get_word(&self) -> Option<String> {
|
||||||
|
|
|
@ -808,7 +808,8 @@ impl<'a> StatefulWidget for Chat<'a> {
|
||||||
state.reply_to.as_ref().and_then(|k| {
|
state.reply_to.as_ref().and_then(|k| {
|
||||||
let room = self.store.application.rooms.get(state.id())?;
|
let room = self.store.application.rooms.get(state.id())?;
|
||||||
let msg = room.messages.get(k)?;
|
let msg = room.messages.get(k)?;
|
||||||
let user = self.store.application.settings.get_user_span(msg.sender.as_ref());
|
let user =
|
||||||
|
self.store.application.settings.get_user_span(msg.sender.as_ref(), room);
|
||||||
let prefix = if editing.is_some() {
|
let prefix = if editing.is_some() {
|
||||||
Span::from("Editing reply to ")
|
Span::from("Editing reply to ")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -139,8 +139,9 @@ impl RoomState {
|
||||||
let mut invited = vec![Span::from(format!("You have been invited to join {name}"))];
|
let mut invited = vec![Span::from(format!("You have been invited to join {name}"))];
|
||||||
|
|
||||||
if let Ok(Some(inviter)) = &inviter {
|
if let Ok(Some(inviter)) = &inviter {
|
||||||
|
let info = store.application.rooms.get_or_default(self.id().to_owned());
|
||||||
invited.push(Span::from(" by "));
|
invited.push(Span::from(" by "));
|
||||||
invited.push(store.application.settings.get_user_span(inviter.user_id()));
|
invited.push(store.application.settings.get_user_span(inviter.user_id(), info));
|
||||||
}
|
}
|
||||||
|
|
||||||
let l1 = Spans(invited);
|
let l1 = Spans(invited);
|
||||||
|
|
|
@ -40,6 +40,7 @@ use matrix_sdk::{
|
||||||
reaction::ReactionEventContent,
|
reaction::ReactionEventContent,
|
||||||
room::{
|
room::{
|
||||||
encryption::RoomEncryptionEventContent,
|
encryption::RoomEncryptionEventContent,
|
||||||
|
member::OriginalSyncRoomMemberEvent,
|
||||||
message::{MessageType, RoomMessageEventContent},
|
message::{MessageType, RoomMessageEventContent},
|
||||||
name::RoomNameEventContent,
|
name::RoomNameEventContent,
|
||||||
redaction::{OriginalSyncRoomRedactionEvent, SyncRoomRedactionEvent},
|
redaction::{OriginalSyncRoomRedactionEvent, SyncRoomRedactionEvent},
|
||||||
|
@ -838,6 +839,38 @@ impl ClientWorker {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let _ = self.client.add_event_handler(
|
||||||
|
|ev: OriginalSyncRoomMemberEvent,
|
||||||
|
room: MatrixRoom,
|
||||||
|
client: Client,
|
||||||
|
store: Ctx<AsyncProgramStore>| {
|
||||||
|
async move {
|
||||||
|
let room_id = room.room_id();
|
||||||
|
let user_id = ev.state_key;
|
||||||
|
|
||||||
|
let ambiguous_name =
|
||||||
|
ev.content.displayname.as_deref().unwrap_or_else(|| user_id.localpart());
|
||||||
|
let ambiguous = client
|
||||||
|
.store()
|
||||||
|
.get_users_with_display_name(room_id, ambiguous_name)
|
||||||
|
.await
|
||||||
|
.map(|users| users.len() > 1)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut locked = store.lock().await;
|
||||||
|
let info = locked.application.get_room_info(room_id.to_owned());
|
||||||
|
|
||||||
|
if ambiguous {
|
||||||
|
info.display_names.remove(&user_id);
|
||||||
|
} else if let Some(display) = ev.content.displayname {
|
||||||
|
info.display_names.insert(user_id, display);
|
||||||
|
} else {
|
||||||
|
info.display_names.remove(&user_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let _ = self.client.add_event_handler(
|
let _ = self.client.add_event_handler(
|
||||||
|ev: OriginalSyncKeyVerificationStartEvent,
|
|ev: OriginalSyncKeyVerificationStartEvent,
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue