mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-18 17:14:21 +01:00
ui: add RepostDecisionView
Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
@@ -12,6 +12,7 @@ pub mod post;
|
||||
pub mod preview;
|
||||
pub mod profile;
|
||||
pub mod relay;
|
||||
pub mod repost;
|
||||
pub mod search;
|
||||
pub mod settings;
|
||||
pub mod side_panel;
|
||||
|
||||
186
crates/notedeck_columns/src/ui/repost.rs
Normal file
186
crates/notedeck_columns/src/ui/repost.rs
Normal file
@@ -0,0 +1,186 @@
|
||||
use std::f32::consts::PI;
|
||||
|
||||
use egui::{
|
||||
epaint::PathShape, pos2, vec2, CornerRadius, Layout, Margin, Pos2, RichText, Sense, Shape,
|
||||
Stroke,
|
||||
};
|
||||
use egui_extras::StripBuilder;
|
||||
use enostr::NoteId;
|
||||
use notedeck::{fonts::get_font_size, NotedeckTextStyle};
|
||||
use notedeck_ui::app_images;
|
||||
|
||||
use crate::repost::RepostAction;
|
||||
|
||||
pub struct RepostDecisionView<'a> {
|
||||
noteid: &'a NoteId,
|
||||
}
|
||||
|
||||
impl<'a> RepostDecisionView<'a> {
|
||||
pub fn new(noteid: &'a NoteId) -> Self {
|
||||
Self { noteid }
|
||||
}
|
||||
|
||||
pub fn show(&self, ui: &mut egui::Ui) -> Option<RepostAction> {
|
||||
let mut action = None;
|
||||
egui::Frame::new()
|
||||
.inner_margin(Margin::symmetric(48, 24))
|
||||
.show(ui, |ui| {
|
||||
StripBuilder::new(ui)
|
||||
.sizes(egui_extras::Size::exact(48.0), 2)
|
||||
.size(egui_extras::Size::exact(80.0))
|
||||
.vertical(|mut strip| {
|
||||
strip.cell(|ui| {
|
||||
if ui
|
||||
.with_layout(Layout::left_to_right(egui::Align::Center), |ui| {
|
||||
let r = ui.add(
|
||||
app_images::repost_image(ui.visuals().dark_mode)
|
||||
.max_height(24.0)
|
||||
.sense(Sense::click()),
|
||||
);
|
||||
r.union(ui.add(repost_item_text("Repost")))
|
||||
})
|
||||
.inner
|
||||
.on_hover_cursor(egui::CursorIcon::PointingHand)
|
||||
.clicked()
|
||||
{
|
||||
action = Some(RepostAction::Kind06Repost(*self.noteid))
|
||||
}
|
||||
});
|
||||
|
||||
strip.cell(|ui| {
|
||||
if ui
|
||||
.with_layout(Layout::left_to_right(egui::Align::Center), |ui| {
|
||||
let r = ui
|
||||
.add(quote_icon())
|
||||
.on_hover_cursor(egui::CursorIcon::PointingHand);
|
||||
r.union(ui.add(repost_item_text("Quote")))
|
||||
})
|
||||
.inner
|
||||
.on_hover_cursor(egui::CursorIcon::PointingHand)
|
||||
.clicked()
|
||||
{
|
||||
action = Some(RepostAction::Quote(*self.noteid))
|
||||
}
|
||||
});
|
||||
|
||||
strip.cell(|ui| {
|
||||
ui.add_space(16.0);
|
||||
let resp = ui.allocate_response(
|
||||
vec2(ui.available_width(), 48.0),
|
||||
Sense::click(),
|
||||
);
|
||||
|
||||
let color = if resp.hovered() {
|
||||
ui.visuals().widgets.hovered.bg_fill
|
||||
} else {
|
||||
ui.visuals().text_color()
|
||||
};
|
||||
|
||||
let painter = ui.painter_at(resp.rect);
|
||||
ui.painter().rect_stroke(
|
||||
resp.rect,
|
||||
CornerRadius::same(32),
|
||||
egui::Stroke::new(1.5, color),
|
||||
egui::StrokeKind::Inside,
|
||||
);
|
||||
|
||||
let galley = painter.layout_no_wrap(
|
||||
"Cancel".to_owned(),
|
||||
NotedeckTextStyle::Heading3.get_font_id(ui.ctx()),
|
||||
ui.visuals().text_color(),
|
||||
);
|
||||
|
||||
painter.galley(
|
||||
galley_top_left_from_center(&galley, resp.rect.center()),
|
||||
galley,
|
||||
ui.visuals().text_color(),
|
||||
);
|
||||
|
||||
if resp.clicked() {
|
||||
action = Some(RepostAction::Cancel);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
action
|
||||
}
|
||||
}
|
||||
|
||||
fn galley_top_left_from_center(galley: &std::sync::Arc<egui::Galley>, center: Pos2) -> Pos2 {
|
||||
let mut top_left = center;
|
||||
top_left.x -= galley.rect.width() / 2.0;
|
||||
top_left.y -= galley.rect.height() / 2.0;
|
||||
|
||||
top_left
|
||||
}
|
||||
|
||||
fn repost_item_text(text: &str) -> impl egui::Widget + use<'_> {
|
||||
move |ui: &mut egui::Ui| -> egui::Response {
|
||||
ui.add(egui::Label::new(
|
||||
RichText::new(text).size(get_font_size(ui.ctx(), &NotedeckTextStyle::Heading3)),
|
||||
))
|
||||
.on_hover_cursor(egui::CursorIcon::PointingHand)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn quote_icon() -> impl egui::Widget {
|
||||
move |ui: &mut egui::Ui| -> egui::Response {
|
||||
let h = 32.0; // scaling constant
|
||||
let color = ui.visuals().strong_text_color();
|
||||
let r = h * 0.12; // dot radius
|
||||
let arc_r = r * 2.0; // larger so it protrudes above
|
||||
let sw = h * 0.06; // stroke width
|
||||
let stroke = Stroke::new(sw, color);
|
||||
|
||||
// Same horizontal layout as before (in "local" coords using height scale)
|
||||
let cx1_raw = h * 0.34;
|
||||
let cx2_raw = h * 0.72;
|
||||
let gap = cx2_raw - cx1_raw;
|
||||
|
||||
// Bounds including stroke (only the left side needs +sw/2 for arcs)
|
||||
let left_bound = (cx1_raw - r) - sw * 0.5;
|
||||
let right_bound = (cx2_raw + r).max(cx2_raw + (arc_r - r)); // safe if arc_r > 2r
|
||||
let width = right_bound - left_bound;
|
||||
|
||||
// Vertical bounds: arc top needs sw/2; total content height = arc_r + r + sw/2
|
||||
let content_h = arc_r + r + sw * 0.5;
|
||||
let v_margin = (h - content_h) * 0.5;
|
||||
|
||||
let resp = ui.allocate_response(vec2(width, h), egui::Sense::click());
|
||||
let rect = resp.rect;
|
||||
let origin = rect.min;
|
||||
|
||||
// Place centers with bounds aligned to rect
|
||||
let dx = origin.x - left_bound;
|
||||
let cy = origin.y + v_margin + arc_r + sw * 0.5;
|
||||
|
||||
let c1 = pos2(dx + cx1_raw, cy);
|
||||
let c2 = pos2(dx + cx1_raw + gap, cy);
|
||||
|
||||
// arc centers (unchanged)
|
||||
let a1 = pos2(c1.x + (arc_r - r) + 0.8, c1.y);
|
||||
let a2 = pos2(c2.x + (arc_r - r) + 0.8, c2.y);
|
||||
|
||||
// Draw arcs FIRST (upper-left quadrant [π, 3π/2])
|
||||
let arc = |ac: egui::Pos2| {
|
||||
let steps = 16;
|
||||
(0..=steps)
|
||||
.map(|i| {
|
||||
let t = i as f32 / steps as f32;
|
||||
let ang = PI + t * (PI * 0.5);
|
||||
pos2(ac.x + arc_r * ang.cos(), ac.y + arc_r * ang.sin())
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let painter = ui.painter_at(rect);
|
||||
painter.add(Shape::Path(PathShape::line(arc(a1), stroke)));
|
||||
painter.add(Shape::Path(PathShape::line(arc(a2), stroke)));
|
||||
|
||||
// Dots LAST to hide the junction
|
||||
painter.circle_filled(c1, r, color);
|
||||
painter.circle_filled(c2, r, color);
|
||||
|
||||
resp
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user