commit 893fd582dcba072cf6b305700a7bad94db82d145
parent 2edba9942ca1de00ca0945b613f38a841afb0f49
Author: William Casarin <jb55@jb55.com>
Date: Sun, 21 Apr 2024 15:55:47 -0700
profiles: introduce DisplayNames
This is exactly the same as the DisplayName enum in Damus iOS. Due to
the various inconsistencies in `name` and `display_name` between
clients, we have to generalize DisplayName into two variants: one name
or two names.
If we have two names, we treat it in the standard way of display_name is
the real name, and `name` is the username.
If only one is set, then it is considered both the username and "real name".
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
4 files changed, 56 insertions(+), 19 deletions(-)
diff --git a/src/lib.rs b/src/lib.rs
@@ -31,6 +31,7 @@ mod test_utils;
pub use app::Damus;
pub use error::Error;
+pub use profile::DisplayName;
#[cfg(target_os = "android")]
use winit::platform::android::EventLoopBuilderExtAndroid;
diff --git a/src/profile.rs b/src/profile.rs
@@ -1,17 +1,39 @@
use nostrdb::ProfileRecord;
-pub fn get_profile_name<'a>(record: &'a ProfileRecord) -> Option<&'a str> {
- let profile = record.record().profile()?;
- let display_name = profile.display_name();
- let name = profile.name();
+pub enum DisplayName<'a> {
+ One(&'a str),
- if display_name.is_some() && display_name.unwrap() != "" {
- return display_name;
- }
+ Both {
+ username: &'a str,
+ display_name: &'a str,
+ },
+}
- if name.is_some() && name.unwrap() != "" {
- return name;
+impl<'a> DisplayName<'a> {
+ pub fn username(&self) -> &'a str {
+ match self {
+ Self::One(n) => n,
+ Self::Both { username, .. } => username,
+ }
}
+}
- None
+fn is_empty(s: &str) -> bool {
+ s.chars().all(|c| c.is_whitespace())
+}
+
+pub fn get_profile_name<'a>(record: &'a ProfileRecord) -> Option<DisplayName<'a>> {
+ let profile = record.record().profile()?;
+ let display_name = profile.display_name().filter(|n| !is_empty(n));
+ let name = profile.name().filter(|n| !is_empty(n));
+
+ match (display_name, name) {
+ (None, None) => None,
+ (Some(disp), None) => Some(DisplayName::One(disp)),
+ (None, Some(username)) => Some(DisplayName::One(username)),
+ (Some(display_name), Some(username)) => Some(DisplayName::Both {
+ display_name,
+ username,
+ }),
+ }
}
diff --git a/src/ui/note/contents.rs b/src/ui/note/contents.rs
@@ -129,19 +129,17 @@ fn render_note_contents(
let name: String = if let Some(name) =
profile.as_ref().and_then(crate::profile::get_profile_name)
{
- format!("@{}", name)
+ format!("@{}", name.username())
} else {
- "@nostrich".to_string()
+ "??".to_string()
};
let resp = ui.colored_label(colors::PURPLE, &name);
if let Some(rec) = profile.as_ref() {
resp.on_hover_ui_at_pointer(|ui| {
- egui::Frame::default().show(ui, |ui| {
- ui.set_max_width(300.0);
- ui.add(ui::ProfilePreview::new(rec));
- });
+ ui.set_max_width(300.0);
+ ui.add(ui::ProfilePreview::new(rec));
});
}
});
diff --git a/src/ui/profile/preview.rs b/src/ui/profile/preview.rs
@@ -1,5 +1,6 @@
use crate::app_style::NotedeckTextStyle;
use crate::images;
+use crate::DisplayName;
use egui::load::TexturePoll;
use egui::{RichText, Sense};
use egui_extras::Size;
@@ -58,14 +59,29 @@ impl<'a> ProfilePreview<'a> {
}
}
- fn body(ui: &mut egui::Ui, profile: &ProfileRecord<'_>) -> egui::Response {
+ fn body(ui: &mut egui::Ui, profile: &ProfileRecord<'_>) {
let name = if let Some(name) = crate::profile::get_profile_name(profile) {
name
} else {
- "nostrich"
+ DisplayName::One("??")
};
- ui.label(RichText::new(name).text_style(NotedeckTextStyle::Heading3.text_style()))
+ match name {
+ DisplayName::One(n) => {
+ ui.label(RichText::new(n).text_style(NotedeckTextStyle::Heading3.text_style()));
+ }
+
+ DisplayName::Both {
+ display_name,
+ username,
+ } => {
+ ui.label(
+ RichText::new(display_name)
+ .text_style(NotedeckTextStyle::Heading3.text_style()),
+ );
+ ui.label(RichText::new(format!("@{}", username)));
+ }
+ }
}
}