context: implement note broadcasting

Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
William Casarin
2025-04-10 10:39:40 -07:00
parent 956c557851
commit 50dec5b5d5
11 changed files with 150 additions and 97 deletions

View File

@@ -28,12 +28,16 @@ pub enum ClientMessage {
} }
impl ClientMessage { impl ClientMessage {
pub fn event(note: Note) -> Result<Self, Error> { pub fn event(note: &Note) -> Result<Self, Error> {
Ok(ClientMessage::Event(EventClientMessage { Ok(ClientMessage::Event(EventClientMessage {
note_json: note.json()?, note_json: note.json()?,
})) }))
} }
pub fn event_json(note_json: String) -> Result<Self, Error> {
Ok(ClientMessage::Event(EventClientMessage { note_json }))
}
pub fn raw(raw: String) -> Self { pub fn raw(raw: String) -> Self {
ClientMessage::Raw(raw) ClientMessage::Raw(raw)
} }

View File

@@ -180,7 +180,7 @@ impl AccountRelayData {
} }
} }
let note = builder.sign(seckey).build().expect("note build"); let note = builder.sign(seckey).build().expect("note build");
pool.send(&enostr::ClientMessage::event(note).expect("note client message")); pool.send(&enostr::ClientMessage::event(&note).expect("note client message"));
} }
} }

View File

@@ -2,6 +2,7 @@ use crate::{
column::Columns, column::Columns,
route::{Route, Router}, route::{Route, Router},
timeline::{TimelineCache, TimelineKind}, timeline::{TimelineCache, TimelineKind},
ui::note::NoteContextSelection,
}; };
use enostr::{NoteId, Pubkey, RelayPool}; use enostr::{NoteId, Pubkey, RelayPool};
@@ -12,11 +13,18 @@ use notedeck::{
}; };
use tracing::error; use tracing::error;
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct ContextSelection {
pub note_key: NoteKey,
pub action: NoteContextSelection,
}
#[derive(Debug, Eq, PartialEq, Clone)] #[derive(Debug, Eq, PartialEq, Clone)]
pub enum NoteAction { pub enum NoteAction {
Reply(NoteId), Reply(NoteId),
Quote(NoteId), Quote(NoteId),
OpenTimeline(TimelineKind), OpenTimeline(TimelineKind),
Context(ContextSelection),
Zap(ZapAction), Zap(ZapAction),
} }
@@ -48,6 +56,7 @@ impl NoteAction {
accounts: &mut Accounts, accounts: &mut Accounts,
global_wallet: &mut GlobalWallet, global_wallet: &mut GlobalWallet,
zaps: &mut Zaps, zaps: &mut Zaps,
ui: &mut egui::Ui,
) -> Option<TimelineOpenResult> { ) -> Option<TimelineOpenResult> {
match self { match self {
NoteAction::Reply(note_id) => { NoteAction::Reply(note_id) => {
@@ -89,6 +98,16 @@ impl NoteAction {
None None
} }
NoteAction::Context(context) => {
match ndb.get_note_by_key(txn, context.note_key) {
Err(err) => tracing::error!("{err}"),
Ok(note) => {
context.action.process(ui, &note, pool);
}
}
None
}
} }
} }
@@ -107,6 +126,7 @@ impl NoteAction {
accounts: &mut Accounts, accounts: &mut Accounts,
global_wallet: &mut GlobalWallet, global_wallet: &mut GlobalWallet,
zaps: &mut Zaps, zaps: &mut Zaps,
ui: &mut egui::Ui,
) { ) {
let router = columns.column_mut(col).router_mut(); let router = columns.column_mut(col).router_mut();
if let Some(br) = self.execute( if let Some(br) = self.execute(
@@ -119,6 +139,7 @@ impl NoteAction {
accounts, accounts,
global_wallet, global_wallet,
zaps, zaps,
ui,
) { ) {
br.process(ndb, note_cache, txn, timeline_cache, unknown_ids); br.process(ndb, note_cache, txn, timeline_cache, unknown_ids);
} }

View File

@@ -513,7 +513,7 @@ fn render_damus_mobile(app: &mut Damus, app_ctx: &mut AppContext<'_>, ui: &mut e
if !app.columns(app_ctx.accounts).columns().is_empty() if !app.columns(app_ctx.accounts).columns().is_empty()
&& nav::render_nav(0, ui.available_rect_before_wrap(), app, app_ctx, ui) && nav::render_nav(0, ui.available_rect_before_wrap(), app, app_ctx, ui)
.process_render_nav_response(app, app_ctx) .process_render_nav_response(app, app_ctx, ui)
&& !app.tmp_columns && !app.tmp_columns
{ {
storage::save_decks_cache(app_ctx.path, &app.decks_cache); storage::save_decks_cache(app_ctx.path, &app.decks_cache);
@@ -546,12 +546,14 @@ fn render_damus_desktop(app: &mut Damus, app_ctx: &mut AppContext<'_>, ui: &mut
fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus, ctx: &mut AppContext<'_>) { fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus, ctx: &mut AppContext<'_>) {
let num_cols = get_active_columns(ctx.accounts, &app.decks_cache).num_columns(); let num_cols = get_active_columns(ctx.accounts, &app.decks_cache).num_columns();
let mut side_panel_action: Option<nav::SwitchingAction> = None;
let mut responses = Vec::with_capacity(num_cols);
StripBuilder::new(ui) StripBuilder::new(ui)
.size(Size::exact(ui::side_panel::SIDE_PANEL_WIDTH)) .size(Size::exact(ui::side_panel::SIDE_PANEL_WIDTH))
.sizes(sizes, num_cols) .sizes(sizes, num_cols)
.clip(true) .clip(true)
.horizontal(|mut strip| { .horizontal(|mut strip| {
let mut side_panel_action: Option<nav::SwitchingAction> = None;
strip.cell(|ui| { strip.cell(|ui| {
let rect = ui.available_rect_before_wrap(); let rect = ui.available_rect_before_wrap();
let side_panel = let side_panel =
@@ -589,7 +591,6 @@ fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus, ctx: &mut App
); );
}); });
let mut responses = Vec::with_capacity(num_cols);
for col_index in 0..num_cols { for col_index in 0..num_cols {
strip.cell(|ui| { strip.cell(|ui| {
let rect = ui.available_rect_before_wrap(); let rect = ui.available_rect_before_wrap();
@@ -604,32 +605,36 @@ fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus, ctx: &mut App
// vertical line // vertical line
ui.painter() ui.painter()
.vline(rect.right(), rect.y_range(), v_line_stroke); .vline(rect.right(), rect.y_range(), v_line_stroke);
// we need borrow ui context for processing, so proces
// responses in the last cell
if col_index == num_cols - 1 {}
}); });
//strip.cell(|ui| timeline::timeline_view(ui, app, timeline_ind)); //strip.cell(|ui| timeline::timeline_view(ui, app, timeline_ind));
} }
// process the side panel action after so we don't change the number of columns during
// StripBuilder rendering
let mut save_cols = false;
if let Some(action) = side_panel_action {
save_cols =
save_cols || action.process(&mut app.timeline_cache, &mut app.decks_cache, ctx);
}
for response in responses {
let save = response.process_render_nav_response(app, ctx);
save_cols = save_cols || save;
}
if app.tmp_columns {
save_cols = false;
}
if save_cols {
storage::save_decks_cache(ctx.path, &app.decks_cache);
}
}); });
// process the side panel action after so we don't change the number of columns during
// StripBuilder rendering
let mut save_cols = false;
if let Some(action) = side_panel_action {
save_cols = save_cols || action.process(&mut app.timeline_cache, &mut app.decks_cache, ctx);
}
for response in responses {
let save = response.process_render_nav_response(app, ctx, ui);
save_cols = save_cols || save;
}
if app.tmp_columns {
save_cols = false;
}
if save_cols {
storage::save_decks_cache(ctx.path, &app.decks_cache);
}
} }
impl notedeck::App for Damus { impl notedeck::App for Damus {

View File

@@ -16,7 +16,7 @@ use crate::{
column::NavTitle, column::NavTitle,
configure_deck::ConfigureDeckView, configure_deck::ConfigureDeckView,
edit_deck::{EditDeckResponse, EditDeckView}, edit_deck::{EditDeckResponse, EditDeckView},
note::{contents::NoteContext, PostAction, PostType}, note::{contents::NoteContext, NewPostAction, PostAction, PostType},
profile::EditProfileView, profile::EditProfileView,
search::{FocusState, SearchView}, search::{FocusState, SearchView},
support::SupportView, support::SupportView,
@@ -35,7 +35,7 @@ use tracing::error;
pub enum RenderNavAction { pub enum RenderNavAction {
Back, Back,
RemoveColumn, RemoveColumn,
PostAction(PostAction), PostAction(NewPostAction),
NoteAction(NoteAction), NoteAction(NoteAction),
ProfileAction(ProfileAction), ProfileAction(ProfileAction),
SwitchingAction(SwitchingAction), SwitchingAction(SwitchingAction),
@@ -100,6 +100,15 @@ impl SwitchingAction {
impl From<PostAction> for RenderNavAction { impl From<PostAction> for RenderNavAction {
fn from(post_action: PostAction) -> Self { fn from(post_action: PostAction) -> Self {
match post_action {
PostAction::QuotedNoteAction(note_action) => Self::NoteAction(note_action),
PostAction::NewPostAction(new_post) => Self::PostAction(new_post),
}
}
}
impl From<NewPostAction> for RenderNavAction {
fn from(post_action: NewPostAction) -> Self {
Self::PostAction(post_action) Self::PostAction(post_action)
} }
} }
@@ -124,7 +133,12 @@ impl RenderNavResponse {
} }
#[must_use = "Make sure to save columns if result is true"] #[must_use = "Make sure to save columns if result is true"]
pub fn process_render_nav_response(&self, app: &mut Damus, ctx: &mut AppContext<'_>) -> bool { pub fn process_render_nav_response(
&self,
app: &mut Damus,
ctx: &mut AppContext<'_>,
ui: &mut egui::Ui,
) -> bool {
let mut switching_occured: bool = false; let mut switching_occured: bool = false;
let col = self.column; let col = self.column;
@@ -155,9 +169,12 @@ impl RenderNavResponse {
switching_occured = true; switching_occured = true;
} }
RenderNavAction::PostAction(post_action) => { RenderNavAction::PostAction(new_post_action) => {
let txn = Transaction::new(ctx.ndb).expect("txn"); let txn = Transaction::new(ctx.ndb).expect("txn");
let _ = post_action.execute(ctx.ndb, &txn, ctx.pool, &mut app.drafts); match new_post_action.execute(ctx.ndb, &txn, ctx.pool, &mut app.drafts) {
Err(err) => tracing::error!("Error executing post action: {err}"),
Ok(_) => tracing::debug!("Post action executed"),
}
get_active_columns_mut(ctx.accounts, &mut app.decks_cache) get_active_columns_mut(ctx.accounts, &mut app.decks_cache)
.column_mut(col) .column_mut(col)
.router_mut() .router_mut()
@@ -179,6 +196,7 @@ impl RenderNavResponse {
ctx.accounts, ctx.accounts,
ctx.global_wallet, ctx.global_wallet,
ctx.zaps, ctx.zaps,
ui,
); );
} }
@@ -260,6 +278,7 @@ fn render_nav_body(
img_cache: ctx.img_cache, img_cache: ctx.img_cache,
note_cache: ctx.note_cache, note_cache: ctx.note_cache,
zaps: ctx.zaps, zaps: ctx.zaps,
pool: ctx.pool,
}; };
match top { match top {
Route::Timeline(kind) => render_timeline_route( Route::Timeline(kind) => render_timeline_route(
@@ -334,10 +353,6 @@ fn render_nav_body(
}) })
.inner; .inner;
if let Some(selection) = response.context_selection {
selection.process(ui, &note);
}
response.action response.action
}; };
@@ -374,10 +389,6 @@ fn render_nav_body(
}) })
.inner; .inner;
if let Some(selection) = response.context_selection {
selection.process(ui, &note);
}
response.action.map(Into::into) response.action.map(Into::into)
} }

View File

@@ -4,7 +4,7 @@ use crate::ui::{
}; };
use crate::{actionbar::NoteAction, timeline::TimelineKind}; use crate::{actionbar::NoteAction, timeline::TimelineKind};
use egui::{Button, Color32, Hyperlink, Image, Response, RichText, Sense, Window}; use egui::{Button, Color32, Hyperlink, Image, Response, RichText, Sense, Window};
use enostr::KeypairUnowned; use enostr::{KeypairUnowned, RelayPool};
use nostrdb::{BlockType, Mention, Ndb, Note, NoteKey, Transaction}; use nostrdb::{BlockType, Mention, Ndb, Note, NoteKey, Transaction};
use notedeck_ui::images::ImageType; use notedeck_ui::images::ImageType;
use notedeck_ui::{ use notedeck_ui::{
@@ -22,6 +22,7 @@ pub struct NoteContext<'d> {
pub img_cache: &'d mut Images, pub img_cache: &'d mut Images,
pub note_cache: &'d mut NoteCache, pub note_cache: &'d mut NoteCache,
pub zaps: &'d mut Zaps, pub zaps: &'d mut Zaps,
pub pool: &'d mut RelayPool,
} }
pub struct NoteContents<'a, 'd> { pub struct NoteContents<'a, 'd> {

View File

@@ -1,20 +1,25 @@
use egui::{Rect, Vec2}; use egui::{Rect, Vec2};
use enostr::{NoteId, Pubkey}; use enostr::{ClientMessage, NoteId, Pubkey, RelayPool};
use nostrdb::{Note, NoteKey}; use nostrdb::{Note, NoteKey};
use tracing::error; use tracing::error;
#[derive(Clone)] #[derive(Debug, Clone, Eq, PartialEq)]
#[allow(clippy::enum_variant_names)] #[allow(clippy::enum_variant_names)]
pub enum NoteContextSelection { pub enum NoteContextSelection {
CopyText, CopyText,
CopyPubkey, CopyPubkey,
CopyNoteId, CopyNoteId,
CopyNoteJSON, CopyNoteJSON,
Broadcast,
} }
impl NoteContextSelection { impl NoteContextSelection {
pub fn process(&self, ui: &mut egui::Ui, note: &Note<'_>) { pub fn process(&self, ui: &mut egui::Ui, note: &Note<'_>, pool: &mut RelayPool) {
match self { match self {
NoteContextSelection::Broadcast => {
tracing::info!("Broadcasting note {}", hex::encode(note.id()));
pool.send(&ClientMessage::event(note).unwrap());
}
NoteContextSelection::CopyText => { NoteContextSelection::CopyText => {
ui.ctx().copy_text(note.content().to_string()); ui.ctx().copy_text(note.content().to_string());
} }
@@ -161,6 +166,10 @@ impl NoteContextButton {
context_selection = Some(NoteContextSelection::CopyNoteJSON); context_selection = Some(NoteContextSelection::CopyNoteJSON);
ui.close_menu(); ui.close_menu();
} }
if ui.button("Broadcast").clicked() {
context_selection = Some(NoteContextSelection::Broadcast);
ui.close_menu();
}
}); });
context_selection context_selection

View File

@@ -10,13 +10,13 @@ pub use contents::NoteContents;
use contents::NoteContext; use contents::NoteContext;
pub use context::{NoteContextButton, NoteContextSelection}; pub use context::{NoteContextButton, NoteContextSelection};
pub use options::NoteOptions; pub use options::NoteOptions;
pub use post::{PostAction, PostResponse, PostType, PostView}; pub use post::{NewPostAction, PostAction, PostResponse, PostType, PostView};
pub use quote_repost::QuoteRepostView; pub use quote_repost::QuoteRepostView;
pub use reply::PostReplyView; pub use reply::PostReplyView;
pub use reply_description::reply_desc; pub use reply_description::reply_desc;
use crate::{ use crate::{
actionbar::{NoteAction, ZapAction}, actionbar::{ContextSelection, NoteAction, ZapAction},
profile::get_display_name, profile::get_display_name,
timeline::{ThreadSelection, TimelineKind}, timeline::{ThreadSelection, TimelineKind},
ui::{self, View}, ui::{self, View},
@@ -43,7 +43,6 @@ pub struct NoteView<'a, 'd> {
pub struct NoteResponse { pub struct NoteResponse {
pub response: egui::Response, pub response: egui::Response,
pub context_selection: Option<NoteContextSelection>,
pub action: Option<NoteAction>, pub action: Option<NoteAction>,
} }
@@ -51,7 +50,6 @@ impl NoteResponse {
pub fn new(response: egui::Response) -> Self { pub fn new(response: egui::Response) -> Self {
Self { Self {
response, response,
context_selection: None,
action: None, action: None,
} }
} }
@@ -60,11 +58,6 @@ impl NoteResponse {
self.action = action; self.action = action;
self self
} }
pub fn select_option(mut self, context_selection: Option<NoteContextSelection>) -> Self {
self.context_selection = context_selection;
self
}
} }
impl View for NoteView<'_, '_> { impl View for NoteView<'_, '_> {
@@ -338,7 +331,6 @@ impl<'a, 'd> NoteView<'a, 'd> {
let txn = self.note.txn().expect("todo: support non-db notes"); let txn = self.note.txn().expect("todo: support non-db notes");
let mut note_action: Option<NoteAction> = None; let mut note_action: Option<NoteAction> = None;
let mut selected_option: Option<NoteContextSelection> = None;
let hitbox_id = note_hitbox_id(note_key, self.options(), self.parent); let hitbox_id = note_hitbox_id(note_key, self.options(), self.parent);
let profile = self let profile = self
@@ -505,7 +497,9 @@ impl<'a, 'd> NoteView<'a, 'd> {
}; };
let resp = ui.add(NoteContextButton::new(note_key).place_at(context_pos)); let resp = ui.add(NoteContextButton::new(note_key).place_at(context_pos));
selected_option = NoteContextButton::menu(ui, resp.clone()); if let Some(action) = NoteContextButton::menu(ui, resp.clone()) {
note_action = Some(NoteAction::Context(ContextSelection { note_key, action }));
}
} }
let note_action = if note_hitbox_clicked(ui, hitbox_id, &response.rect, maybe_hitbox) { let note_action = if note_hitbox_clicked(ui, hitbox_id, &response.rect, maybe_hitbox) {
@@ -523,9 +517,7 @@ impl<'a, 'd> NoteView<'a, 'd> {
note_action note_action
}; };
NoteResponse::new(response) NoteResponse::new(response).with_action(note_action)
.with_action(note_action)
.select_option(selected_option)
} }
} }

View File

@@ -1,3 +1,4 @@
use crate::actionbar::NoteAction;
use crate::draft::{Draft, Drafts, MentionHint}; use crate::draft::{Draft, Drafts, MentionHint};
use crate::media_upload::{nostrbuild_nip96_upload, MediaPath}; use crate::media_upload::{nostrbuild_nip96_upload, MediaPath};
use crate::post::{downcast_post_buffer, MentionType, NewPost}; use crate::post::{downcast_post_buffer, MentionType, NewPost};
@@ -20,7 +21,6 @@ use notedeck::supported_mime_hosted_at_url;
use tracing::error; use tracing::error;
use super::contents::{render_note_preview, NoteContext}; use super::contents::{render_note_preview, NoteContext};
use super::NoteContextSelection;
use super::NoteOptions; use super::NoteOptions;
pub struct PostView<'a, 'd> { pub struct PostView<'a, 'd> {
@@ -40,14 +40,22 @@ pub enum PostType {
Reply(NoteId), Reply(NoteId),
} }
pub struct PostAction { pub enum PostAction {
/// The NoteAction on a note you are replying to.
QuotedNoteAction(NoteAction),
/// The reply/new post action
NewPostAction(NewPostAction),
}
pub struct NewPostAction {
post_type: PostType, post_type: PostType,
post: NewPost, post: NewPost,
} }
impl PostAction { impl NewPostAction {
pub fn new(post_type: PostType, post: NewPost) -> Self { pub fn new(post_type: PostType, post: NewPost) -> Self {
PostAction { post_type, post } NewPostAction { post_type, post }
} }
pub fn execute( pub fn execute(
@@ -73,7 +81,7 @@ impl PostAction {
} }
}; };
pool.send(&enostr::ClientMessage::event(note)?); pool.send(&enostr::ClientMessage::event(&note)?);
drafts.get_from_post_type(&self.post_type).clear(); drafts.get_from_post_type(&self.post_type).clear();
Ok(()) Ok(())
@@ -83,7 +91,6 @@ impl PostAction {
pub struct PostResponse { pub struct PostResponse {
pub action: Option<PostAction>, pub action: Option<PostAction>,
pub edit_response: egui::Response, pub edit_response: egui::Response,
pub context_selection: Option<NoteContextSelection>,
} }
impl<'a, 'd> PostView<'a, 'd> { impl<'a, 'd> PostView<'a, 'd> {
@@ -321,32 +328,34 @@ impl<'a, 'd> PostView<'a, 'd> {
.show(ui, |ui| { .show(ui, |ui| {
ui.vertical(|ui| { ui.vertical(|ui| {
let edit_response = ui.horizontal(|ui| self.editbox(txn, ui)).inner; let edit_response = ui.horizontal(|ui| self.editbox(txn, ui)).inner;
let mut context_selection = None;
if let PostType::Quote(id) = self.post_type { let note_response = if let PostType::Quote(id) = self.post_type {
let avail_size = ui.available_size_before_wrap(); let avail_size = ui.available_size_before_wrap();
ui.with_layout(Layout::left_to_right(egui::Align::TOP), |ui| { Some(
context_selection = Frame::NONE ui.with_layout(Layout::left_to_right(egui::Align::TOP), |ui| {
.show(ui, |ui| { Frame::NONE
ui.vertical(|ui| { .show(ui, |ui| {
ui.set_max_width(avail_size.x * 0.8); ui.vertical(|ui| {
let resp = render_note_preview( ui.set_max_width(avail_size.x * 0.8);
ui, render_note_preview(
self.note_context, ui,
&Some(self.poster.into()), self.note_context,
txn, &Some(self.poster.into()),
id.bytes(), txn,
nostrdb::NoteKey::new(0), id.bytes(),
self.note_options, nostrdb::NoteKey::new(0),
); self.note_options,
resp )
})
.inner
}) })
.inner .inner
.context_selection })
}) .inner,
.inner; )
}); } else {
} None
};
Frame::new() Frame::new()
.inner_margin(Margin::symmetric(0, 8)) .inner_margin(Margin::symmetric(0, 8))
@@ -362,7 +371,7 @@ impl<'a, 'd> PostView<'a, 'd> {
self.transfer_uploads(ui); self.transfer_uploads(ui);
self.show_upload_errors(ui); self.show_upload_errors(ui);
let action = ui let post_action = ui
.horizontal(|ui| { .horizontal(|ui| {
ui.with_layout( ui.with_layout(
egui::Layout::left_to_right(egui::Align::BOTTOM), egui::Layout::left_to_right(egui::Align::BOTTOM),
@@ -394,7 +403,7 @@ impl<'a, 'd> PostView<'a, 'd> {
self.draft.uploaded_media.clone(), self.draft.uploaded_media.clone(),
output.mentions, output.mentions,
); );
Some(PostAction::new(self.post_type.clone(), new_post)) Some(NewPostAction::new(self.post_type.clone(), new_post))
} else { } else {
None None
} }
@@ -403,10 +412,13 @@ impl<'a, 'd> PostView<'a, 'd> {
}) })
.inner; .inner;
let action = note_response
.and_then(|nr| nr.action.map(PostAction::QuotedNoteAction))
.or(post_action.map(PostAction::NewPostAction));
PostResponse { PostResponse {
action, action,
edit_response, edit_response,
context_selection,
} }
}) })
.inner .inner
@@ -736,6 +748,7 @@ mod preview {
img_cache: app.img_cache, img_cache: app.img_cache,
note_cache: app.note_cache, note_cache: app.note_cache,
zaps: app.zaps, zaps: app.zaps,
pool: app.pool,
}; };
PostView::new( PostView::new(

View File

@@ -1,6 +1,6 @@
use crate::draft::Draft; use crate::draft::Draft;
use crate::ui; use crate::ui;
use crate::ui::note::{PostResponse, PostType}; use crate::ui::note::{PostAction, PostResponse, PostType};
use enostr::{FilledKeypair, NoteId}; use enostr::{FilledKeypair, NoteId};
use super::contents::NoteContext; use super::contents::NoteContext;
@@ -61,7 +61,7 @@ impl<'a, 'd> PostReplyView<'a, 'd> {
let note_offset: i8 = let note_offset: i8 =
pfp_offset - ui::ProfilePic::medium_size() / 2 - ui::NoteView::expand_size() / 2; pfp_offset - ui::ProfilePic::medium_size() / 2 - ui::NoteView::expand_size() / 2;
let selection = egui::Frame::NONE let quoted_note = egui::Frame::NONE
.outer_margin(egui::Margin::same(note_offset)) .outer_margin(egui::Margin::same(note_offset))
.show(ui, |ui| { .show(ui, |ui| {
ui::NoteView::new( ui::NoteView::new(
@@ -75,8 +75,7 @@ impl<'a, 'd> PostReplyView<'a, 'd> {
.options_button(true) .options_button(true)
.show(ui) .show(ui)
}) })
.inner .inner;
.context_selection;
let id = self.id(); let id = self.id();
let replying_to = self.note.id(); let replying_to = self.note.id();
@@ -95,7 +94,9 @@ impl<'a, 'd> PostReplyView<'a, 'd> {
.ui(self.note.txn().unwrap(), ui) .ui(self.note.txn().unwrap(), ui)
}; };
post_response.context_selection = selection; post_response.action = post_response
.action
.or(quoted_note.action.map(PostAction::QuotedNoteAction));
// //
// reply line // reply line

View File

@@ -407,10 +407,6 @@ impl<'a, 'd> TimelineTabView<'a, 'd> {
if let Some(note_action) = resp.action { if let Some(note_action) = resp.action {
action = Some(note_action) action = Some(note_action)
} }
if let Some(context) = resp.context_selection {
context.process(ui, &note);
}
}); });
ui::hline(ui); ui::hline(ui);