notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 8b5464641d140b137f05f4b5931587e545587c74
parent c06d18f76b9b1d0a7905e787530db2f453c320f7
Author: kernelkind <kernelkind@gmail.com>
Date:   Mon, 25 Aug 2025 21:16:05 -0400

render follow pack by index from virtual list

Signed-off-by: kernelkind <kernelkind@gmail.com>

Diffstat:
Mcrates/notedeck_columns/src/ui/onboarding.rs | 49+++++++++++++++++++++++++++++++------------------
Mcrates/notedeck_ui/src/nip51_set.rs | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
2 files changed, 91 insertions(+), 43 deletions(-)

diff --git a/crates/notedeck_columns/src/ui/onboarding.rs b/crates/notedeck_columns/src/ui/onboarding.rs @@ -5,7 +5,7 @@ use nostrdb::Ndb; use notedeck::{Images, JobPool, JobsCache, Localization}; use notedeck_ui::{ colors, - nip51_set::{Nip51SetUiCache, Nip51SetWidget, Nip51SetWidgetFlags, Nip51SetWidgetResponse}, + nip51_set::{Nip51SetUiCache, Nip51SetWidget, Nip51SetWidgetAction, Nip51SetWidgetFlags}, }; use crate::{onboarding::Onboarding, ui::widgets::styled_button}; @@ -71,24 +71,37 @@ impl<'a> FollowPackOnboardingView<'a> { .max_height(max_height) .show(ui, |ui| { egui::Frame::new().inner_margin(8.0).show(ui, |ui| { - if let Some(resp) = Nip51SetWidget::new( - follow_pack_state, - self.ui_state, - self.ndb, - self.loc, - self.images, - self.job_pool, - self.jobs, - ) - .with_flags(Nip51SetWidgetFlags::TRUST_IMAGES) - .ui(ui) - { - match resp { - Nip51SetWidgetResponse::ViewProfile(pubkey) => { - action = Some(OnboardingResponse::ViewProfile(pubkey)); + self.onboarding.list.borrow_mut().ui_custom_layout( + ui, + follow_pack_state.len(), + |ui, index| { + let resp = Nip51SetWidget::new( + follow_pack_state, + self.ui_state, + self.ndb, + self.loc, + self.images, + self.job_pool, + self.jobs, + ) + .with_flags(Nip51SetWidgetFlags::TRUST_IMAGES) + .render_at_index(ui, index); + + if let Some(cur_action) = resp.action { + match cur_action { + Nip51SetWidgetAction::ViewProfile(pubkey) => { + action = Some(OnboardingResponse::ViewProfile(pubkey)); + } + } + } + + if resp.rendered { + 1 + } else { + 0 } - } - } + }, + ); }) }); diff --git a/crates/notedeck_ui/src/nip51_set.rs b/crates/notedeck_ui/src/nip51_set.rs @@ -42,7 +42,7 @@ impl Default for Nip51SetWidgetFlags { } } -pub enum Nip51SetWidgetResponse { +pub enum Nip51SetWidgetAction { ViewProfile(Pubkey), } @@ -73,32 +73,62 @@ impl<'a> Nip51SetWidget<'a> { self } - pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<Nip51SetWidgetResponse> { + fn render_set(&mut self, ui: &mut egui::Ui, set: &Nip51Set) -> Nip51SetWidgetResponse { + if should_skip(set, &self.flags) { + return Nip51SetWidgetResponse { + action: None, + rendered: false, + }; + } + + let action = egui::Frame::new() + .corner_radius(CornerRadius::same(8)) + .fill(ui.visuals().extreme_bg_color) + .inner_margin(Margin::same(8)) + .show(ui, |ui| { + render_pack( + ui, + set, + self.ui_state, + self.ndb, + self.images, + self.job_pool, + self.jobs, + self.loc, + self.flags.contains(Nip51SetWidgetFlags::TRUST_IMAGES), + ) + }) + .inner; + + Nip51SetWidgetResponse { + action, + rendered: true, + } + } + + pub fn render_at_index(&mut self, ui: &mut egui::Ui, index: usize) -> Nip51SetWidgetResponse { + let Some(set) = self.state.at_index(index) else { + return Nip51SetWidgetResponse { + action: None, + rendered: false, + }; + }; + + self.render_set(ui, set) + } + + pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<Nip51SetWidgetAction> { let mut resp = None; for pack in self.state.iter() { - if should_skip(pack, &self.flags) { - continue; + let res = self.render_set(ui, pack); + + if let Some(action) = res.action { + resp = Some(action); } - egui::Frame::new() - .corner_radius(CornerRadius::same(8)) - .fill(ui.visuals().extreme_bg_color) - .inner_margin(Margin::same(8)) - .show(ui, |ui| { - if let Some(cur_resp) = render_pack( - ui, - pack, - self.ui_state, - self.ndb, - self.images, - self.job_pool, - self.jobs, - self.loc, - self.flags.contains(Nip51SetWidgetFlags::TRUST_IMAGES), - ) { - resp = Some(cur_resp); - } - }); + if !res.rendered { + continue; + } ui.add_space(8.0); } @@ -107,6 +137,11 @@ impl<'a> Nip51SetWidget<'a> { } } +pub struct Nip51SetWidgetResponse { + pub action: Option<Nip51SetWidgetAction>, + pub rendered: bool, +} + fn should_skip(set: &Nip51Set, required: &Nip51SetWidgetFlags) -> bool { (required.contains(Nip51SetWidgetFlags::REQUIRES_TITLE) && set.title.is_none()) || (required.contains(Nip51SetWidgetFlags::REQUIRES_IMAGE) && set.image.is_none()) @@ -126,7 +161,7 @@ fn render_pack( jobs: &mut JobsCache, loc: &mut Localization, image_trusted: bool, -) -> Option<Nip51SetWidgetResponse> { +) -> Option<Nip51SetWidgetAction> { let max_img_size = vec2(ui.available_width(), 200.0); ui.allocate_new_ui(UiBuilder::new(), |ui| 's: { @@ -210,7 +245,7 @@ fn render_pack( ui.separator(); if render_profile_item(ui, images, m_profile.as_ref(), cur_state) { - resp = Some(Nip51SetWidgetResponse::ViewProfile(*pk)); + resp = Some(Nip51SetWidgetAction::ViewProfile(*pk)); } }