mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-20 01:44:19 +01:00
Merge show-note-client option by fernando
We should move this somewhere else before we turn it on
officially
Fernando López Guevara (2):
refactor: use Margin:ZERO
feat(note-view): show note client
This commit is contained in:
@@ -8,6 +8,7 @@ use crate::{
|
||||
DataPathType, Directory, Images, NoteAction, NoteCache, RelayDebugView, ThemeHandler,
|
||||
UnknownIds,
|
||||
};
|
||||
use egui::Margin;
|
||||
use egui::ThemePreference;
|
||||
use egui_winit::clipboard::Clipboard;
|
||||
use enostr::RelayPool;
|
||||
@@ -51,14 +52,8 @@ pub struct Notedeck {
|
||||
|
||||
/// Our chrome, which is basically nothing
|
||||
fn main_panel(style: &egui::Style) -> egui::CentralPanel {
|
||||
let inner_margin = egui::Margin {
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
};
|
||||
egui::CentralPanel::default().frame(egui::Frame {
|
||||
inner_margin,
|
||||
inner_margin: Margin::ZERO,
|
||||
fill: style.visuals.panel_fill,
|
||||
..Default::default()
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ use tracing::error;
|
||||
pub struct Args {
|
||||
pub relays: Vec<String>,
|
||||
pub is_mobile: Option<bool>,
|
||||
pub show_note_client: bool,
|
||||
pub keys: Vec<Keypair>,
|
||||
pub light: bool,
|
||||
pub debug: bool,
|
||||
@@ -28,6 +29,7 @@ impl Args {
|
||||
is_mobile: None,
|
||||
keys: vec![],
|
||||
light: false,
|
||||
show_note_client: false,
|
||||
debug: false,
|
||||
relay_debug: false,
|
||||
tests: false,
|
||||
@@ -116,6 +118,8 @@ impl Args {
|
||||
res.use_keystore = false;
|
||||
} else if arg == "--relay-debug" {
|
||||
res.relay_debug = true;
|
||||
} else if arg == "--show-note-client" {
|
||||
res.show_note_client = true;
|
||||
} else {
|
||||
unrecognized_args.insert(arg.clone());
|
||||
}
|
||||
|
||||
@@ -193,3 +193,19 @@ where
|
||||
|rnid| Ok(RootNoteId::new_unsafe(rnid.id)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn event_tag<'a>(ev: &nostrdb::Note<'a>, name: &str) -> Option<&'a str> {
|
||||
ev.tags().iter().find_map(|tag| {
|
||||
if tag.count() < 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let cur_name = tag.get_str(0)?;
|
||||
|
||||
if cur_name != name {
|
||||
return None;
|
||||
}
|
||||
|
||||
tag.get_str(1)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -33,18 +33,28 @@ impl NoteCache {
|
||||
#[derive(Clone)]
|
||||
pub struct CachedNote {
|
||||
reltime: TimeCached<String>,
|
||||
pub client: Option<String>,
|
||||
pub reply: NoteReplyBuf,
|
||||
}
|
||||
|
||||
impl CachedNote {
|
||||
pub fn new(note: &Note<'_>) -> Self {
|
||||
pub fn new(note: &Note) -> Self {
|
||||
use crate::note::event_tag;
|
||||
|
||||
let created_at = note.created_at();
|
||||
let reltime = TimeCached::new(
|
||||
Duration::from_secs(1),
|
||||
Box::new(move || time_ago_since(created_at)),
|
||||
);
|
||||
let reply = NoteReply::new(note.tags()).to_owned();
|
||||
CachedNote { reltime, reply }
|
||||
|
||||
let client = event_tag(note, "client");
|
||||
|
||||
CachedNote {
|
||||
client: client.map(|c| c.to_string()),
|
||||
reltime,
|
||||
reply,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reltime_str_mut(&mut self) -> &str {
|
||||
|
||||
@@ -64,23 +64,6 @@ impl Zap {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn event_tag<'a>(ev: nostrdb::Note<'a>, name: &str) -> Option<&'a str> {
|
||||
ev.tags().iter().find_map(|tag| {
|
||||
if tag.count() < 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let cur_name = tag.get_str(0)?;
|
||||
|
||||
if cur_name != name {
|
||||
return None;
|
||||
}
|
||||
|
||||
tag.get_str(1)
|
||||
})
|
||||
}
|
||||
|
||||
fn determine_zap_target(tags: &ZapTags) -> Option<ZapTarget> {
|
||||
if let Some(note_zapped) = tags.note_zapped {
|
||||
Some(ZapTarget::Note(NoteZapTarget {
|
||||
|
||||
@@ -9,7 +9,6 @@ use notedeck::{App, AppAction, AppContext, NotedeckTextStyle, UserAccount, Walle
|
||||
use notedeck_columns::{
|
||||
column::SelectionResult, timeline::kind::ListKind, timeline::TimelineKind, Damus,
|
||||
};
|
||||
|
||||
use notedeck_dave::{Dave, DaveAvatar};
|
||||
use notedeck_ui::{app_images, AnimationHelper, ProfilePic};
|
||||
|
||||
@@ -289,7 +288,7 @@ impl Chrome {
|
||||
/// How far is the chrome panel expanded?
|
||||
fn amount_open(&self, ui: &mut egui::Ui) -> f32 {
|
||||
let open_id = egui::Id::new("chrome_open");
|
||||
let side_panel_width: f32 = 70.0;
|
||||
let side_panel_width: f32 = 74.0;
|
||||
ui.ctx().animate_bool(open_id, self.open) * side_panel_width
|
||||
}
|
||||
|
||||
@@ -406,7 +405,7 @@ impl Chrome {
|
||||
// macos needs a bit of space to make room for window
|
||||
// minimize/close buttons
|
||||
if cfg!(target_os = "macos") {
|
||||
ui.add_space(28.0);
|
||||
ui.add_space(30.0);
|
||||
} else {
|
||||
// we still want *some* padding so that it aligns with the + button regardless
|
||||
ui.add_space(notedeck_ui::constants::FRAME_MARGIN.into());
|
||||
@@ -615,11 +614,12 @@ fn wallet_button() -> impl Widget {
|
||||
|
||||
let max_size = img_size * ICON_EXPANSION_MULTIPLE;
|
||||
|
||||
let mut img = app_images::wallet_image().max_width(img_size);
|
||||
|
||||
if !ui.visuals().dark_mode {
|
||||
img = img.tint(egui::Color32::BLACK);
|
||||
let img = if !ui.visuals().dark_mode {
|
||||
app_images::wallet_light_image()
|
||||
} else {
|
||||
app_images::wallet_dark_image()
|
||||
}
|
||||
.max_width(img_size);
|
||||
|
||||
let helper = AnimationHelper::new(ui, "wallet-icon", vec2(max_size, max_size));
|
||||
|
||||
|
||||
@@ -452,6 +452,10 @@ impl Damus {
|
||||
NoteOptions::HideMedia,
|
||||
parsed_args.is_flag_set(ColumnsFlag::NoMedia),
|
||||
);
|
||||
note_options.set(
|
||||
NoteOptions::ShowNoteClient,
|
||||
parsed_args.is_flag_set(ColumnsFlag::ShowNoteClient),
|
||||
);
|
||||
options.set(AppOptions::Debug, ctx.args.debug);
|
||||
options.set(
|
||||
AppOptions::SinceOptimize,
|
||||
|
||||
@@ -11,6 +11,7 @@ pub enum ColumnsFlag {
|
||||
Textmode,
|
||||
Scramble,
|
||||
NoMedia,
|
||||
ShowNoteClient,
|
||||
}
|
||||
|
||||
pub struct ColumnsArgs {
|
||||
@@ -52,6 +53,8 @@ impl ColumnsArgs {
|
||||
res.clear_flag(ColumnsFlag::SinceOptimize);
|
||||
} else if arg == "--scramble" {
|
||||
res.set_flag(ColumnsFlag::Scramble);
|
||||
} else if arg == "--show-note-client" {
|
||||
res.set_flag(ColumnsFlag::ShowNoteClient);
|
||||
} else if arg == "--no-media" {
|
||||
res.set_flag(ColumnsFlag::NoMedia);
|
||||
} else if arg == "--filter" {
|
||||
|
||||
@@ -643,15 +643,17 @@ fn media_upload_button() -> impl egui::Widget {
|
||||
|
||||
painter.rect_filled(resp.rect, 8.0, fill_color);
|
||||
painter.rect_stroke(resp.rect, 8.0, stroke, egui::StrokeKind::Middle);
|
||||
let mut upload_img = app_images::media_upload_dark_image();
|
||||
|
||||
if !ui.visuals().dark_mode {
|
||||
upload_img = upload_img.tint(egui::Color32::BLACK);
|
||||
let upload_img = if ui.visuals().dark_mode {
|
||||
app_images::media_upload_dark_image()
|
||||
} else {
|
||||
app_images::media_upload_light_image()
|
||||
};
|
||||
|
||||
upload_img
|
||||
.max_size(egui::vec2(16.0, 16.0))
|
||||
.paint_at(ui, resp.rect.shrink(8.0));
|
||||
|
||||
resp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,9 +261,9 @@ enum ProfileType {
|
||||
|
||||
fn handle_link(ui: &mut egui::Ui, website_url: &str) {
|
||||
let img = if ui.visuals().dark_mode {
|
||||
app_images::link_image()
|
||||
app_images::link_dark_image()
|
||||
} else {
|
||||
app_images::link_image().tint(egui::Color32::BLACK)
|
||||
app_images::link_light_image()
|
||||
};
|
||||
|
||||
ui.add(img);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use eframe::icon_data::from_png_bytes;
|
||||
use egui::{include_image, IconData, Image};
|
||||
use egui::{include_image, Color32, IconData, Image};
|
||||
|
||||
pub fn app_icon() -> IconData {
|
||||
from_png_bytes(include_bytes!("../../../assets/damus-app-icon.png")).expect("icon")
|
||||
@@ -113,12 +113,12 @@ pub fn help_light_image() -> Image<'static> {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn home_dark_image() -> Image<'static> {
|
||||
Image::new(include_image!("../../../assets/icons/home-toolbar.png"))
|
||||
pub fn home_light_image() -> Image<'static> {
|
||||
home_dark_image().tint(Color32::BLACK)
|
||||
}
|
||||
|
||||
pub fn home_light_image() -> Image<'static> {
|
||||
home_dark_image().tint(egui::Color32::BLACK)
|
||||
pub fn home_dark_image() -> Image<'static> {
|
||||
Image::new(include_image!("../../../assets/icons/home-toolbar.png"))
|
||||
}
|
||||
|
||||
pub fn home_image() -> Image<'static> {
|
||||
@@ -131,10 +131,14 @@ pub fn key_image() -> Image<'static> {
|
||||
Image::new(include_image!("../../../assets/icons/key_4x.png"))
|
||||
}
|
||||
|
||||
pub fn link_image() -> Image<'static> {
|
||||
pub fn link_dark_image() -> Image<'static> {
|
||||
Image::new(include_image!("../../../assets/icons/links_4x.png"))
|
||||
}
|
||||
|
||||
pub fn link_light_image() -> Image<'static> {
|
||||
link_dark_image().tint(Color32::BLACK)
|
||||
}
|
||||
|
||||
pub fn new_message_image() -> Image<'static> {
|
||||
Image::new(include_image!("../../../assets/icons/newmessage_64.png"))
|
||||
}
|
||||
@@ -153,15 +157,16 @@ pub fn notifications_image(dark_mode: bool) -> Image<'static> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notifications_light_image() -> Image<'static> {
|
||||
notifications_dark_image().tint(Color32::BLACK)
|
||||
}
|
||||
|
||||
pub fn notifications_dark_image() -> Image<'static> {
|
||||
Image::new(include_image!(
|
||||
"../../../assets/icons/notifications_dark_4x.png"
|
||||
))
|
||||
}
|
||||
|
||||
pub fn notifications_light_image() -> Image<'static> {
|
||||
notifications_dark_image().tint(egui::Color32::BLACK)
|
||||
}
|
||||
pub fn repost_dark_image() -> Image<'static> {
|
||||
Image::new(include_image!("../../../assets/icons/repost_icon_4x.png"))
|
||||
}
|
||||
@@ -208,10 +213,22 @@ pub fn media_upload_dark_image() -> Image<'static> {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn wallet_image() -> Image<'static> {
|
||||
pub fn media_upload_light_image() -> Image<'static> {
|
||||
media_upload_dark_image().tint(Color32::BLACK)
|
||||
}
|
||||
|
||||
pub fn wallet_dark_image() -> Image<'static> {
|
||||
Image::new(include_image!("../../../assets/icons/wallet-icon.svg"))
|
||||
}
|
||||
|
||||
pub fn zap_image() -> Image<'static> {
|
||||
pub fn wallet_light_image() -> Image<'static> {
|
||||
wallet_dark_image().tint(Color32::BLACK)
|
||||
}
|
||||
|
||||
pub fn zap_dark_image() -> Image<'static> {
|
||||
Image::new(include_image!("../../../assets/icons/zap_4x.png"))
|
||||
}
|
||||
|
||||
pub fn zap_light_image() -> Image<'static> {
|
||||
zap_dark_image().tint(Color32::BLACK)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ pub use note::{NoteContents, NoteOptions, NoteView};
|
||||
pub use profile::{ProfilePic, ProfilePreview};
|
||||
pub use username::Username;
|
||||
|
||||
use egui::Margin;
|
||||
use egui::{Label, Margin, RichText};
|
||||
|
||||
/// This is kind of like the Widget trait but is meant for larger top-level
|
||||
/// views that are typically stateful.
|
||||
@@ -58,3 +58,8 @@ pub fn hline_with_width(ui: &egui::Ui, range: egui::Rangef) {
|
||||
let stroke = ui.style().visuals.widgets.noninteractive.bg_stroke;
|
||||
ui.painter().hline(range, resize_y, stroke);
|
||||
}
|
||||
|
||||
pub fn secondary_label(ui: &mut egui::Ui, s: impl Into<String>) {
|
||||
let color = ui.style().visuals.noninteractive().fg_stroke.color;
|
||||
ui.add(Label::new(RichText::new(s).size(10.0).color(color)).selectable(false));
|
||||
}
|
||||
|
||||
@@ -4,13 +4,14 @@ use crate::{
|
||||
blur::imeta_blurhashes,
|
||||
jobs::JobsCache,
|
||||
note::{NoteAction, NoteOptions, NoteResponse, NoteView},
|
||||
secondary_label,
|
||||
};
|
||||
|
||||
use egui::{Color32, Hyperlink, RichText};
|
||||
use nostrdb::{BlockType, Mention, Note, NoteKey, Transaction};
|
||||
use tracing::warn;
|
||||
|
||||
use notedeck::{IsFollowing, NoteContext};
|
||||
use notedeck::{IsFollowing, NoteCache, NoteContext};
|
||||
|
||||
use super::media::{find_renderable_media, image_carousel, RenderableMedia};
|
||||
|
||||
@@ -53,11 +54,28 @@ impl egui::Widget for &mut NoteContents<'_, '_> {
|
||||
self.options,
|
||||
self.jobs,
|
||||
);
|
||||
if self.options.contains(NoteOptions::ShowNoteClient) {
|
||||
render_client(ui, self.note_context.note_cache, self.note);
|
||||
}
|
||||
self.action = result.action;
|
||||
result.response
|
||||
}
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn render_client(ui: &mut egui::Ui, note_cache: &mut NoteCache, note: &Note) {
|
||||
let cached_note = note_cache.cached_note_or_insert_mut(note.key().unwrap(), note);
|
||||
|
||||
match cached_note.client.as_deref() {
|
||||
Some(client) if !client.is_empty() => {
|
||||
ui.horizontal(|ui| {
|
||||
secondary_label(ui, format!("via {}", client));
|
||||
});
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
|
||||
/// Render an inline note preview with a border. These are used when
|
||||
/// notes are references within a note
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
||||
@@ -4,8 +4,8 @@ pub mod media;
|
||||
pub mod options;
|
||||
pub mod reply_description;
|
||||
|
||||
use crate::app_images;
|
||||
use crate::jobs::JobsCache;
|
||||
use crate::{app_images, secondary_label};
|
||||
use crate::{
|
||||
profile::name::one_line_display_name_widget, widgets::x_button, ProfilePic, ProfilePreview,
|
||||
PulseAlpha, Username,
|
||||
@@ -21,7 +21,7 @@ pub use options::NoteOptions;
|
||||
pub use reply_description::reply_desc;
|
||||
|
||||
use egui::emath::{pos2, Vec2};
|
||||
use egui::{Id, Label, Pos2, Rect, Response, RichText, Sense};
|
||||
use egui::{Id, Pos2, Rect, Response, RichText, Sense};
|
||||
use enostr::{KeypairUnowned, NoteId, Pubkey};
|
||||
use nostrdb::{Ndb, Note, NoteKey, ProfileRecord, Transaction};
|
||||
use notedeck::{
|
||||
@@ -534,6 +534,7 @@ impl<'a, 'd> NoteView<'a, 'd> {
|
||||
cur_acc: cur_acc.keypair(),
|
||||
})
|
||||
};
|
||||
|
||||
if self.options().contains(NoteOptions::ActionBar) {
|
||||
note_action = render_note_actionbar(
|
||||
ui,
|
||||
@@ -828,11 +829,6 @@ fn render_note_actionbar(
|
||||
})
|
||||
}
|
||||
|
||||
fn secondary_label(ui: &mut egui::Ui, s: impl Into<String>) {
|
||||
let color = ui.style().visuals.noninteractive().fg_stroke.color;
|
||||
ui.add(Label::new(RichText::new(s).size(10.0).color(color)));
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
fn render_reltime(
|
||||
ui: &mut egui::Ui,
|
||||
@@ -902,14 +898,14 @@ fn zap_button(state: AnyZapState, noteid: &[u8; 32]) -> impl egui::Widget + use<
|
||||
move |ui: &mut egui::Ui| -> egui::Response {
|
||||
let (rect, size, resp) = crate::anim::hover_expand_small(ui, ui.id().with("zap"));
|
||||
|
||||
let mut img = app_images::zap_image().max_width(size);
|
||||
let mut img = app_images::zap_dark_image().max_width(size);
|
||||
let id = ui.id().with(("pulse", noteid));
|
||||
let ctx = ui.ctx().clone();
|
||||
|
||||
match state {
|
||||
AnyZapState::None => {
|
||||
if !ui.visuals().dark_mode {
|
||||
img = img.tint(egui::Color32::BLACK);
|
||||
img = app_images::zap_light_image();
|
||||
}
|
||||
}
|
||||
AnyZapState::Pending => {
|
||||
|
||||
@@ -22,6 +22,8 @@ bitflags! {
|
||||
/// Is the content truncated? If the length is over a certain size it
|
||||
/// will end with a ... and a "Show more" button.
|
||||
const Truncate = 1 << 11;
|
||||
/// Show note's client in the note header
|
||||
const ShowNoteClient = 1 << 12;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user