mirror of
https://github.com/damus-io/notedeck.git
synced 2024-10-18 19:23:27 +00:00
Merge 'Initial quote reposts #305'
kernelkind (6): post quote reposts impl make PostActionExecutor for code reuse add repost button address PR comments make views pure minor cleanup
This commit is contained in:
commit
2208e68726
@ -6,6 +6,8 @@ use std::hash::{Hash, Hasher};
|
|||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub struct NoteId([u8; 32]);
|
pub struct NoteId([u8; 32]);
|
||||||
|
|
||||||
|
static HRP_NOTE: nostr::bech32::Hrp = nostr::bech32::Hrp::parse_unchecked("note");
|
||||||
|
|
||||||
impl NoteId {
|
impl NoteId {
|
||||||
pub fn new(bytes: [u8; 32]) -> Self {
|
pub fn new(bytes: [u8; 32]) -> Self {
|
||||||
NoteId(bytes)
|
NoteId(bytes)
|
||||||
@ -23,6 +25,10 @@ impl NoteId {
|
|||||||
let evid = NoteId(hex::decode(hex_str)?.as_slice().try_into().unwrap());
|
let evid = NoteId(hex::decode(hex_str)?.as_slice().try_into().unwrap());
|
||||||
Ok(evid)
|
Ok(evid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_bech(&self) -> Option<String> {
|
||||||
|
nostr::bech32::encode::<nostr::bech32::Bech32>(HRP_NOTE, &self.0).ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Event is the struct used to represent a Nostr event
|
/// Event is the struct used to represent a Nostr event
|
||||||
|
@ -12,6 +12,7 @@ use uuid::Uuid;
|
|||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
pub enum BarAction {
|
pub enum BarAction {
|
||||||
Reply(NoteId),
|
Reply(NoteId),
|
||||||
|
Quote(NoteId),
|
||||||
OpenThread(NoteId),
|
OpenThread(NoteId),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +131,12 @@ impl BarAction {
|
|||||||
BarAction::OpenThread(note_id) => {
|
BarAction::OpenThread(note_id) => {
|
||||||
open_thread(ndb, txn, router, note_cache, pool, threads, note_id.bytes())
|
open_thread(ndb, txn, router, note_cache, pool, threads, note_id.bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BarAction::Quote(note_id) => {
|
||||||
|
router.route_to(Route::quote(note_id));
|
||||||
|
router.navigating = true;
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ pub struct Draft {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Drafts {
|
pub struct Drafts {
|
||||||
replies: HashMap<[u8; 32], Draft>,
|
replies: HashMap<[u8; 32], Draft>,
|
||||||
|
quotes: HashMap<[u8; 32], Draft>,
|
||||||
compose: Draft,
|
compose: Draft,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,14 +20,19 @@ impl Drafts {
|
|||||||
pub fn reply_mut(&mut self, id: &[u8; 32]) -> &mut Draft {
|
pub fn reply_mut(&mut self, id: &[u8; 32]) -> &mut Draft {
|
||||||
self.replies.entry(*id).or_default()
|
self.replies.entry(*id).or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn quote_mut(&mut self, id: &[u8; 32]) -> &mut Draft {
|
||||||
|
self.quotes.entry(*id).or_default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
pub enum DraftSource<'a> {
|
pub enum DraftSource<'a> {
|
||||||
Compose,
|
Compose,
|
||||||
Reply(&'a [u8; 32]), // note id
|
Reply(&'a [u8; 32]), // note id
|
||||||
|
Quote(&'a [u8; 32]), // note id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
impl<'a> DraftSource<'a> {
|
impl<'a> DraftSource<'a> {
|
||||||
pub fn draft(&self, drafts: &'a mut Drafts) -> &'a mut Draft {
|
pub fn draft(&self, drafts: &'a mut Drafts) -> &'a mut Draft {
|
||||||
match self {
|
match self {
|
||||||
|
@ -25,6 +25,7 @@ mod nav;
|
|||||||
mod note;
|
mod note;
|
||||||
mod notecache;
|
mod notecache;
|
||||||
mod post;
|
mod post;
|
||||||
|
mod post_action_executor;
|
||||||
mod profile;
|
mod profile;
|
||||||
pub mod relay_pool_manager;
|
pub mod relay_pool_manager;
|
||||||
mod result;
|
mod result;
|
||||||
|
21
src/post.rs
21
src/post.rs
@ -89,4 +89,25 @@ impl NewPost {
|
|||||||
.build()
|
.build()
|
||||||
.expect("expected build to work")
|
.expect("expected build to work")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_quote(&self, seckey: &[u8; 32], quoting: &Note) -> Note {
|
||||||
|
let new_content = format!(
|
||||||
|
"{}\nnostr:{}",
|
||||||
|
self.content,
|
||||||
|
enostr::NoteId::new(*quoting.id()).to_bech().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
NoteBuilder::new()
|
||||||
|
.kind(1)
|
||||||
|
.content(&new_content)
|
||||||
|
.start_tag()
|
||||||
|
.tag_str("q")
|
||||||
|
.tag_str(&hex::encode(quoting.id()))
|
||||||
|
.start_tag()
|
||||||
|
.tag_str("p")
|
||||||
|
.tag_str(&hex::encode(quoting.pubkey()))
|
||||||
|
.sign(seckey)
|
||||||
|
.build()
|
||||||
|
.expect("expected build to work")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
28
src/post_action_executor.rs
Normal file
28
src/post_action_executor.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
use enostr::{FilledKeypair, RelayPool};
|
||||||
|
use nostrdb::Note;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
use crate::{draft::Draft, post::NewPost, ui::note::PostAction};
|
||||||
|
|
||||||
|
pub struct PostActionExecutor {}
|
||||||
|
|
||||||
|
impl PostActionExecutor {
|
||||||
|
pub fn execute<'a>(
|
||||||
|
poster: FilledKeypair<'_>,
|
||||||
|
action: &'a PostAction,
|
||||||
|
pool: &mut RelayPool,
|
||||||
|
draft: &mut Draft,
|
||||||
|
get_note: impl Fn(&'a NewPost, &[u8; 32]) -> Note<'a>,
|
||||||
|
) {
|
||||||
|
match action {
|
||||||
|
PostAction::Post(np) => {
|
||||||
|
let note = get_note(np, &poster.secret_key.to_secret_bytes());
|
||||||
|
|
||||||
|
let raw_msg = format!("[\"EVENT\",{}]", note.json().unwrap());
|
||||||
|
info!("sending {}", raw_msg);
|
||||||
|
pool.send(&enostr::ClientMessage::raw(raw_msg));
|
||||||
|
draft.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,10 @@ impl Route {
|
|||||||
Route::Timeline(TimelineRoute::Reply(replying_to))
|
Route::Timeline(TimelineRoute::Reply(replying_to))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn quote(quoting: NoteId) -> Self {
|
||||||
|
Route::Timeline(TimelineRoute::Quote(quoting))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn accounts() -> Self {
|
pub fn accounts() -> Self {
|
||||||
Route::Accounts(AccountsRoute::Accounts)
|
Route::Accounts(AccountsRoute::Accounts)
|
||||||
}
|
}
|
||||||
@ -110,6 +114,7 @@ impl fmt::Display for Route {
|
|||||||
TimelineRoute::Timeline(name) => write!(f, "{}", name),
|
TimelineRoute::Timeline(name) => write!(f, "{}", name),
|
||||||
TimelineRoute::Thread(_id) => write!(f, "Thread"),
|
TimelineRoute::Thread(_id) => write!(f, "Thread"),
|
||||||
TimelineRoute::Reply(_id) => write!(f, "Reply"),
|
TimelineRoute::Reply(_id) => write!(f, "Reply"),
|
||||||
|
TimelineRoute::Quote(_id) => write!(f, "Quote"),
|
||||||
},
|
},
|
||||||
|
|
||||||
Route::Relays => write!(f, "Relays"),
|
Route::Relays => write!(f, "Relays"),
|
||||||
|
@ -4,9 +4,13 @@ use crate::{
|
|||||||
draft::Drafts,
|
draft::Drafts,
|
||||||
imgcache::ImageCache,
|
imgcache::ImageCache,
|
||||||
notecache::NoteCache,
|
notecache::NoteCache,
|
||||||
|
post_action_executor::PostActionExecutor,
|
||||||
thread::Threads,
|
thread::Threads,
|
||||||
timeline::TimelineId,
|
timeline::TimelineId,
|
||||||
ui::{self, note::post::PostResponse},
|
ui::{
|
||||||
|
self,
|
||||||
|
note::{post::PostResponse, QuoteRepostView},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use enostr::{NoteId, RelayPool};
|
use enostr::{NoteId, RelayPool};
|
||||||
@ -17,6 +21,7 @@ pub enum TimelineRoute {
|
|||||||
Timeline(TimelineId),
|
Timeline(TimelineId),
|
||||||
Thread(NoteId),
|
Thread(NoteId),
|
||||||
Reply(NoteId),
|
Reply(NoteId),
|
||||||
|
Quote(NoteId),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum TimelineRouteResponse {
|
pub enum TimelineRouteResponse {
|
||||||
@ -48,8 +53,15 @@ pub fn render_timeline_route(
|
|||||||
match route {
|
match route {
|
||||||
TimelineRoute::Timeline(timeline_id) => {
|
TimelineRoute::Timeline(timeline_id) => {
|
||||||
if show_postbox {
|
if show_postbox {
|
||||||
if let Some(kp) = accounts.selected_or_first_nsec() {
|
let kp = accounts.selected_or_first_nsec()?;
|
||||||
ui::timeline::postbox_view(ndb, kp, pool, drafts, img_cache, ui);
|
let draft = drafts.compose_mut();
|
||||||
|
let response =
|
||||||
|
ui::timeline::postbox_view(ndb, kp, draft, img_cache, note_cache, ui);
|
||||||
|
|
||||||
|
if let Some(action) = response.action {
|
||||||
|
PostActionExecutor::execute(kp, &action, pool, draft, |np, seckey| {
|
||||||
|
np.to_note(seckey)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,18 +108,51 @@ pub fn render_timeline_route(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let id = egui::Id::new(("post", col, note.key().unwrap()));
|
let id = egui::Id::new(("post", col, note.key().unwrap()));
|
||||||
|
let poster = accounts.selected_or_first_nsec()?;
|
||||||
|
let draft = drafts.reply_mut(note.id());
|
||||||
|
|
||||||
if let Some(poster) = accounts.selected_or_first_nsec() {
|
|
||||||
let response = egui::ScrollArea::vertical().show(ui, |ui| {
|
let response = egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
ui::PostReplyView::new(ndb, poster, pool, drafts, note_cache, img_cache, ¬e)
|
ui::PostReplyView::new(ndb, poster, draft, note_cache, img_cache, ¬e)
|
||||||
.id_source(id)
|
.id_source(id)
|
||||||
.show(ui)
|
.show(ui)
|
||||||
});
|
});
|
||||||
|
|
||||||
Some(TimelineRouteResponse::post(response.inner))
|
if let Some(action) = &response.inner.action {
|
||||||
} else {
|
PostActionExecutor::execute(poster, action, pool, draft, |np, seckey| {
|
||||||
None
|
np.to_reply(seckey, ¬e)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(TimelineRouteResponse::post(response.inner))
|
||||||
|
}
|
||||||
|
|
||||||
|
TimelineRoute::Quote(id) => {
|
||||||
|
let txn = Transaction::new(ndb).expect("txn");
|
||||||
|
|
||||||
|
let note = if let Ok(note) = ndb.get_note_by_id(&txn, id.bytes()) {
|
||||||
|
note
|
||||||
|
} else {
|
||||||
|
ui.label("Quote of unknown note");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let id = egui::Id::new(("post", col, note.key().unwrap()));
|
||||||
|
|
||||||
|
let poster = accounts.selected_or_first_nsec()?;
|
||||||
|
let draft = drafts.quote_mut(note.id());
|
||||||
|
|
||||||
|
let response = egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
|
QuoteRepostView::new(ndb, poster, note_cache, img_cache, draft, ¬e)
|
||||||
|
.id_source(id)
|
||||||
|
.show(ui)
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(action) = &response.inner.action {
|
||||||
|
PostActionExecutor::execute(poster, action, pool, draft, |np, seckey| {
|
||||||
|
np.to_quote(seckey, ¬e)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Some(TimelineRouteResponse::post(response.inner))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ impl egui::Widget for NoteContents<'_> {
|
|||||||
|
|
||||||
/// Render an inline note preview with a border. These are used when
|
/// Render an inline note preview with a border. These are used when
|
||||||
/// notes are references within a note
|
/// notes are references within a note
|
||||||
fn render_note_preview(
|
pub fn render_note_preview(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
ndb: &Ndb,
|
ndb: &Ndb,
|
||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
pub mod contents;
|
pub mod contents;
|
||||||
pub mod options;
|
pub mod options;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
|
pub mod quote_repost;
|
||||||
pub mod reply;
|
pub mod reply;
|
||||||
|
|
||||||
pub use contents::NoteContents;
|
pub use contents::NoteContents;
|
||||||
pub use options::NoteOptions;
|
pub use options::NoteOptions;
|
||||||
pub use post::{PostAction, PostResponse, PostView};
|
pub use post::{PostAction, PostResponse, PostView};
|
||||||
|
pub use quote_repost::QuoteRepostView;
|
||||||
pub use reply::PostReplyView;
|
pub use reply::PostReplyView;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -555,9 +557,12 @@ fn render_note_actionbar(
|
|||||||
) -> egui::InnerResponse<Option<BarAction>> {
|
) -> egui::InnerResponse<Option<BarAction>> {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let reply_resp = reply_button(ui, note_key);
|
let reply_resp = reply_button(ui, note_key);
|
||||||
|
let quote_resp = quote_repost_button(ui, note_key);
|
||||||
|
|
||||||
if reply_resp.clicked() {
|
if reply_resp.clicked() {
|
||||||
Some(BarAction::Reply(NoteId::new(*note_id)))
|
Some(BarAction::Reply(NoteId::new(*note_id)))
|
||||||
|
} else if quote_resp.clicked() {
|
||||||
|
Some(BarAction::Quote(NoteId::new(*note_id)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -614,3 +619,15 @@ fn repost_icon() -> egui::Image<'static> {
|
|||||||
let img_data = egui::include_image!("../../../assets/icons/repost_icon_4x.png");
|
let img_data = egui::include_image!("../../../assets/icons/repost_icon_4x.png");
|
||||||
egui::Image::new(img_data)
|
egui::Image::new(img_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn quote_repost_button(ui: &mut egui::Ui, note_key: NoteKey) -> egui::Response {
|
||||||
|
let (rect, size, resp) =
|
||||||
|
ui::anim::hover_expand_small(ui, ui.id().with(("repost_anim", note_key)));
|
||||||
|
|
||||||
|
let expand_size = 5.0;
|
||||||
|
let rect = rect.translate(egui::vec2(-(expand_size / 2.0), 0.0));
|
||||||
|
|
||||||
|
let put_resp = ui.put(rect, repost_icon().max_width(size));
|
||||||
|
|
||||||
|
resp.union(put_resp)
|
||||||
|
}
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
use crate::draft::Draft;
|
use crate::draft::{Draft, DraftSource};
|
||||||
use crate::imgcache::ImageCache;
|
use crate::imgcache::ImageCache;
|
||||||
|
use crate::notecache::NoteCache;
|
||||||
use crate::post::NewPost;
|
use crate::post::NewPost;
|
||||||
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 egui::{Frame, Layout};
|
||||||
use enostr::{FilledKeypair, FullKeypair};
|
use enostr::{FilledKeypair, FullKeypair};
|
||||||
use nostrdb::{Config, Ndb, Transaction};
|
use nostrdb::{Config, Ndb, Transaction};
|
||||||
|
|
||||||
|
use super::contents::render_note_preview;
|
||||||
|
|
||||||
pub struct PostView<'a> {
|
pub struct PostView<'a> {
|
||||||
ndb: &'a Ndb,
|
ndb: &'a Ndb,
|
||||||
draft: &'a mut Draft,
|
draft: &'a mut Draft,
|
||||||
|
draft_source: DraftSource<'a>,
|
||||||
img_cache: &'a mut ImageCache,
|
img_cache: &'a mut ImageCache,
|
||||||
|
note_cache: &'a mut NoteCache,
|
||||||
poster: FilledKeypair<'a>,
|
poster: FilledKeypair<'a>,
|
||||||
id_source: Option<egui::Id>,
|
id_source: Option<egui::Id>,
|
||||||
}
|
}
|
||||||
@ -28,7 +34,9 @@ impl<'a> PostView<'a> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
ndb: &'a Ndb,
|
ndb: &'a Ndb,
|
||||||
draft: &'a mut Draft,
|
draft: &'a mut Draft,
|
||||||
|
draft_source: DraftSource<'a>,
|
||||||
img_cache: &'a mut ImageCache,
|
img_cache: &'a mut ImageCache,
|
||||||
|
note_cache: &'a mut NoteCache,
|
||||||
poster: FilledKeypair<'a>,
|
poster: FilledKeypair<'a>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let id_source: Option<egui::Id> = None;
|
let id_source: Option<egui::Id> = None;
|
||||||
@ -36,8 +44,10 @@ impl<'a> PostView<'a> {
|
|||||||
ndb,
|
ndb,
|
||||||
draft,
|
draft,
|
||||||
img_cache,
|
img_cache,
|
||||||
|
note_cache,
|
||||||
poster,
|
poster,
|
||||||
id_source,
|
id_source,
|
||||||
|
draft_source,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +139,28 @@ impl<'a> PostView<'a> {
|
|||||||
let edit_response = ui.horizontal(|ui| self.editbox(txn, ui)).inner;
|
let edit_response = ui.horizontal(|ui| self.editbox(txn, ui)).inner;
|
||||||
|
|
||||||
let action = ui
|
let action = ui
|
||||||
.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
|
.horizontal(|ui| {
|
||||||
|
if let DraftSource::Quote(id) = self.draft_source {
|
||||||
|
let avail_size = ui.available_size_before_wrap();
|
||||||
|
ui.with_layout(Layout::left_to_right(egui::Align::TOP), |ui| {
|
||||||
|
Frame::none().show(ui, |ui| {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.set_max_width(avail_size.x * 0.8);
|
||||||
|
render_note_preview(
|
||||||
|
ui,
|
||||||
|
self.ndb,
|
||||||
|
self.note_cache,
|
||||||
|
self.img_cache,
|
||||||
|
txn,
|
||||||
|
id,
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.with_layout(egui::Layout::right_to_left(egui::Align::BOTTOM), |ui| {
|
||||||
if ui
|
if ui
|
||||||
.add_sized([91.0, 32.0], egui::Button::new("Post now"))
|
.add_sized([91.0, 32.0], egui::Button::new("Post now"))
|
||||||
.clicked()
|
.clicked()
|
||||||
@ -142,6 +173,8 @@ impl<'a> PostView<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.inner
|
||||||
|
})
|
||||||
.inner;
|
.inner;
|
||||||
|
|
||||||
PostResponse {
|
PostResponse {
|
||||||
@ -161,6 +194,7 @@ mod preview {
|
|||||||
pub struct PostPreview {
|
pub struct PostPreview {
|
||||||
ndb: Ndb,
|
ndb: Ndb,
|
||||||
img_cache: ImageCache,
|
img_cache: ImageCache,
|
||||||
|
note_cache: NoteCache,
|
||||||
draft: Draft,
|
draft: Draft,
|
||||||
poster: FullKeypair,
|
poster: FullKeypair,
|
||||||
}
|
}
|
||||||
@ -172,6 +206,7 @@ mod preview {
|
|||||||
PostPreview {
|
PostPreview {
|
||||||
ndb,
|
ndb,
|
||||||
img_cache: ImageCache::new(".".into()),
|
img_cache: ImageCache::new(".".into()),
|
||||||
|
note_cache: NoteCache::default(),
|
||||||
draft: Draft::new(),
|
draft: Draft::new(),
|
||||||
poster: FullKeypair::generate(),
|
poster: FullKeypair::generate(),
|
||||||
}
|
}
|
||||||
@ -184,7 +219,9 @@ mod preview {
|
|||||||
PostView::new(
|
PostView::new(
|
||||||
&self.ndb,
|
&self.ndb,
|
||||||
&mut self.draft,
|
&mut self.draft,
|
||||||
|
DraftSource::Compose,
|
||||||
&mut self.img_cache,
|
&mut self.img_cache,
|
||||||
|
&mut self.note_cache,
|
||||||
self.poster.to_filled(),
|
self.poster.to_filled(),
|
||||||
)
|
)
|
||||||
.ui(&txn, ui);
|
.ui(&txn, ui);
|
||||||
|
64
src/ui/note/quote_repost.rs
Normal file
64
src/ui/note/quote_repost.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use enostr::FilledKeypair;
|
||||||
|
use nostrdb::Ndb;
|
||||||
|
|
||||||
|
use crate::{draft::Draft, imgcache::ImageCache, notecache::NoteCache, ui};
|
||||||
|
|
||||||
|
use super::PostResponse;
|
||||||
|
|
||||||
|
pub struct QuoteRepostView<'a> {
|
||||||
|
ndb: &'a Ndb,
|
||||||
|
poster: FilledKeypair<'a>,
|
||||||
|
note_cache: &'a mut NoteCache,
|
||||||
|
img_cache: &'a mut ImageCache,
|
||||||
|
draft: &'a mut Draft,
|
||||||
|
quoting_note: &'a nostrdb::Note<'a>,
|
||||||
|
id_source: Option<egui::Id>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> QuoteRepostView<'a> {
|
||||||
|
pub fn new(
|
||||||
|
ndb: &'a Ndb,
|
||||||
|
poster: FilledKeypair<'a>,
|
||||||
|
note_cache: &'a mut NoteCache,
|
||||||
|
img_cache: &'a mut ImageCache,
|
||||||
|
draft: &'a mut Draft,
|
||||||
|
quoting_note: &'a nostrdb::Note<'a>,
|
||||||
|
) -> Self {
|
||||||
|
let id_source: Option<egui::Id> = None;
|
||||||
|
QuoteRepostView {
|
||||||
|
ndb,
|
||||||
|
poster,
|
||||||
|
note_cache,
|
||||||
|
img_cache,
|
||||||
|
draft,
|
||||||
|
quoting_note,
|
||||||
|
id_source,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show(&mut self, ui: &mut egui::Ui) -> PostResponse {
|
||||||
|
let id = self.id();
|
||||||
|
let quoting_note_id = self.quoting_note.id();
|
||||||
|
|
||||||
|
ui::PostView::new(
|
||||||
|
self.ndb,
|
||||||
|
self.draft,
|
||||||
|
crate::draft::DraftSource::Quote(quoting_note_id),
|
||||||
|
self.img_cache,
|
||||||
|
self.note_cache,
|
||||||
|
self.poster,
|
||||||
|
)
|
||||||
|
.id_source(id)
|
||||||
|
.ui(self.quoting_note.txn().unwrap(), ui)
|
||||||
|
}
|
||||||
|
|
||||||
|
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("quote-repost-view"))
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,17 @@
|
|||||||
use crate::draft::Drafts;
|
use crate::draft::Draft;
|
||||||
use crate::imgcache::ImageCache;
|
use crate::imgcache::ImageCache;
|
||||||
use crate::notecache::NoteCache;
|
use crate::notecache::NoteCache;
|
||||||
use crate::ui;
|
use crate::ui;
|
||||||
use crate::ui::note::{PostAction, PostResponse};
|
use crate::ui::note::PostResponse;
|
||||||
use enostr::{FilledKeypair, RelayPool};
|
use enostr::FilledKeypair;
|
||||||
use nostrdb::Ndb;
|
use nostrdb::Ndb;
|
||||||
use tracing::info;
|
|
||||||
|
|
||||||
pub struct PostReplyView<'a> {
|
pub struct PostReplyView<'a> {
|
||||||
ndb: &'a Ndb,
|
ndb: &'a Ndb,
|
||||||
poster: FilledKeypair<'a>,
|
poster: FilledKeypair<'a>,
|
||||||
pool: &'a mut RelayPool,
|
|
||||||
note_cache: &'a mut NoteCache,
|
note_cache: &'a mut NoteCache,
|
||||||
img_cache: &'a mut ImageCache,
|
img_cache: &'a mut ImageCache,
|
||||||
drafts: &'a mut Drafts,
|
draft: &'a mut Draft,
|
||||||
note: &'a nostrdb::Note<'a>,
|
note: &'a nostrdb::Note<'a>,
|
||||||
id_source: Option<egui::Id>,
|
id_source: Option<egui::Id>,
|
||||||
}
|
}
|
||||||
@ -22,8 +20,7 @@ impl<'a> PostReplyView<'a> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
ndb: &'a Ndb,
|
ndb: &'a Ndb,
|
||||||
poster: FilledKeypair<'a>,
|
poster: FilledKeypair<'a>,
|
||||||
pool: &'a mut RelayPool,
|
draft: &'a mut Draft,
|
||||||
drafts: &'a mut Drafts,
|
|
||||||
note_cache: &'a mut NoteCache,
|
note_cache: &'a mut NoteCache,
|
||||||
img_cache: &'a mut ImageCache,
|
img_cache: &'a mut ImageCache,
|
||||||
note: &'a nostrdb::Note<'a>,
|
note: &'a nostrdb::Note<'a>,
|
||||||
@ -32,8 +29,7 @@ impl<'a> PostReplyView<'a> {
|
|||||||
PostReplyView {
|
PostReplyView {
|
||||||
ndb,
|
ndb,
|
||||||
poster,
|
poster,
|
||||||
pool,
|
draft,
|
||||||
drafts,
|
|
||||||
note,
|
note,
|
||||||
note_cache,
|
note_cache,
|
||||||
img_cache,
|
img_cache,
|
||||||
@ -79,27 +75,18 @@ impl<'a> PostReplyView<'a> {
|
|||||||
let rect_before_post = ui.min_rect();
|
let rect_before_post = ui.min_rect();
|
||||||
|
|
||||||
let post_response = {
|
let post_response = {
|
||||||
let draft = self.drafts.reply_mut(replying_to);
|
ui::PostView::new(
|
||||||
ui::PostView::new(self.ndb, draft, self.img_cache, self.poster)
|
self.ndb,
|
||||||
|
self.draft,
|
||||||
|
crate::draft::DraftSource::Reply(replying_to),
|
||||||
|
self.img_cache,
|
||||||
|
self.note_cache,
|
||||||
|
self.poster,
|
||||||
|
)
|
||||||
.id_source(id)
|
.id_source(id)
|
||||||
.ui(self.note.txn().unwrap(), ui)
|
.ui(self.note.txn().unwrap(), ui)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(action) = &post_response.action {
|
|
||||||
match action {
|
|
||||||
PostAction::Post(np) => {
|
|
||||||
let seckey = self.poster.secret_key.to_secret_bytes();
|
|
||||||
|
|
||||||
let note = np.to_reply(&seckey, self.note);
|
|
||||||
|
|
||||||
let raw_msg = format!("[\"EVENT\",{}]", note.json().unwrap());
|
|
||||||
info!("sending {}", raw_msg);
|
|
||||||
self.pool.send(&enostr::ClientMessage::raw(raw_msg));
|
|
||||||
self.drafts.reply_mut(replying_to).clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// reply line
|
// reply line
|
||||||
//
|
//
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
|
use crate::draft::Draft;
|
||||||
use crate::{
|
use crate::{
|
||||||
actionbar::BarAction, column::Columns, draft::Drafts, imgcache::ImageCache,
|
actionbar::BarAction, column::Columns, imgcache::ImageCache, notecache::NoteCache,
|
||||||
notecache::NoteCache, timeline::TimelineId, ui, ui::note::PostAction,
|
timeline::TimelineId, ui,
|
||||||
};
|
};
|
||||||
use egui::containers::scroll_area::ScrollBarVisibility;
|
use egui::containers::scroll_area::ScrollBarVisibility;
|
||||||
use egui::{Direction, Layout};
|
use egui::{Direction, Layout};
|
||||||
use egui_tabs::TabColor;
|
use egui_tabs::TabColor;
|
||||||
use enostr::{FilledKeypair, RelayPool};
|
use enostr::FilledKeypair;
|
||||||
use nostrdb::{Ndb, Transaction};
|
use nostrdb::{Ndb, Transaction};
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, warn};
|
||||||
|
|
||||||
|
use super::note::PostResponse;
|
||||||
|
|
||||||
pub struct TimelineView<'a> {
|
pub struct TimelineView<'a> {
|
||||||
timeline_id: TimelineId,
|
timeline_id: TimelineId,
|
||||||
@ -170,27 +173,22 @@ fn timeline_ui(
|
|||||||
pub fn postbox_view<'a>(
|
pub fn postbox_view<'a>(
|
||||||
ndb: &'a Ndb,
|
ndb: &'a Ndb,
|
||||||
key: FilledKeypair<'a>,
|
key: FilledKeypair<'a>,
|
||||||
pool: &'a mut RelayPool,
|
draft: &'a mut Draft,
|
||||||
drafts: &'a mut Drafts,
|
|
||||||
img_cache: &'a mut ImageCache,
|
img_cache: &'a mut ImageCache,
|
||||||
|
note_cache: &'a mut NoteCache,
|
||||||
ui: &'a mut egui::Ui,
|
ui: &'a mut egui::Ui,
|
||||||
) {
|
) -> PostResponse {
|
||||||
// show a postbox in the first timeline
|
// show a postbox in the first timeline
|
||||||
let txn = Transaction::new(ndb).expect("txn");
|
let txn = Transaction::new(ndb).expect("txn");
|
||||||
let response = ui::PostView::new(ndb, drafts.compose_mut(), img_cache, key).ui(&txn, ui);
|
ui::PostView::new(
|
||||||
|
ndb,
|
||||||
if let Some(action) = response.action {
|
draft,
|
||||||
match action {
|
crate::draft::DraftSource::Compose,
|
||||||
PostAction::Post(np) => {
|
img_cache,
|
||||||
let seckey = key.secret_key.to_secret_bytes();
|
note_cache,
|
||||||
let note = np.to_note(&seckey);
|
key,
|
||||||
let raw_msg = format!("[\"EVENT\",{}]", note.json().unwrap());
|
)
|
||||||
info!("sending {}", raw_msg);
|
.ui(&txn, ui)
|
||||||
pool.send(&enostr::ClientMessage::raw(raw_msg));
|
|
||||||
drafts.compose_mut().clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tabs_ui(ui: &mut egui::Ui) -> i32 {
|
fn tabs_ui(ui: &mut egui::Ui) -> i32 {
|
||||||
|
Loading…
Reference in New Issue
Block a user