add more notes indicator
closes: https://github.com/damus-io/notedeck/issues/72 Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
use std::f32::consts::PI;
|
||||
|
||||
use crate::actionbar::NoteAction;
|
||||
use crate::timeline::TimelineTab;
|
||||
use crate::{
|
||||
@@ -7,13 +9,15 @@ use crate::{
|
||||
ui::note::NoteOptions,
|
||||
};
|
||||
use egui::containers::scroll_area::ScrollBarVisibility;
|
||||
use egui::{Direction, Layout};
|
||||
use egui::{vec2, Direction, Layout, Pos2, Stroke};
|
||||
use egui_tabs::TabColor;
|
||||
use nostrdb::{Ndb, Transaction};
|
||||
use notedeck::note::root_note_id_from_selected_id;
|
||||
use notedeck::{ImageCache, MuteFun, NoteCache};
|
||||
use tracing::{error, warn};
|
||||
|
||||
use super::anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE};
|
||||
|
||||
pub struct TimelineView<'a> {
|
||||
timeline_id: TimelineId,
|
||||
columns: &'a mut Columns,
|
||||
@@ -105,35 +109,120 @@ fn timeline_ui(
|
||||
egui::Id::new(("tlscroll", timeline.view_id()))
|
||||
};
|
||||
|
||||
egui::ScrollArea::vertical()
|
||||
let show_top_button_id = ui.id().with((scroll_id, "at_top"));
|
||||
|
||||
let show_top_button = ui
|
||||
.ctx()
|
||||
.data(|d| d.get_temp::<bool>(show_top_button_id))
|
||||
.unwrap_or(false);
|
||||
|
||||
let goto_top = if show_top_button {
|
||||
let top_button_pos = ui.available_rect_before_wrap().right_top() - vec2(48.0, -24.0);
|
||||
egui::Area::new(ui.id().with("foreground_area"))
|
||||
.order(egui::Order::Foreground)
|
||||
.fixed_pos(top_button_pos)
|
||||
.show(ui.ctx(), |ui| {
|
||||
ui.add(goto_top_button(top_button_pos)).clicked()
|
||||
})
|
||||
.inner
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let mut scroll_area = egui::ScrollArea::vertical()
|
||||
.id_salt(scroll_id)
|
||||
.animated(false)
|
||||
.auto_shrink([false, false])
|
||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysVisible)
|
||||
.show(ui, |ui| {
|
||||
let timeline = if let Some(timeline) = columns.find_timeline_mut(timeline_id) {
|
||||
timeline
|
||||
} else {
|
||||
error!("tried to render timeline in column, but timeline was missing");
|
||||
// TODO (jb55): render error when timeline is missing?
|
||||
// this shouldn't happen...
|
||||
return None;
|
||||
};
|
||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysVisible);
|
||||
if goto_top {
|
||||
scroll_area = scroll_area.vertical_scroll_offset(0.0);
|
||||
}
|
||||
|
||||
let txn = Transaction::new(ndb).expect("failed to create txn");
|
||||
TimelineTabView::new(
|
||||
timeline.current_view(),
|
||||
reversed,
|
||||
note_options,
|
||||
&txn,
|
||||
ndb,
|
||||
note_cache,
|
||||
img_cache,
|
||||
is_muted,
|
||||
)
|
||||
.show(ui)
|
||||
})
|
||||
.inner
|
||||
let scroll_output = scroll_area.show(ui, |ui| {
|
||||
let timeline = if let Some(timeline) = columns.find_timeline_mut(timeline_id) {
|
||||
timeline
|
||||
} else {
|
||||
error!("tried to render timeline in column, but timeline was missing");
|
||||
// TODO (jb55): render error when timeline is missing?
|
||||
// this shouldn't happen...
|
||||
return None;
|
||||
};
|
||||
|
||||
let txn = Transaction::new(ndb).expect("failed to create txn");
|
||||
TimelineTabView::new(
|
||||
timeline.current_view(),
|
||||
reversed,
|
||||
note_options,
|
||||
&txn,
|
||||
ndb,
|
||||
note_cache,
|
||||
img_cache,
|
||||
is_muted,
|
||||
)
|
||||
.show(ui)
|
||||
});
|
||||
|
||||
let at_top_after_scroll = scroll_output.state.offset.y == 0.0;
|
||||
let cur_show_top_button = ui.ctx().data(|d| d.get_temp::<bool>(show_top_button_id));
|
||||
|
||||
if at_top_after_scroll {
|
||||
if cur_show_top_button != Some(false) {
|
||||
ui.ctx()
|
||||
.data_mut(|d| d.insert_temp(show_top_button_id, false));
|
||||
}
|
||||
} else if cur_show_top_button == Some(false) {
|
||||
ui.ctx()
|
||||
.data_mut(|d| d.insert_temp(show_top_button_id, true));
|
||||
}
|
||||
|
||||
scroll_output.inner
|
||||
}
|
||||
|
||||
fn goto_top_button(center: Pos2) -> impl egui::Widget {
|
||||
move |ui: &mut egui::Ui| -> egui::Response {
|
||||
let radius = 12.0;
|
||||
let max_size = vec2(
|
||||
ICON_EXPANSION_MULTIPLE * 2.0 * radius,
|
||||
ICON_EXPANSION_MULTIPLE * 2.0 * radius,
|
||||
);
|
||||
let helper = AnimationHelper::new_from_rect(ui, "goto_top", {
|
||||
let painter = ui.painter();
|
||||
let center = painter.round_pos_to_pixel_center(center);
|
||||
egui::Rect::from_center_size(center, max_size)
|
||||
});
|
||||
|
||||
let painter = ui.painter();
|
||||
painter.circle_filled(center, helper.scale_1d_pos(radius), crate::colors::PINK);
|
||||
|
||||
let create_pt = |angle: f32| {
|
||||
let side = radius / 2.0;
|
||||
let x = side * angle.cos();
|
||||
let mut y = side * angle.sin();
|
||||
|
||||
let height = (side * (3.0_f32).sqrt()) / 2.0;
|
||||
y += height / 2.0;
|
||||
Pos2 { x, y }
|
||||
};
|
||||
|
||||
let left_pt =
|
||||
painter.round_pos_to_pixel_center(helper.scale_pos_from_center(create_pt(-PI)));
|
||||
let center_pt =
|
||||
painter.round_pos_to_pixel_center(helper.scale_pos_from_center(create_pt(-PI / 2.0)));
|
||||
let right_pt =
|
||||
painter.round_pos_to_pixel_center(helper.scale_pos_from_center(create_pt(0.0)));
|
||||
|
||||
let line_width = helper.scale_1d_pos(4.0);
|
||||
let line_color = ui.visuals().text_color();
|
||||
painter.line_segment([left_pt, center_pt], Stroke::new(line_width, line_color));
|
||||
painter.line_segment([center_pt, right_pt], Stroke::new(line_width, line_color));
|
||||
|
||||
let end_radius = (line_width - 1.0) / 2.0;
|
||||
painter.circle_filled(left_pt, end_radius, line_color);
|
||||
painter.circle_filled(center_pt, end_radius, line_color);
|
||||
painter.circle_filled(right_pt, end_radius, line_color);
|
||||
|
||||
helper.take_animation_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tabs_ui(ui: &mut egui::Ui, selected: usize, views: &[TimelineTab]) -> usize {
|
||||
|
||||
Reference in New Issue
Block a user