15
src/app.rs
15
src/app.rs
@@ -925,17 +925,10 @@ fn render_nav(routes: Vec<Route>, timeline_ind: usize, app: &mut Damus, ui: &mut
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let note_key = note.key().unwrap();
|
let id = egui::Id::new(("post", timeline_ind, note.key().unwrap()));
|
||||||
|
ui::PostReplyView::new(&mut app, ¬e)
|
||||||
let poster = app
|
.id_source(id)
|
||||||
.account_manager
|
.show(ui);
|
||||||
.get_selected_account_index()
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
let replying_to = note.pubkey();
|
|
||||||
ui::PostView::new(&mut app, poster, replying_to)
|
|
||||||
.id_source(("post", timeline_ind, note_key))
|
|
||||||
.ui(&txn, ui);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ impl<'a> View for AccountLoginView<'a> {
|
|||||||
if self.is_mobile {
|
if self.is_mobile {
|
||||||
self.show_mobile(ui);
|
self.show_mobile(ui);
|
||||||
} else {
|
} else {
|
||||||
self.show(ui);
|
self.ui(ui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ impl<'a> AccountLoginView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ui: &mut egui::Ui) -> egui::Response {
|
fn ui(&mut self, ui: &mut egui::Ui) -> egui::Response {
|
||||||
let screen_width = ui.ctx().screen_rect().max.x;
|
let screen_width = ui.ctx().screen_rect().max.x;
|
||||||
let screen_height = ui.ctx().screen_rect().max.y;
|
let screen_height = ui.ctx().screen_rect().max.y;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ pub mod username;
|
|||||||
pub use account_management::AccountManagementView;
|
pub use account_management::AccountManagementView;
|
||||||
pub use account_switcher::AccountSelectionWidget;
|
pub use account_switcher::AccountSelectionWidget;
|
||||||
pub use mention::Mention;
|
pub use mention::Mention;
|
||||||
pub use note::{BarAction, Note, NoteResponse, PostView};
|
pub use note::{BarAction, Note, NoteResponse, PostReplyView, PostView};
|
||||||
pub use preview::{Preview, PreviewApp, PreviewConfig};
|
pub use preview::{Preview, PreviewApp, PreviewConfig};
|
||||||
pub use profile::{profile_preview_controller, ProfilePic, ProfilePreview};
|
pub use profile::{profile_preview_controller, ProfilePic, ProfilePreview};
|
||||||
pub use relay::RelayView;
|
pub use relay::RelayView;
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
pub mod contents;
|
pub mod contents;
|
||||||
pub mod options;
|
pub mod options;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
|
pub mod reply;
|
||||||
|
|
||||||
pub use contents::NoteContents;
|
pub use contents::NoteContents;
|
||||||
pub use options::NoteOptions;
|
pub use options::NoteOptions;
|
||||||
pub use post::PostView;
|
pub use post::PostView;
|
||||||
|
pub use reply::PostReplyView;
|
||||||
|
|
||||||
use crate::{colors, notecache::CachedNote, ui, ui::View, Damus};
|
use crate::{colors, notecache::CachedNote, ui, ui::View, Damus};
|
||||||
use egui::{Label, RichText, Sense};
|
use egui::{Label, RichText, Sense};
|
||||||
@@ -128,6 +130,11 @@ impl<'a> Note<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn medium_pfp(mut self, enable: bool) -> Self {
|
||||||
|
self.options_mut().set_medium_pfp(enable);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn note_previews(mut self, enable: bool) -> Self {
|
pub fn note_previews(mut self, enable: bool) -> Self {
|
||||||
self.options_mut().set_note_previews(enable);
|
self.options_mut().set_note_previews(enable);
|
||||||
self
|
self
|
||||||
@@ -179,6 +186,10 @@ impl<'a> Note<'a> {
|
|||||||
.response
|
.response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expand_size() -> f32 {
|
||||||
|
5.0
|
||||||
|
}
|
||||||
|
|
||||||
fn pfp(
|
fn pfp(
|
||||||
&mut self,
|
&mut self,
|
||||||
note_key: NoteKey,
|
note_key: NoteKey,
|
||||||
@@ -188,7 +199,9 @@ impl<'a> Note<'a> {
|
|||||||
ui.spacing_mut().item_spacing.x = 16.0;
|
ui.spacing_mut().item_spacing.x = 16.0;
|
||||||
|
|
||||||
let pfp_size = if self.options().has_small_pfp() {
|
let pfp_size = if self.options().has_small_pfp() {
|
||||||
24.0
|
ui::ProfilePic::small_size()
|
||||||
|
} else if self.options().has_medium_pfp() {
|
||||||
|
ui::ProfilePic::medium_size()
|
||||||
} else {
|
} else {
|
||||||
ui::ProfilePic::default_size()
|
ui::ProfilePic::default_size()
|
||||||
};
|
};
|
||||||
@@ -201,7 +214,6 @@ impl<'a> Note<'a> {
|
|||||||
// these have different lifetimes and types,
|
// these have different lifetimes and types,
|
||||||
// so the calls must be separate
|
// so the calls must be separate
|
||||||
Some(pic) => {
|
Some(pic) => {
|
||||||
let expand_size = 5.0;
|
|
||||||
let anim_speed = 0.05;
|
let anim_speed = 0.05;
|
||||||
let profile_key = profile.as_ref().unwrap().record().note_key();
|
let profile_key = profile.as_ref().unwrap().record().note_key();
|
||||||
let note_key = note_key.as_u64();
|
let note_key = note_key.as_u64();
|
||||||
@@ -213,7 +225,7 @@ impl<'a> Note<'a> {
|
|||||||
ui,
|
ui,
|
||||||
egui::Id::new((profile_key, note_key)),
|
egui::Id::new((profile_key, note_key)),
|
||||||
pfp_size,
|
pfp_size,
|
||||||
expand_size,
|
ui::Note::expand_size(),
|
||||||
anim_speed,
|
anim_speed,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ bitflags! {
|
|||||||
const actionbar = 0b00000001;
|
const actionbar = 0b00000001;
|
||||||
const note_previews = 0b00000010;
|
const note_previews = 0b00000010;
|
||||||
const small_pfp = 0b00000100;
|
const small_pfp = 0b00000100;
|
||||||
const wide = 0b00001000;
|
const medium_pfp = 0b00001000;
|
||||||
|
const wide = 0b00010000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +29,11 @@ impl NoteOptions {
|
|||||||
(self & NoteOptions::small_pfp) == NoteOptions::small_pfp
|
(self & NoteOptions::small_pfp) == NoteOptions::small_pfp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn has_medium_pfp(self) -> bool {
|
||||||
|
(self & NoteOptions::medium_pfp) == NoteOptions::medium_pfp
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn has_wide(self) -> bool {
|
pub fn has_wide(self) -> bool {
|
||||||
(self & NoteOptions::wide) == NoteOptions::wide
|
(self & NoteOptions::wide) == NoteOptions::wide
|
||||||
@@ -41,6 +47,16 @@ impl NoteOptions {
|
|||||||
*self &= !NoteOptions::small_pfp;
|
*self &= !NoteOptions::small_pfp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_medium_pfp(&mut self, enable: bool) {
|
||||||
|
if enable {
|
||||||
|
*self |= NoteOptions::medium_pfp;
|
||||||
|
} else {
|
||||||
|
*self &= !NoteOptions::medium_pfp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_note_previews(&mut self, enable: bool) {
|
pub fn set_note_previews(&mut self, enable: bool) {
|
||||||
if enable {
|
if enable {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::app::Damus;
|
use crate::app::Damus;
|
||||||
|
use crate::draft::Draft;
|
||||||
use crate::ui;
|
use crate::ui;
|
||||||
use crate::ui::{Preview, PreviewConfig, View};
|
use crate::ui::{Preview, PreviewConfig, View};
|
||||||
use egui::widgets::text_edit::TextEdit;
|
use egui::widgets::text_edit::TextEdit;
|
||||||
use nostrdb::Transaction;
|
use nostrdb::Transaction;
|
||||||
use tracing::info;
|
|
||||||
|
|
||||||
pub struct PostView<'app, 'p> {
|
pub struct PostView<'app, 'p> {
|
||||||
app: &'app mut Damus,
|
app: &'app mut Damus,
|
||||||
@@ -13,6 +13,20 @@ pub struct PostView<'app, 'p> {
|
|||||||
replying_to: &'p [u8; 32],
|
replying_to: &'p [u8; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct NewPost {
|
||||||
|
pub content: String,
|
||||||
|
pub account: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum PostAction {
|
||||||
|
Post(NewPost),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PostResponse {
|
||||||
|
pub action: Option<PostAction>,
|
||||||
|
pub edit_response: egui::Response,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'app, 'p> PostView<'app, 'p> {
|
impl<'app, 'p> PostView<'app, 'p> {
|
||||||
pub fn new(app: &'app mut Damus, poster: usize, replying_to: &'p [u8; 32]) -> Self {
|
pub fn new(app: &'app mut Damus, poster: usize, replying_to: &'p [u8; 32]) -> Self {
|
||||||
let id_source: Option<egui::Id> = None;
|
let id_source: Option<egui::Id> = None;
|
||||||
@@ -29,7 +43,14 @@ impl<'app, 'p> PostView<'app, 'p> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editbox(&mut self, txn: &nostrdb::Transaction, ui: &mut egui::Ui) {
|
fn draft(&mut self) -> &mut Draft {
|
||||||
|
self.app
|
||||||
|
.drafts
|
||||||
|
.entry(enostr::NoteId::new(*self.replying_to))
|
||||||
|
.or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn editbox(&mut self, txn: &nostrdb::Transaction, ui: &mut egui::Ui) -> egui::Response {
|
||||||
ui.spacing_mut().item_spacing.x = 12.0;
|
ui.spacing_mut().item_spacing.x = 12.0;
|
||||||
|
|
||||||
let pfp_size = 24.0;
|
let pfp_size = 24.0;
|
||||||
@@ -61,17 +82,13 @@ impl<'app, 'p> PostView<'app, 'p> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let draft = self
|
let response = ui.add(TextEdit::multiline(&mut self.draft().buffer).frame(false));
|
||||||
.app
|
|
||||||
.drafts
|
|
||||||
.entry(enostr::NoteId::new(*self.replying_to))
|
|
||||||
.or_default();
|
|
||||||
|
|
||||||
let focused = ui
|
let focused = response.has_focus();
|
||||||
.add(TextEdit::multiline(&mut draft.buffer).frame(false))
|
|
||||||
.has_focus();
|
|
||||||
|
|
||||||
ui.ctx().data_mut(|d| d.insert_temp(self.id(), focused));
|
ui.ctx().data_mut(|d| d.insert_temp(self.id(), focused));
|
||||||
|
|
||||||
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focused(&self, ui: &egui::Ui) -> bool {
|
fn focused(&self, ui: &egui::Ui) -> bool {
|
||||||
@@ -83,7 +100,15 @@ impl<'app, 'p> PostView<'app, 'p> {
|
|||||||
self.id_source.unwrap_or_else(|| egui::Id::new("post"))
|
self.id_source.unwrap_or_else(|| egui::Id::new("post"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ui(&mut self, txn: &nostrdb::Transaction, ui: &mut egui::Ui) {
|
pub fn outer_margin() -> f32 {
|
||||||
|
16.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner_margin() -> f32 {
|
||||||
|
12.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ui(&mut self, txn: &nostrdb::Transaction, ui: &mut egui::Ui) -> PostResponse {
|
||||||
let focused = self.focused(ui);
|
let focused = self.focused(ui);
|
||||||
let stroke = if focused {
|
let stroke = if focused {
|
||||||
ui.visuals().selection.stroke
|
ui.visuals().selection.stroke
|
||||||
@@ -93,8 +118,8 @@ impl<'app, 'p> PostView<'app, 'p> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut frame = egui::Frame::default()
|
let mut frame = egui::Frame::default()
|
||||||
.inner_margin(egui::Margin::same(12.0))
|
.inner_margin(egui::Margin::same(PostView::inner_margin()))
|
||||||
.outer_margin(egui::Margin::same(12.0))
|
.outer_margin(egui::Margin::same(PostView::outer_margin()))
|
||||||
.fill(ui.visuals().extreme_bg_color)
|
.fill(ui.visuals().extreme_bg_color)
|
||||||
.stroke(stroke)
|
.stroke(stroke)
|
||||||
.rounding(12.0);
|
.rounding(12.0);
|
||||||
@@ -108,22 +133,35 @@ impl<'app, 'p> PostView<'app, 'p> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.show(ui, |ui| {
|
frame
|
||||||
ui.vertical(|ui| {
|
.show(ui, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.vertical(|ui| {
|
||||||
self.editbox(txn, ui);
|
let edit_response = ui.horizontal(|ui| self.editbox(txn, ui)).inner;
|
||||||
});
|
|
||||||
|
|
||||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
|
let action = ui
|
||||||
if ui
|
.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
|
||||||
.add_sized([91.0, 32.0], egui::Button::new("Post now"))
|
if ui
|
||||||
.clicked()
|
.add_sized([91.0, 32.0], egui::Button::new("Post now"))
|
||||||
{
|
.clicked()
|
||||||
info!("Post clicked");
|
{
|
||||||
|
Some(PostAction::Post(NewPost {
|
||||||
|
content: self.draft().buffer.clone(),
|
||||||
|
account: self.poster,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.inner;
|
||||||
|
|
||||||
|
PostResponse {
|
||||||
|
action,
|
||||||
|
edit_response,
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
});
|
.inner
|
||||||
});
|
})
|
||||||
|
.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,106 @@
|
|||||||
struct PostReplyView {}
|
use crate::{ui, Damus};
|
||||||
|
|
||||||
|
pub struct PostReplyView<'a> {
|
||||||
|
app: &'a mut Damus,
|
||||||
|
id_source: Option<egui::Id>,
|
||||||
|
note: &'a nostrdb::Note<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PostReplyView<'a> {
|
||||||
|
pub fn new(app: &'a mut Damus, note: &'a nostrdb::Note<'a>) -> Self {
|
||||||
|
let id_source: Option<egui::Id> = None;
|
||||||
|
PostReplyView {
|
||||||
|
app,
|
||||||
|
id_source,
|
||||||
|
note,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id_source(mut self, id: egui::Id) -> Self {
|
||||||
|
self.id_source = Some(id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> egui::Id {
|
||||||
|
self.id_source
|
||||||
|
.unwrap_or_else(|| egui::Id::new("post-reply-view"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show(&mut self, ui: &mut egui::Ui) {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
let avail_rect = ui.available_rect_before_wrap();
|
||||||
|
|
||||||
|
// This is the offset of the post view's pfp. We use this
|
||||||
|
// to indent things so that the reply line is aligned
|
||||||
|
let pfp_offset = ui::PostView::outer_margin()
|
||||||
|
+ ui::PostView::inner_margin()
|
||||||
|
+ ui::ProfilePic::small_size() / 2.0;
|
||||||
|
|
||||||
|
let note_offset =
|
||||||
|
pfp_offset - ui::ProfilePic::medium_size() / 2.0 - ui::Note::expand_size() / 2.0;
|
||||||
|
|
||||||
|
egui::Frame::none()
|
||||||
|
.outer_margin(egui::Margin::same(note_offset))
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui::Note::new(self.app, self.note)
|
||||||
|
.actionbar(false)
|
||||||
|
.medium_pfp(true)
|
||||||
|
.show(ui);
|
||||||
|
});
|
||||||
|
|
||||||
|
let poster = self
|
||||||
|
.app
|
||||||
|
.account_manager
|
||||||
|
.get_selected_account_index()
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let replying_to = self.note.pubkey();
|
||||||
|
let rect_before_post = ui.min_rect();
|
||||||
|
|
||||||
|
let id = self.id();
|
||||||
|
let post_response = ui::PostView::new(self.app, poster, replying_to)
|
||||||
|
.id_source(id)
|
||||||
|
.ui(self.note.txn().unwrap(), ui);
|
||||||
|
|
||||||
|
//
|
||||||
|
// reply line
|
||||||
|
//
|
||||||
|
|
||||||
|
// Position and draw the reply line
|
||||||
|
let mut rect = ui.min_rect();
|
||||||
|
|
||||||
|
// Position the line right above the poster's profile pic in
|
||||||
|
// the post box. Use the PostView's margin values to
|
||||||
|
// determine this offset.
|
||||||
|
rect.min.x = avail_rect.min.x + pfp_offset;
|
||||||
|
|
||||||
|
// honestly don't know what the fuck I'm doing here. just trying
|
||||||
|
// to get the line under the profile picture
|
||||||
|
rect.min.y = avail_rect.min.y
|
||||||
|
+ (ui::ProfilePic::medium_size() / 2.0
|
||||||
|
+ ui::ProfilePic::medium_size()
|
||||||
|
+ ui::Note::expand_size() * 2.0)
|
||||||
|
+ 1.0;
|
||||||
|
|
||||||
|
// For some reason we need to nudge the reply line's height a
|
||||||
|
// few more pixels?
|
||||||
|
let nudge = if post_response.edit_response.has_focus() {
|
||||||
|
// we nudge by one less pixel if focused, otherwise it
|
||||||
|
// overlaps the focused PostView purple border color
|
||||||
|
2.0
|
||||||
|
} else {
|
||||||
|
// we have to nudge by one more pixel when not focused
|
||||||
|
// otherwise it looks like there's a gap(?)
|
||||||
|
3.0
|
||||||
|
};
|
||||||
|
|
||||||
|
rect.max.y = rect_before_post.max.y + ui::PostView::outer_margin() + nudge;
|
||||||
|
|
||||||
|
ui.painter().vline(
|
||||||
|
rect.left(),
|
||||||
|
rect.y_range(),
|
||||||
|
ui.visuals().widgets.noninteractive.bg_stroke,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,14 +31,27 @@ impl<'cache, 'url> ProfilePic<'cache, 'url> {
|
|||||||
.map(|url| ProfilePic::new(cache, url))
|
.map(|url| ProfilePic::new(cache, url))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn default_size() -> f32 {
|
pub fn default_size() -> f32 {
|
||||||
38.0
|
38.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn medium_size() -> f32 {
|
||||||
|
32.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn small_size() -> f32 {
|
||||||
|
24.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn no_pfp_url() -> &'static str {
|
pub fn no_pfp_url() -> &'static str {
|
||||||
"https://damus.io/img/no-profile.svg"
|
"https://damus.io/img/no-profile.svg"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn size(mut self, size: f32) -> Self {
|
pub fn size(mut self, size: f32) -> Self {
|
||||||
self.size = size;
|
self.size = size;
|
||||||
self
|
self
|
||||||
|
|||||||
Reference in New Issue
Block a user