Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: customizable tabs per column view #598

Merged
merged 4 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions crates/notedeck_columns/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub struct Damus {
pub textmode: bool,
}

fn handle_key_events(input: &egui::InputState, _pixels_per_point: f32, columns: &mut Columns) {
fn handle_key_events(input: &egui::InputState, columns: &mut Columns) {
for event in &input.raw.events {
if let egui::Event::Key {
key, pressed: true, ..
Expand Down Expand Up @@ -87,9 +87,8 @@ fn try_process_event(
app_ctx: &mut AppContext<'_>,
ctx: &egui::Context,
) -> Result<()> {
let ppp = ctx.pixels_per_point();
let current_columns = get_active_columns_mut(app_ctx.accounts, &mut damus.decks_cache);
ctx.input(|i| handle_key_events(i, ppp, current_columns));
ctx.input(|i| handle_key_events(i, current_columns));

let ctx2 = ctx.clone();
let wakeup = move || {
Expand Down
3 changes: 2 additions & 1 deletion crates/notedeck_columns/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use notedeck::FilterState;

use crate::timeline::{PubkeySource, Timeline, TimelineKind};
use crate::timeline::{PubkeySource, Timeline, TimelineKind, TimelineTab};
use enostr::{Filter, Pubkey};
use nostrdb::Ndb;
use tracing::{debug, error, info};
Expand Down Expand Up @@ -151,6 +151,7 @@ impl ArgColumn {
ArgColumn::Generic(filters) => Some(Timeline::new(
TimelineKind::Generic,
FilterState::ready(filters),
TimelineTab::full_tabs(),
)),
ArgColumn::Timeline(tk) => tk.into_timeline(ndb, user),
}
Expand Down
9 changes: 6 additions & 3 deletions crates/notedeck_columns/src/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use notedeck::{filter::default_limit, FilterState, MuteFun, NoteCache, NoteRef};
use crate::{
multi_subscriber::MultiSubscriber,
notes_holder::NotesHolder,
timeline::{copy_notes_into_timeline, PubkeySource, Timeline, TimelineKind},
timeline::{copy_notes_into_timeline, PubkeySource, Timeline, TimelineKind, TimelineTab},
};

pub enum DisplayName<'a> {
Expand Down Expand Up @@ -62,8 +62,11 @@ impl Profile {
notes: Vec<NoteRef>,
is_muted: &MuteFun,
) -> Self {
let mut timeline =
Timeline::new(TimelineKind::profile(source), FilterState::ready(filters));
let mut timeline = Timeline::new(
TimelineKind::profile(source),
FilterState::ready(filters),
TimelineTab::full_tabs(),
);

copy_notes_into_timeline(&mut timeline, txn, ndb, note_cache, notes, is_muted);

Expand Down
7 changes: 6 additions & 1 deletion crates/notedeck_columns/src/timeline/kind.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::Error;
use crate::timeline::Timeline;
use crate::timeline::{Timeline, TimelineTab};
use enostr::{Filter, Pubkey};
use nostrdb::{Ndb, Transaction};
use notedeck::{filter::default_limit, FilterError, FilterState};
Expand Down Expand Up @@ -119,6 +119,7 @@ impl TimelineKind {
.kinds([1])
.limit(default_limit())
.build()]),
TimelineTab::no_replies(),
)),

TimelineKind::Generic => {
Expand All @@ -141,6 +142,7 @@ impl TimelineKind {
Some(Timeline::new(
TimelineKind::profile(pk_src),
FilterState::ready(vec![filter]),
TimelineTab::full_tabs(),
))
}

Expand All @@ -159,6 +161,7 @@ impl TimelineKind {
Some(Timeline::new(
TimelineKind::notifications(pk_src),
FilterState::ready(vec![notifications_filter]),
TimelineTab::only_notes_and_replies(),
))
}

Expand All @@ -181,6 +184,7 @@ impl TimelineKind {
return Some(Timeline::new(
TimelineKind::contact_list(pk_src),
FilterState::needs_remote(vec![contact_filter.clone()]),
TimelineTab::full_tabs(),
));
}

Expand All @@ -189,6 +193,7 @@ impl TimelineKind {
Some(Timeline::new(
TimelineKind::contact_list(pk_src),
FilterState::needs_remote(vec![contact_filter]),
TimelineTab::full_tabs(),
))
}
Err(e) => {
Expand Down
73 changes: 42 additions & 31 deletions crates/notedeck_columns/src/timeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,6 @@ impl ViewFilter {
}
}

pub fn index(&self) -> usize {
match self {
ViewFilter::Notes => 0,
ViewFilter::NotesAndReplies => 1,
}
}

pub fn filter_notes(cache: &CachedNote, note: &Note) -> bool {
!cache.reply.borrow(note.tags()).is_reply()
}
Expand Down Expand Up @@ -100,6 +93,21 @@ impl TimelineTab {
TimelineTab::new_with_capacity(filter, 1000)
}

pub fn only_notes_and_replies() -> Vec<Self> {
vec![TimelineTab::new(ViewFilter::NotesAndReplies)]
}

pub fn no_replies() -> Vec<Self> {
vec![TimelineTab::new(ViewFilter::Notes)]
}

pub fn full_tabs() -> Vec<Self> {
vec![
TimelineTab::new(ViewFilter::Notes),
TimelineTab::new(ViewFilter::NotesAndReplies),
]
}

pub fn new_with_capacity(filter: ViewFilter, cap: usize) -> Self {
let selection = 0i32;
let mut list = VirtualList::new();
Expand Down Expand Up @@ -179,7 +187,7 @@ pub struct Timeline {
// that codepaths have to explicitly handle it
pub filter: FilterStates,
pub views: Vec<TimelineTab>,
pub selected_view: i32,
pub selected_view: usize,

/// Our nostrdb subscription
pub subscription: Option<Subscription>,
Expand All @@ -198,6 +206,7 @@ impl Timeline {
Ok(Timeline::new(
TimelineKind::contact_list(pk_src),
FilterState::ready(filter),
TimelineTab::full_tabs(),
))
}

Expand All @@ -211,26 +220,24 @@ impl Timeline {
Timeline::new(
TimelineKind::Hashtag(hashtag),
FilterState::ready(vec![filter]),
TimelineTab::full_tabs(),
)
}

pub fn make_view_id(id: TimelineId, selected_view: i32) -> egui::Id {
pub fn make_view_id(id: TimelineId, selected_view: usize) -> egui::Id {
egui::Id::new((id, selected_view))
}

pub fn view_id(&self) -> egui::Id {
Timeline::make_view_id(self.id, self.selected_view)
}

pub fn new(kind: TimelineKind, filter_state: FilterState) -> Self {
pub fn new(kind: TimelineKind, filter_state: FilterState, views: Vec<TimelineTab>) -> Self {
// global unique id for all new timelines
static UIDS: AtomicU32 = AtomicU32::new(0);

let filter = FilterStates::new(filter_state);
let subscription: Option<Subscription> = None;
let notes = TimelineTab::new(ViewFilter::Notes);
let replies = TimelineTab::new(ViewFilter::NotesAndReplies);
let views = vec![notes, replies];
let selected_view = 0;
let id = TimelineId::new(UIDS.fetch_add(1, Ordering::Relaxed));

Expand All @@ -245,23 +252,32 @@ impl Timeline {
}

pub fn current_view(&self) -> &TimelineTab {
&self.views[self.selected_view as usize]
&self.views[self.selected_view]
}

pub fn current_view_mut(&mut self) -> &mut TimelineTab {
&mut self.views[self.selected_view as usize]
&mut self.views[self.selected_view]
}

pub fn notes(&self, view: ViewFilter) -> &[NoteRef] {
&self.views[view.index()].notes
/// Get the note refs for NotesAndReplies. If we only have Notes, then
/// just return that instead
pub fn all_or_any_notes(&self) -> &[NoteRef] {
self.notes(ViewFilter::NotesAndReplies).unwrap_or_else(|| {
self.notes(ViewFilter::Notes)
.expect("should have at least notes")
})
}

pub fn view(&self, view: ViewFilter) -> &TimelineTab {
&self.views[view.index()]
pub fn notes(&self, view: ViewFilter) -> Option<&[NoteRef]> {
self.view(view).map(|v| &*v.notes)
}

pub fn view_mut(&mut self, view: ViewFilter) -> &mut TimelineTab {
&mut self.views[view.index()]
pub fn view(&self, view: ViewFilter) -> Option<&TimelineTab> {
self.views.iter().find(|tab| tab.filter == view)
}

pub fn view_mut(&mut self, view: ViewFilter) -> Option<&mut TimelineTab> {
self.views.iter_mut().find(|tab| tab.filter == view)
}

pub fn poll_notes_into_view(
Expand Down Expand Up @@ -314,21 +330,18 @@ impl Timeline {
let reversed = false;

// ViewFilter::NotesAndReplies
{
if let Some(view) = timeline.view_mut(ViewFilter::NotesAndReplies) {
let refs: Vec<NoteRef> = new_refs.iter().map(|(_note, nr)| *nr).collect();

let reversed = false;
timeline
.view_mut(ViewFilter::NotesAndReplies)
.insert(&refs, reversed);
view.insert(&refs, reversed);
}

//
// handle the filtered case (ViewFilter::Notes, no replies)
//
// TODO(jb55): this is mostly just copied from above, let's just use a loop
// I initially tried this but ran into borrow checker issues
{
if let Some(view) = timeline.view_mut(ViewFilter::Notes) {
let mut filtered_refs = Vec::with_capacity(new_refs.len());
for (note, nr) in &new_refs {
let cached_note = note_cache.cached_note_or_insert(nr.key, note);
Expand All @@ -338,9 +351,7 @@ impl Timeline {
}
}

timeline
.view_mut(ViewFilter::Notes)
.insert(&filtered_refs, reversed);
view.insert(&filtered_refs, reversed);
}

Ok(())
Expand Down Expand Up @@ -478,7 +489,7 @@ pub fn send_initial_timeline_filter(
filter = filter.limit_mut(lim);
}

let notes = timeline.notes(ViewFilter::NotesAndReplies);
let notes = timeline.all_or_any_notes();

// Should we since optimize? Not always. For example
// if we only have a few notes locally. One way to
Expand Down
Loading
Loading