context: implement note broadcasting
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(¬e).expect("note client message"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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, ¬e, 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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, ¬e);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.action
|
response.action
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -374,10 +389,6 @@ fn render_nav_body(
|
|||||||
})
|
})
|
||||||
.inner;
|
.inner;
|
||||||
|
|
||||||
if let Some(selection) = response.context_selection {
|
|
||||||
selection.process(ui, ¬e);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.action.map(Into::into)
|
response.action.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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(¬e)?);
|
||||||
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(
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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, ¬e);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ui::hline(ui);
|
ui::hline(ui);
|
||||||
|
|||||||
Reference in New Issue
Block a user