mirror of
https://github.com/aljazceru/notedeck.git
synced 2026-01-11 04:14:20 +01:00
column: switch to profile pictures in header
We also switch away from manual layout to centered cross-alignment. Changelog-Changed: Show profile pictures in column headers Fixes: https://github.com/damus-io/notedeck/issues/12 Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -249,7 +249,14 @@ pub fn render_nav(col: usize, app: &mut Damus, ui: &mut egui::Ui) -> RenderNavRe
|
||||
.returning(app.columns_mut().column_mut(col).router_mut().returning)
|
||||
.id_source(egui::Id::new(col_id))
|
||||
.show_mut(ui, |ui, render_type, nav| match render_type {
|
||||
NavUiType::Title => NavTitle::new(&app.columns, nav.routes_arr()).show(ui),
|
||||
NavUiType::Title => NavTitle::new(
|
||||
&app.ndb,
|
||||
&mut app.img_cache,
|
||||
&app.columns,
|
||||
app.accounts.get_selected_account().map(|a| &a.pubkey),
|
||||
nav.routes_arr(),
|
||||
)
|
||||
.show(ui),
|
||||
NavUiType::Body => render_nav_body(ui, app, nav.routes().last().expect("top"), col),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,74 +1,75 @@
|
||||
use crate::{
|
||||
app_style::{get_font_size, NotedeckTextStyle},
|
||||
app_style::NotedeckTextStyle,
|
||||
column::Columns,
|
||||
fonts::NamedFontFamily,
|
||||
imgcache::ImageCache,
|
||||
nav::RenderNavAction,
|
||||
route::Route,
|
||||
ui::anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE},
|
||||
timeline::{TimelineId, TimelineRoute},
|
||||
ui::{
|
||||
self,
|
||||
anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE},
|
||||
},
|
||||
};
|
||||
|
||||
use egui::{pos2, Color32, Stroke};
|
||||
use egui::{pos2, RichText, Stroke};
|
||||
use enostr::Pubkey;
|
||||
use nostrdb::{Ndb, Transaction};
|
||||
|
||||
pub struct NavTitle<'a> {
|
||||
ndb: &'a Ndb,
|
||||
img_cache: &'a mut ImageCache,
|
||||
columns: &'a Columns,
|
||||
deck_author: Option<&'a Pubkey>,
|
||||
routes: &'a [Route],
|
||||
}
|
||||
|
||||
impl<'a> NavTitle<'a> {
|
||||
pub fn new(columns: &'a Columns, routes: &'a [Route]) -> Self {
|
||||
NavTitle { columns, routes }
|
||||
pub fn new(
|
||||
ndb: &'a Ndb,
|
||||
img_cache: &'a mut ImageCache,
|
||||
columns: &'a Columns,
|
||||
deck_author: Option<&'a Pubkey>,
|
||||
routes: &'a [Route],
|
||||
) -> Self {
|
||||
NavTitle {
|
||||
ndb,
|
||||
img_cache,
|
||||
columns,
|
||||
deck_author,
|
||||
routes,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(&mut self, ui: &mut egui::Ui) -> Option<RenderNavAction> {
|
||||
let mut rect = ui.available_rect_before_wrap();
|
||||
rect.set_height(48.0);
|
||||
let bar = ui.allocate_rect(rect, egui::Sense::hover());
|
||||
ui::padding(8.0, ui, |ui| {
|
||||
let mut rect = ui.available_rect_before_wrap();
|
||||
rect.set_height(48.0);
|
||||
|
||||
self.title_bar(ui, bar)
|
||||
let mut child_ui =
|
||||
ui.child_ui(rect, egui::Layout::left_to_right(egui::Align::Center), None);
|
||||
|
||||
let r = self.title_bar(&mut child_ui);
|
||||
|
||||
ui.advance_cursor_after_rect(rect);
|
||||
|
||||
r
|
||||
})
|
||||
.inner
|
||||
}
|
||||
|
||||
fn title_bar(
|
||||
&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
allocated_response: egui::Response,
|
||||
) -> Option<RenderNavAction> {
|
||||
fn title_bar(&mut self, ui: &mut egui::Ui) -> Option<RenderNavAction> {
|
||||
let icon_width = 32.0;
|
||||
let padding_external = 16.0;
|
||||
let padding_internal = 8.0;
|
||||
let has_back = prev(self.routes).is_some();
|
||||
|
||||
let (spacing_rect, titlebar_rect) = allocated_response
|
||||
.rect
|
||||
.split_left_right_at_x(allocated_response.rect.left() + padding_external);
|
||||
let back_button_resp = if prev(self.routes).is_some() {
|
||||
let (button_rect, _resp) =
|
||||
ui.allocate_exact_size(egui::vec2(icon_width, icon_width), egui::Sense::hover());
|
||||
|
||||
ui.advance_cursor_after_rect(spacing_rect);
|
||||
|
||||
let (titlebar_resp, back_button_resp) = if has_back {
|
||||
let (button_rect, titlebar_rect) = titlebar_rect.split_left_right_at_x(
|
||||
allocated_response.rect.left() + icon_width + padding_external,
|
||||
);
|
||||
(
|
||||
allocated_response.with_new_rect(titlebar_rect),
|
||||
Some(self.back_button(ui, button_rect)),
|
||||
)
|
||||
Some(self.back_button(ui, button_rect))
|
||||
} else {
|
||||
(allocated_response, None)
|
||||
None
|
||||
};
|
||||
|
||||
self.title(
|
||||
ui,
|
||||
self.routes.last().unwrap(),
|
||||
titlebar_resp.rect,
|
||||
icon_width,
|
||||
if has_back {
|
||||
padding_internal
|
||||
} else {
|
||||
padding_external
|
||||
},
|
||||
);
|
||||
|
||||
let delete_button_resp =
|
||||
self.delete_column_button(ui, titlebar_resp, icon_width, padding_external);
|
||||
let delete_button_resp = self.title(ui, self.routes.last().unwrap());
|
||||
|
||||
if delete_button_resp.clicked() {
|
||||
Some(RenderNavAction::RemoveColumn)
|
||||
@@ -118,13 +119,7 @@ impl<'a> NavTitle<'a> {
|
||||
helper.take_animation_response()
|
||||
}
|
||||
|
||||
fn delete_column_button(
|
||||
&self,
|
||||
ui: &mut egui::Ui,
|
||||
allocation_response: egui::Response,
|
||||
icon_width: f32,
|
||||
padding: f32,
|
||||
) -> egui::Response {
|
||||
fn delete_column_button(&self, ui: &mut egui::Ui, icon_width: f32) -> egui::Response {
|
||||
let img_size = 16.0;
|
||||
let max_size = icon_width * ICON_EXPANSION_MULTIPLE;
|
||||
|
||||
@@ -135,20 +130,8 @@ impl<'a> NavTitle<'a> {
|
||||
};
|
||||
let img = egui::Image::new(img_data).max_width(img_size);
|
||||
|
||||
let button_rect = {
|
||||
let titlebar_rect = allocation_response.rect;
|
||||
let titlebar_width = titlebar_rect.width();
|
||||
let titlebar_center = titlebar_rect.center();
|
||||
let button_center_y = titlebar_center.y;
|
||||
let button_center_x =
|
||||
titlebar_center.x + (titlebar_width / 2.0) - (max_size / 2.0) - padding;
|
||||
egui::Rect::from_center_size(
|
||||
pos2(button_center_x, button_center_y),
|
||||
egui::vec2(max_size, max_size),
|
||||
)
|
||||
};
|
||||
|
||||
let helper = AnimationHelper::new_from_rect(ui, "delete-column-button", button_rect);
|
||||
let helper =
|
||||
AnimationHelper::new(ui, "delete-column-button", egui::vec2(max_size, max_size));
|
||||
|
||||
let cur_img_size = helper.scale_1d_pos_min_max(0.0, img_size);
|
||||
|
||||
@@ -160,42 +143,85 @@ impl<'a> NavTitle<'a> {
|
||||
animation_resp
|
||||
}
|
||||
|
||||
fn title(
|
||||
&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
top: &Route,
|
||||
titlebar_rect: egui::Rect,
|
||||
icon_width: f32,
|
||||
padding: f32,
|
||||
) {
|
||||
let painter = ui.painter_at(titlebar_rect);
|
||||
fn pubkey_pfp<'txn, 'me>(
|
||||
&'me mut self,
|
||||
txn: &'txn Transaction,
|
||||
pubkey: &[u8; 32],
|
||||
pfp_size: f32,
|
||||
) -> Option<ui::ProfilePic<'me, 'txn>> {
|
||||
self.ndb
|
||||
.get_profile_by_pubkey(txn, pubkey)
|
||||
.as_ref()
|
||||
.ok()
|
||||
.and_then(move |p| {
|
||||
Some(ui::ProfilePic::from_profile(self.img_cache, p)?.size(pfp_size))
|
||||
})
|
||||
}
|
||||
|
||||
let font = egui::FontId::new(
|
||||
get_font_size(ui.ctx(), &NotedeckTextStyle::Body),
|
||||
egui::FontFamily::Name(NamedFontFamily::Bold.as_str().into()),
|
||||
fn timeline_pfp(&mut self, ui: &mut egui::Ui, id: TimelineId, pfp_size: f32) {
|
||||
let txn = Transaction::new(self.ndb).unwrap();
|
||||
|
||||
if let Some(pfp) = self
|
||||
.columns
|
||||
.find_timeline(id)
|
||||
.and_then(|tl| tl.kind.pubkey_source())
|
||||
.and_then(|pksrc| self.deck_author.map(|da| pksrc.to_pubkey(da)))
|
||||
.and_then(|pk| self.pubkey_pfp(&txn, pk.bytes(), pfp_size))
|
||||
{
|
||||
ui.add(pfp);
|
||||
} else {
|
||||
ui.add(
|
||||
ui::ProfilePic::new(self.img_cache, ui::ProfilePic::no_pfp_url()).size(pfp_size),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn title_pfp(&mut self, ui: &mut egui::Ui, top: &Route) {
|
||||
let pfp_size = 32.0;
|
||||
match top {
|
||||
Route::Timeline(tlr) => match tlr {
|
||||
TimelineRoute::Timeline(tlid) => {
|
||||
self.timeline_pfp(ui, *tlid, pfp_size);
|
||||
}
|
||||
|
||||
TimelineRoute::Thread(_note_id) => {}
|
||||
TimelineRoute::Reply(_note_id) => {}
|
||||
TimelineRoute::Quote(_note_id) => {}
|
||||
|
||||
TimelineRoute::Profile(pubkey) => {
|
||||
let txn = Transaction::new(self.ndb).unwrap();
|
||||
if let Some(pfp) = self.pubkey_pfp(&txn, pubkey.bytes(), pfp_size) {
|
||||
ui.add(pfp);
|
||||
} else {
|
||||
ui.add(
|
||||
ui::ProfilePic::new(self.img_cache, ui::ProfilePic::no_pfp_url())
|
||||
.size(pfp_size),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Route::Accounts(_as) => {}
|
||||
Route::ComposeNote => {}
|
||||
Route::AddColumn(_add_col_route) => {}
|
||||
Route::Support => {}
|
||||
Route::Relays => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn title(&mut self, ui: &mut egui::Ui, top: &Route) -> egui::Response {
|
||||
ui.spacing_mut().item_spacing.x = 10.0;
|
||||
|
||||
self.title_pfp(ui, top);
|
||||
|
||||
ui.label(
|
||||
RichText::new(top.title(self.columns)).text_style(NotedeckTextStyle::Body.text_style()),
|
||||
);
|
||||
|
||||
let max_title_width = titlebar_rect.width() - icon_width - padding * 2.;
|
||||
|
||||
let title_galley = ui.fonts(|f| {
|
||||
f.layout(
|
||||
top.title(self.columns).to_string(),
|
||||
font,
|
||||
ui.visuals().text_color(),
|
||||
max_title_width,
|
||||
)
|
||||
});
|
||||
|
||||
let pos = {
|
||||
let titlebar_center = titlebar_rect.center();
|
||||
let text_height = title_galley.rect.height();
|
||||
|
||||
let galley_pos_x = titlebar_rect.left() + padding;
|
||||
let galley_pos_y = titlebar_center.y - (text_height / 2.);
|
||||
pos2(galley_pos_x, galley_pos_y)
|
||||
};
|
||||
|
||||
painter.galley(pos, title_galley, Color32::WHITE);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
self.delete_column_button(ui, 32.0)
|
||||
})
|
||||
.inner
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user