refactor: unify note, post and nav actions

There was a bunch of redundant responses. Let's unify them under
the RenderNavAction enum. We unify all action processing under this
type.

This also centralizes all of our side effects into a single function
instead of scattering them everywhere
This commit is contained in:
William Casarin
2024-11-19 11:07:42 -08:00
parent d97c957e67
commit 7f234935cc
15 changed files with 372 additions and 404 deletions

View File

@@ -1,7 +1,9 @@
use crate::{ use crate::{
column::Columns,
note::NoteRef, note::NoteRef,
notecache::NoteCache, notecache::NoteCache,
notes_holder::{NotesHolder, NotesHolderStorage}, notes_holder::{NotesHolder, NotesHolderStorage},
profile::Profile,
route::{Route, Router}, route::{Route, Router},
thread::Thread, thread::Thread,
}; };
@@ -9,16 +11,11 @@ use enostr::{NoteId, Pubkey, RelayPool};
use nostrdb::{Ndb, Transaction}; use nostrdb::{Ndb, Transaction};
#[derive(Debug, Eq, PartialEq, Copy, Clone)] #[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum BarAction { pub enum NoteAction {
Reply(NoteId), Reply(NoteId),
Quote(NoteId), Quote(NoteId),
OpenThread(NoteId), OpenThread(NoteId),
} OpenProfile(Pubkey),
#[derive(Default)]
pub struct NoteActionResponse {
pub bar_action: Option<BarAction>,
pub open_profile: Option<Pubkey>,
} }
pub struct NewNotes { pub struct NewNotes {
@@ -50,47 +47,55 @@ fn open_thread(
Thread::open(ndb, note_cache, txn, pool, threads, root_id) Thread::open(ndb, note_cache, txn, pool, threads, root_id)
} }
impl BarAction { impl NoteAction {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn execute( pub fn execute(
self, self,
ndb: &Ndb, ndb: &Ndb,
router: &mut Router<Route>, router: &mut Router<Route>,
threads: &mut NotesHolderStorage<Thread>, threads: &mut NotesHolderStorage<Thread>,
profiles: &mut NotesHolderStorage<Profile>,
note_cache: &mut NoteCache, note_cache: &mut NoteCache,
pool: &mut RelayPool, pool: &mut RelayPool,
txn: &Transaction, txn: &Transaction,
) -> Option<NotesHolderResult> { ) -> Option<NotesHolderResult> {
match self { match self {
BarAction::Reply(note_id) => { NoteAction::Reply(note_id) => {
router.route_to(Route::reply(note_id)); router.route_to(Route::reply(note_id));
router.navigating = true;
None None
} }
BarAction::OpenThread(note_id) => { NoteAction::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) => { NoteAction::OpenProfile(pubkey) => {
router.route_to(Route::profile(pubkey));
Profile::open(ndb, note_cache, txn, pool, profiles, pubkey.bytes())
}
NoteAction::Quote(note_id) => {
router.route_to(Route::quote(note_id)); router.route_to(Route::quote(note_id));
router.navigating = true;
None None
} }
} }
} }
/// Execute the BarAction and process the BarResult /// Execute the NoteAction and process the NotesHolderResult
#[allow(clippy::too_many_arguments)]
pub fn execute_and_process_result( pub fn execute_and_process_result(
self, self,
ndb: &Ndb, ndb: &Ndb,
router: &mut Router<Route>, columns: &mut Columns,
col: usize,
threads: &mut NotesHolderStorage<Thread>, threads: &mut NotesHolderStorage<Thread>,
profiles: &mut NotesHolderStorage<Profile>,
note_cache: &mut NoteCache, note_cache: &mut NoteCache,
pool: &mut RelayPool, pool: &mut RelayPool,
txn: &Transaction, txn: &Transaction,
) { ) {
if let Some(br) = self.execute(ndb, router, threads, note_cache, pool, txn) { let router = columns.column_mut(col).router_mut();
if let Some(br) = self.execute(ndb, router, threads, profiles, note_cache, pool, txn) {
br.process(ndb, note_cache, txn, threads); br.process(ndb, note_cache, txn, threads);
} }
} }

View File

@@ -745,9 +745,7 @@ fn render_damus_mobile(ctx: &egui::Context, app: &mut Damus) {
main_panel(&ctx.style(), ui::is_narrow(ctx)).show(ctx, |ui| { main_panel(&ctx.style(), ui::is_narrow(ctx)).show(ctx, |ui| {
if !app.columns.columns().is_empty() { if !app.columns.columns().is_empty() {
if let Some(r) = nav::render_nav(0, app, ui) { nav::render_nav(0, app, ui).process_render_nav_response(app);
r.process_nav_response(&app.path, &mut app.columns)
}
} }
}); });
} }
@@ -824,13 +822,11 @@ fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus) {
); );
}); });
let mut nav_resp: Option<nav::RenderNavResponse> = None; let mut responses = Vec::with_capacity(app.columns.num_columns());
for col_index in 0..app.columns.num_columns() { for col_index in 0..app.columns.num_columns() {
strip.cell(|ui| { strip.cell(|ui| {
let rect = ui.available_rect_before_wrap(); let rect = ui.available_rect_before_wrap();
if let Some(r) = nav::render_nav(col_index, app, ui) { responses.push(nav::render_nav(col_index, app, ui));
nav_resp = Some(r);
}
// vertical line // vertical line
ui.painter().vline( ui.painter().vline(
@@ -843,8 +839,8 @@ fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus) {
//strip.cell(|ui| timeline::timeline_view(ui, app, timeline_ind)); //strip.cell(|ui| timeline::timeline_view(ui, app, timeline_ind));
} }
if let Some(r) = nav_resp { for response in responses {
r.process_nav_response(&app.path, &mut app.columns); response.process_render_nav_response(app);
} }
}); });
} }

View File

@@ -261,9 +261,6 @@ impl SerializableColumns {
Route::Timeline(TimelineRoute::Thread(_thread)) => { Route::Timeline(TimelineRoute::Thread(_thread)) => {
// TODO: open thread before pushing route // TODO: open thread before pushing route
} }
Route::Profile(_profile) => {
// TODO: open profile before pushing route
}
_ => routes.push(*route), _ => routes.push(*route),
} }
} }

View File

@@ -1,3 +1,4 @@
use crate::ui::note::PostType;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Default)] #[derive(Default)]
@@ -17,6 +18,14 @@ impl Drafts {
&mut self.compose &mut self.compose
} }
pub fn get_from_post_type(&mut self, post_type: &PostType) -> &mut Draft {
match post_type {
PostType::New => self.compose_mut(),
PostType::Quote(note_id) => self.quote_mut(note_id.bytes()),
PostType::Reply(note_id) => self.reply_mut(note_id.bytes()),
}
}
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()
} }
@@ -26,23 +35,6 @@ impl Drafts {
} }
} }
pub enum DraftSource<'a> {
Compose,
Reply(&'a [u8; 32]), // note id
Quote(&'a [u8; 32]), // note id
}
/*
impl<'a> DraftSource<'a> {
pub fn draft(&self, drafts: &'a mut Drafts) -> &'a mut Draft {
match self {
DraftSource::Compose => drafts.compose_mut(),
DraftSource::Reply(id) => drafts.reply_mut(id),
}
}
}
*/
impl Draft { impl Draft {
pub fn new() -> Self { pub fn new() -> Self {
Draft::default() Draft::default()

View File

@@ -1,23 +1,23 @@
use crate::{ use crate::{
accounts::render_accounts_route, accounts::render_accounts_route,
actionbar::NoteAction,
app_style::{get_font_size, NotedeckTextStyle}, app_style::{get_font_size, NotedeckTextStyle},
column::Columns,
fonts::NamedFontFamily, fonts::NamedFontFamily,
notes_holder::NotesHolder, notes_holder::NotesHolder,
profile::Profile, profile::Profile,
relay_pool_manager::RelayPoolManager, relay_pool_manager::RelayPoolManager,
route::Route, route::Route,
storage::{self, DataPath}, storage::{self},
thread::Thread, thread::Thread,
timeline::{ timeline::{
route::{render_profile_route, render_timeline_route, AfterRouteExecution, TimelineRoute}, route::{render_timeline_route, TimelineRoute},
Timeline, Timeline,
}, },
ui::{ ui::{
self, self,
add_column::render_add_column_routes, add_column::render_add_column_routes,
anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE}, anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE},
note::PostAction, note::{PostAction, PostType},
support::SupportView, support::SupportView,
RelayView, View, RelayView, View,
}, },
@@ -25,32 +25,135 @@ use crate::{
}; };
use egui::{pos2, Color32, InnerResponse, Stroke}; use egui::{pos2, Color32, InnerResponse, Stroke};
use egui_nav::{Nav, NavAction, TitleBarResponse}; use egui_nav::{Nav, NavAction, NavResponse, TitleBarResponse};
use nostrdb::{Ndb, Transaction}; use nostrdb::{Ndb, Transaction};
use tracing::{error, info}; use tracing::{error, info};
pub enum RenderNavResponse { pub enum RenderNavAction {
ColumnChanged, PostAction(PostAction),
RemoveColumn(usize), NoteAction(NoteAction),
}
impl From<PostAction> for RenderNavAction {
fn from(post_action: PostAction) -> Self {
Self::PostAction(post_action)
}
}
impl From<NoteAction> for RenderNavAction {
fn from(note_action: NoteAction) -> RenderNavAction {
Self::NoteAction(note_action)
}
}
pub struct RenderNavResponse {
column: usize,
response: NavResponse<Option<RenderNavAction>, TitleResponse>,
} }
impl RenderNavResponse { impl RenderNavResponse {
pub fn process_nav_response(&self, path: &DataPath, columns: &mut Columns) { #[allow(private_interfaces)]
match self { pub fn new(
RenderNavResponse::ColumnChanged => { column: usize,
storage::save_columns(path, columns.as_serializable_columns()); response: NavResponse<Option<RenderNavAction>, TitleResponse>,
) -> Self {
RenderNavResponse { column, response }
}
pub fn process_render_nav_response(&self, app: &mut Damus) {
let mut col_changed: bool = false;
let col = self.column;
if let Some(action) = &self.response.inner {
// start returning when we're finished posting
match action {
RenderNavAction::PostAction(post_action) => {
let txn = Transaction::new(&app.ndb).expect("txn");
let _ = post_action.execute(&app.ndb, &txn, &mut app.pool, &mut app.drafts);
app.columns_mut().column_mut(col).router_mut().go_back();
}
RenderNavAction::NoteAction(note_action) => {
let txn = Transaction::new(&app.ndb).expect("txn");
note_action.execute_and_process_result(
&app.ndb,
&mut app.columns,
col,
&mut app.threads,
&mut app.profiles,
&mut app.note_cache,
&mut app.pool,
&txn,
);
}
}
}
if let Some(NavAction::Returned) = self.response.action {
let r = app.columns_mut().column_mut(col).router_mut().pop();
let txn = Transaction::new(&app.ndb).expect("txn");
if let Some(Route::Timeline(TimelineRoute::Thread(id))) = r {
let root_id = {
crate::note::root_note_id_from_selected_id(
&app.ndb,
&mut app.note_cache,
&txn,
id.bytes(),
)
};
Thread::unsubscribe_locally(
&txn,
&app.ndb,
&mut app.note_cache,
&mut app.threads,
&mut app.pool,
root_id,
);
} }
RenderNavResponse::RemoveColumn(col) => { if let Some(Route::Timeline(TimelineRoute::Profile(pubkey))) = r {
columns.delete_column(*col); Profile::unsubscribe_locally(
storage::save_columns(path, columns.as_serializable_columns()); &txn,
&app.ndb,
&mut app.note_cache,
&mut app.profiles,
&mut app.pool,
pubkey.bytes(),
);
} }
col_changed = true;
} else if let Some(NavAction::Navigated) = self.response.action {
let cur_router = app.columns_mut().column_mut(col).router_mut();
cur_router.navigating = false;
if cur_router.is_replacing() {
cur_router.remove_previous_routes();
}
col_changed = true;
}
if let Some(title_response) = &self.response.title_response {
match title_response {
TitleResponse::RemoveColumn => {
let tl = app.columns().find_timeline_for_column_index(col);
if let Some(timeline) = tl {
unsubscribe_timeline(app.ndb(), timeline);
}
app.columns_mut().delete_column(col);
col_changed = true;
}
}
}
if col_changed {
storage::save_columns(&app.path, app.columns().as_serializable_columns());
} }
} }
} }
pub fn render_nav(col: usize, app: &mut Damus, ui: &mut egui::Ui) -> Option<RenderNavResponse> { #[must_use = "RenderNavResponse must be handled by calling .process_render_nav_response(..)"]
let mut resp: Option<RenderNavResponse> = None; pub fn render_nav(col: usize, app: &mut Damus, ui: &mut egui::Ui) -> RenderNavResponse {
let col_id = app.columns.get_column_id_at_index(col); let col_id = app.columns.get_column_id_at_index(col);
// TODO(jb55): clean up this router_mut mess by using Router<R> in egui-nav directly // TODO(jb55): clean up this router_mut mess by using Router<R> in egui-nav directly
let routes = app let routes = app
@@ -61,186 +164,78 @@ pub fn render_nav(col: usize, app: &mut Damus, ui: &mut egui::Ui) -> Option<Rend
.iter() .iter()
.map(|r| r.get_titled_route(&app.columns, &app.ndb)) .map(|r| r.get_titled_route(&app.columns, &app.ndb))
.collect(); .collect();
let nav_response = Nav::new(routes) let nav_response = Nav::new(routes)
.navigating(app.columns_mut().column_mut(col).router_mut().navigating) .navigating(app.columns_mut().column_mut(col).router_mut().navigating)
.returning(app.columns_mut().column_mut(col).router_mut().returning) .returning(app.columns_mut().column_mut(col).router_mut().returning)
.id_source(egui::Id::new(col_id)) .id_source(egui::Id::new(col_id))
.title(48.0, title_bar) .title(48.0, title_bar)
.show_mut(ui, |ui, nav| { .show_mut(ui, |ui, nav| match &nav.top().route {
let column = app.columns.column_mut(col); Route::Timeline(tlr) => render_timeline_route(
match &nav.top().route { &app.ndb,
Route::Timeline(tlr) => render_timeline_route( &mut app.columns,
&mut app.drafts,
&mut app.img_cache,
&mut app.unknown_ids,
&mut app.note_cache,
&mut app.threads,
&mut app.profiles,
&mut app.accounts,
*tlr,
col,
app.textmode,
ui,
),
Route::Accounts(amr) => {
let action = render_accounts_route(
ui,
&app.ndb, &app.ndb,
col,
&mut app.columns, &mut app.columns,
&mut app.pool,
&mut app.drafts,
&mut app.img_cache, &mut app.img_cache,
&mut app.unknown_ids,
&mut app.note_cache,
&mut app.threads,
&mut app.accounts, &mut app.accounts,
*tlr, &mut app.view_state.login,
col, *amr,
app.textmode, );
ui, let txn = Transaction::new(&app.ndb).expect("txn");
), action.process_action(&mut app.unknown_ids, &app.ndb, &txn);
Route::Accounts(amr) => { None
let action = render_accounts_route( }
ui, Route::Relays => {
&app.ndb, let manager = RelayPoolManager::new(app.pool_mut());
col, RelayView::new(manager).ui(ui);
&mut app.columns, None
&mut app.img_cache, }
&mut app.accounts, Route::ComposeNote => {
&mut app.view_state.login, let kp = app.accounts.selected_or_first_nsec()?;
*amr, let draft = app.drafts.compose_mut();
);
let txn = Transaction::new(&app.ndb).expect("txn");
action.process_action(&mut app.unknown_ids, &app.ndb, &txn);
None
}
Route::Relays => {
let manager = RelayPoolManager::new(app.pool_mut());
RelayView::new(manager).ui(ui);
None
}
Route::ComposeNote => {
let kp = app.accounts.selected_or_first_nsec()?;
let draft = app.drafts.compose_mut();
let txn = nostrdb::Transaction::new(&app.ndb).expect("txn"); let txn = nostrdb::Transaction::new(&app.ndb).expect("txn");
let post_response = ui::PostView::new( let post_response = ui::PostView::new(
&app.ndb,
draft,
crate::draft::DraftSource::Compose,
&mut app.img_cache,
&mut app.note_cache,
kp,
)
.ui(&txn, ui);
if let Some(action) = post_response.action {
PostAction::execute(kp, &action, &mut app.pool, draft, |np, seckey| {
np.to_note(seckey)
});
column.router_mut().go_back();
}
None
}
Route::AddColumn(route) => {
render_add_column_routes(ui, app, col, route);
None
}
Route::Profile(pubkey) => render_profile_route(
pubkey,
&app.ndb, &app.ndb,
&mut app.columns, draft,
&mut app.profiles, PostType::New,
&mut app.pool,
&mut app.img_cache, &mut app.img_cache,
&mut app.note_cache, &mut app.note_cache,
&mut app.threads, kp,
col, )
ui, .ui(&txn, ui);
),
Route::Support => { post_response.action.map(Into::into)
SupportView::new(&mut app.support).show(ui); }
None Route::AddColumn(route) => {
} render_add_column_routes(ui, app, col, route);
None
}
Route::Support => {
SupportView::new(&mut app.support).show(ui);
None
} }
}); });
if let Some(after_route_execution) = nav_response.inner { RenderNavResponse::new(col, nav_response)
// start returning when we're finished posting
match after_route_execution {
AfterRouteExecution::Post(resp) => {
if let Some(action) = resp.action {
match action {
PostAction::Post(_) => {
app.columns_mut().column_mut(col).router_mut().returning = true;
}
}
}
}
AfterRouteExecution::OpenProfile(pubkey) => {
app.columns
.column_mut(col)
.router_mut()
.route_to(Route::Profile(pubkey));
let txn = Transaction::new(&app.ndb).expect("txn");
if let Some(res) = Profile::open(
&app.ndb,
&mut app.note_cache,
&txn,
&mut app.pool,
&mut app.profiles,
pubkey.bytes(),
) {
res.process(&app.ndb, &mut app.note_cache, &txn, &mut app.profiles);
}
}
}
}
if let Some(NavAction::Returned) = nav_response.action {
let r = app.columns_mut().column_mut(col).router_mut().pop();
let txn = Transaction::new(&app.ndb).expect("txn");
if let Some(Route::Timeline(TimelineRoute::Thread(id))) = r {
let root_id = {
crate::note::root_note_id_from_selected_id(
&app.ndb,
&mut app.note_cache,
&txn,
id.bytes(),
)
};
Thread::unsubscribe_locally(
&txn,
&app.ndb,
&mut app.note_cache,
&mut app.threads,
&mut app.pool,
root_id,
);
}
if let Some(Route::Profile(pubkey)) = r {
Profile::unsubscribe_locally(
&txn,
&app.ndb,
&mut app.note_cache,
&mut app.profiles,
&mut app.pool,
pubkey.bytes(),
);
}
resp = Some(RenderNavResponse::ColumnChanged)
} else if let Some(NavAction::Navigated) = nav_response.action {
let cur_router = app.columns_mut().column_mut(col).router_mut();
cur_router.navigating = false;
if cur_router.is_replacing() {
cur_router.remove_previous_routes();
}
resp = Some(RenderNavResponse::ColumnChanged)
}
if let Some(title_response) = nav_response.title_response {
match title_response {
TitleResponse::RemoveColumn => {
let tl = app.columns().find_timeline_for_column_index(col);
if let Some(timeline) = tl {
unsubscribe_timeline(app.ndb(), timeline);
}
resp = Some(RenderNavResponse::RemoveColumn(col))
}
}
}
resp
} }
fn unsubscribe_timeline(ndb: &Ndb, timeline: &Timeline) { fn unsubscribe_timeline(ndb: &Ndb, timeline: &Timeline) {

View File

@@ -21,7 +21,6 @@ pub enum Route {
Relays, Relays,
ComposeNote, ComposeNote,
AddColumn(AddColumnRoute), AddColumn(AddColumnRoute),
Profile(Pubkey),
Support, Support,
} }
@@ -58,6 +57,10 @@ impl Route {
Route::Timeline(TimelineRoute::Thread(thread_root)) Route::Timeline(TimelineRoute::Thread(thread_root))
} }
pub fn profile(pubkey: Pubkey) -> Self {
Route::Timeline(TimelineRoute::Profile(pubkey))
}
pub fn reply(replying_to: NoteId) -> Self { pub fn reply(replying_to: NoteId) -> Self {
Route::Timeline(TimelineRoute::Reply(replying_to)) Route::Timeline(TimelineRoute::Reply(replying_to))
} }
@@ -92,6 +95,9 @@ impl Route {
TimelineRoute::Quote(id) => { TimelineRoute::Quote(id) => {
format!("{}'s Quote", get_note_users_displayname_string(ndb, id)) format!("{}'s Quote", get_note_users_displayname_string(ndb, id))
} }
TimelineRoute::Profile(pubkey) => {
format!("{}'s Profile", get_profile_displayname_string(ndb, pubkey))
}
}, },
Route::Relays => "Relays".to_owned(), Route::Relays => "Relays".to_owned(),
@@ -108,9 +114,6 @@ impl Route {
"Add External Notifications Column".to_owned() "Add External Notifications Column".to_owned()
} }
}, },
Route::Profile(pubkey) => {
format!("{}'s Profile", get_profile_displayname_string(ndb, pubkey))
}
Route::Support => "Damus Support".to_owned(), Route::Support => "Damus Support".to_owned(),
}; };
@@ -207,6 +210,7 @@ impl fmt::Display for Route {
Route::Timeline(tlr) => match tlr { Route::Timeline(tlr) => match tlr {
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::Profile(_id) => write!(f, "Profile"),
TimelineRoute::Reply(_id) => write!(f, "Reply"), TimelineRoute::Reply(_id) => write!(f, "Reply"),
TimelineRoute::Quote(_id) => write!(f, "Quote"), TimelineRoute::Quote(_id) => write!(f, "Quote"),
}, },
@@ -220,7 +224,6 @@ impl fmt::Display for Route {
Route::ComposeNote => write!(f, "Compose Note"), Route::ComposeNote => write!(f, "Compose Note"),
Route::AddColumn(_) => write!(f, "Add Column"), Route::AddColumn(_) => write!(f, "Add Column"),
Route::Profile(_) => write!(f, "Profile"),
Route::Support => write!(f, "Support"), Route::Support => write!(f, "Support"),
} }
} }

View File

@@ -3,6 +3,7 @@ use crate::{
column::Columns, column::Columns,
draft::Drafts, draft::Drafts,
imgcache::ImageCache, imgcache::ImageCache,
nav::RenderNavAction,
notecache::NoteCache, notecache::NoteCache,
notes_holder::NotesHolderStorage, notes_holder::NotesHolderStorage,
profile::Profile, profile::Profile,
@@ -10,53 +11,40 @@ use crate::{
timeline::{TimelineId, TimelineKind}, timeline::{TimelineId, TimelineKind},
ui::{ ui::{
self, self,
note::{ note::{NoteOptions, QuoteRepostView},
post::{PostAction, PostResponse},
NoteOptions, QuoteRepostView,
},
profile::ProfileView, profile::ProfileView,
}, },
unknowns::UnknownIds, unknowns::UnknownIds,
}; };
use enostr::{NoteId, Pubkey, RelayPool}; use enostr::{NoteId, Pubkey};
use nostrdb::{Ndb, Transaction}; use nostrdb::{Ndb, Transaction};
#[derive(Debug, Eq, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] #[derive(Debug, Eq, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)]
pub enum TimelineRoute { pub enum TimelineRoute {
Timeline(TimelineId), Timeline(TimelineId),
Thread(NoteId), Thread(NoteId),
Profile(Pubkey),
Reply(NoteId), Reply(NoteId),
Quote(NoteId), Quote(NoteId),
} }
pub enum AfterRouteExecution {
Post(PostResponse),
OpenProfile(Pubkey),
}
impl AfterRouteExecution {
pub fn post(post: PostResponse) -> Self {
AfterRouteExecution::Post(post)
}
}
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn render_timeline_route( pub fn render_timeline_route(
ndb: &Ndb, ndb: &Ndb,
columns: &mut Columns, columns: &mut Columns,
pool: &mut RelayPool,
drafts: &mut Drafts, drafts: &mut Drafts,
img_cache: &mut ImageCache, img_cache: &mut ImageCache,
unknown_ids: &mut UnknownIds, unknown_ids: &mut UnknownIds,
note_cache: &mut NoteCache, note_cache: &mut NoteCache,
threads: &mut NotesHolderStorage<Thread>, threads: &mut NotesHolderStorage<Thread>,
profiles: &mut NotesHolderStorage<Profile>,
accounts: &mut Accounts, accounts: &mut Accounts,
route: TimelineRoute, route: TimelineRoute,
col: usize, col: usize,
textmode: bool, textmode: bool,
ui: &mut egui::Ui, ui: &mut egui::Ui,
) -> Option<AfterRouteExecution> { ) -> Option<RenderNavAction> {
match route { match route {
TimelineRoute::Timeline(timeline_id) => { TimelineRoute::Timeline(timeline_id) => {
let note_options = { let note_options = {
@@ -71,7 +59,7 @@ pub fn render_timeline_route(
options options
}; };
let timeline_response = ui::TimelineView::new( let note_action = ui::TimelineView::new(
timeline_id, timeline_id,
columns, columns,
ndb, ndb,
@@ -81,42 +69,21 @@ pub fn render_timeline_route(
) )
.ui(ui); .ui(ui);
if let Some(bar_action) = timeline_response.bar_action { note_action.map(RenderNavAction::NoteAction)
let txn = Transaction::new(ndb).expect("txn");
let mut cur_column = columns.columns_mut();
let router = cur_column[col].router_mut();
bar_action.execute_and_process_result(ndb, router, threads, note_cache, pool, &txn);
}
timeline_response
.open_profile
.map(AfterRouteExecution::OpenProfile)
} }
TimelineRoute::Thread(id) => { TimelineRoute::Thread(id) => ui::ThreadView::new(
let timeline_response = ui::ThreadView::new( threads,
threads, ndb,
ndb, note_cache,
note_cache, unknown_ids,
unknown_ids, img_cache,
img_cache, id.bytes(),
id.bytes(), textmode,
textmode, )
) .id_source(egui::Id::new(("threadscroll", col)))
.id_source(egui::Id::new(("threadscroll", col))) .ui(ui)
.ui(ui); .map(Into::into),
if let Some(bar_action) = timeline_response.bar_action {
let txn = Transaction::new(ndb).expect("txn");
let mut cur_column = columns.columns_mut();
let router = cur_column[col].router_mut();
bar_action.execute_and_process_result(ndb, router, threads, note_cache, pool, &txn);
}
timeline_response
.open_profile
.map(AfterRouteExecution::OpenProfile)
}
TimelineRoute::Reply(id) => { TimelineRoute::Reply(id) => {
let txn = if let Ok(txn) = Transaction::new(ndb) { let txn = if let Ok(txn) = Transaction::new(ndb) {
@@ -135,21 +102,24 @@ 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 poster = accounts.selected_or_first_nsec()?;
let draft = drafts.reply_mut(note.id());
let response = egui::ScrollArea::vertical().show(ui, |ui| { let action = {
ui::PostReplyView::new(ndb, poster, draft, note_cache, img_cache, &note) let draft = drafts.reply_mut(note.id());
.id_source(id)
.show(ui)
});
if let Some(action) = &response.inner.action { let response = egui::ScrollArea::vertical().show(ui, |ui| {
PostAction::execute(poster, action, pool, draft, |np, seckey| { ui::PostReplyView::new(ndb, poster, draft, note_cache, img_cache, &note)
np.to_reply(seckey, &note) .id_source(id)
.show(ui)
}); });
}
Some(AfterRouteExecution::post(response.inner)) response.inner.action
};
action.map(Into::into)
}
TimelineRoute::Profile(pubkey) => {
render_profile_route(&pubkey, ndb, profiles, img_cache, note_cache, col, ui)
} }
TimelineRoute::Quote(id) => { TimelineRoute::Quote(id) => {
@@ -173,12 +143,7 @@ pub fn render_timeline_route(
.show(ui) .show(ui)
}); });
if let Some(action) = &response.inner.action { response.inner.action.map(Into::into)
PostAction::execute(poster, action, pool, draft, |np, seckey| {
np.to_quote(seckey, &note)
});
}
Some(AfterRouteExecution::post(response.inner))
} }
} }
} }
@@ -187,16 +152,13 @@ pub fn render_timeline_route(
pub fn render_profile_route( pub fn render_profile_route(
pubkey: &Pubkey, pubkey: &Pubkey,
ndb: &Ndb, ndb: &Ndb,
columns: &mut Columns,
profiles: &mut NotesHolderStorage<Profile>, profiles: &mut NotesHolderStorage<Profile>,
pool: &mut RelayPool,
img_cache: &mut ImageCache, img_cache: &mut ImageCache,
note_cache: &mut NoteCache, note_cache: &mut NoteCache,
threads: &mut NotesHolderStorage<Thread>,
col: usize, col: usize,
ui: &mut egui::Ui, ui: &mut egui::Ui,
) -> Option<AfterRouteExecution> { ) -> Option<RenderNavAction> {
let timeline_response = ProfileView::new( let note_action = ProfileView::new(
pubkey, pubkey,
col, col,
profiles, profiles,
@@ -206,15 +168,6 @@ pub fn render_profile_route(
NoteOptions::default(), NoteOptions::default(),
) )
.ui(ui); .ui(ui);
if let Some(bar_action) = timeline_response.bar_action {
let txn = nostrdb::Transaction::new(ndb).expect("txn");
let mut cur_column = columns.columns_mut();
let router = cur_column[col].router_mut();
bar_action.execute_and_process_result(ndb, router, threads, note_cache, pool, &txn); note_action.map(RenderNavAction::NoteAction)
}
timeline_response
.open_profile
.map(AfterRouteExecution::OpenProfile)
} }

View File

@@ -1,4 +1,4 @@
use crate::actionbar::NoteActionResponse; use crate::actionbar::NoteAction;
use crate::images::ImageType; use crate::images::ImageType;
use crate::imgcache::ImageCache; use crate::imgcache::ImageCache;
use crate::notecache::NoteCache; use crate::notecache::NoteCache;
@@ -17,7 +17,7 @@ pub struct NoteContents<'a> {
note: &'a Note<'a>, note: &'a Note<'a>,
note_key: NoteKey, note_key: NoteKey,
options: NoteOptions, options: NoteOptions,
action: NoteActionResponse, action: Option<NoteAction>,
} }
impl<'a> NoteContents<'a> { impl<'a> NoteContents<'a> {
@@ -38,11 +38,11 @@ impl<'a> NoteContents<'a> {
note, note,
note_key, note_key,
options, options,
action: NoteActionResponse::default(), action: None,
} }
} }
pub fn action(&self) -> &NoteActionResponse { pub fn action(&self) -> &Option<NoteAction> {
&self.action &self.action
} }
} }
@@ -212,7 +212,7 @@ fn render_note_contents(
let note_action = if let Some((id, block_str)) = inline_note { let note_action = if let Some((id, block_str)) = inline_note {
render_note_preview(ui, ndb, note_cache, img_cache, txn, id, block_str).action render_note_preview(ui, ndb, note_cache, img_cache, txn, id, block_str).action
} else { } else {
NoteActionResponse::default() None
}; };
if !images.is_empty() && !options.has_textmode() { if !images.is_empty() && !options.has_textmode() {

View File

@@ -8,12 +8,12 @@ pub mod reply;
pub use contents::NoteContents; pub use contents::NoteContents;
pub use context::{NoteContextButton, NoteContextSelection}; pub use context::{NoteContextButton, NoteContextSelection};
pub use options::NoteOptions; pub use options::NoteOptions;
pub use post::{PostAction, PostResponse, PostView}; pub use post::{PostAction, PostResponse, PostType, PostView};
pub use quote_repost::QuoteRepostView; pub use quote_repost::QuoteRepostView;
pub use reply::PostReplyView; pub use reply::PostReplyView;
use crate::{ use crate::{
actionbar::{BarAction, NoteActionResponse}, actionbar::NoteAction,
app_style::NotedeckTextStyle, app_style::NotedeckTextStyle,
colors, colors,
imgcache::ImageCache, imgcache::ImageCache,
@@ -38,7 +38,7 @@ pub struct NoteView<'a> {
pub struct NoteResponse { pub struct NoteResponse {
pub response: egui::Response, pub response: egui::Response,
pub context_selection: Option<NoteContextSelection>, pub context_selection: Option<NoteContextSelection>,
pub action: NoteActionResponse, pub action: Option<NoteAction>,
} }
impl NoteResponse { impl NoteResponse {
@@ -46,11 +46,11 @@ impl NoteResponse {
Self { Self {
response, response,
context_selection: None, context_selection: None,
action: NoteActionResponse::default(), action: None,
} }
} }
pub fn with_action(mut self, action: NoteActionResponse) -> Self { pub fn with_action(mut self, action: Option<NoteAction>) -> Self {
self.action = action; self.action = action;
self self
} }
@@ -437,8 +437,7 @@ impl<'a> NoteView<'a> {
let note_key = self.note.key().expect("todo: support non-db notes"); let note_key = self.note.key().expect("todo: support non-db notes");
let txn = self.note.txn().expect("todo: support non-db notes"); let txn = self.note.txn().expect("todo: support non-db notes");
let mut open_profile: Option<Pubkey> = None; let mut note_action: Option<NoteAction> = None;
let mut bar_action: Option<BarAction> = None;
let mut selected_option: Option<NoteContextSelection> = None; let mut selected_option: Option<NoteContextSelection> = None;
let profile = self.ndb.get_profile_by_pubkey(txn, self.note.pubkey()); let profile = self.ndb.get_profile_by_pubkey(txn, self.note.pubkey());
@@ -454,7 +453,7 @@ impl<'a> NoteView<'a> {
let response = if self.options().has_wide() { let response = if self.options().has_wide() {
ui.horizontal(|ui| { ui.horizontal(|ui| {
if self.pfp(note_key, &profile, ui).clicked() { if self.pfp(note_key, &profile, ui).clicked() {
open_profile = Some(Pubkey::new(*self.note.pubkey())); note_action = Some(NoteAction::OpenProfile(Pubkey::new(*self.note.pubkey())));
}; };
let size = ui.available_size(); let size = ui.available_size();
@@ -498,12 +497,15 @@ impl<'a> NoteView<'a> {
self.options(), self.options(),
); );
let resp = ui.add(&mut contents); let resp = ui.add(&mut contents);
bar_action = bar_action.or(contents.action().bar_action);
open_profile = open_profile.or(contents.action().open_profile); if let Some(action) = contents.action() {
note_action = Some(*action);
}
if self.options().has_actionbar() { if self.options().has_actionbar() {
let ab = render_note_actionbar(ui, self.note.id(), note_key); if let Some(action) = render_note_actionbar(ui, self.note.id(), note_key).inner {
bar_action = bar_action.or(ab.inner); note_action = Some(action);
}
} }
resp resp
@@ -511,7 +513,7 @@ impl<'a> NoteView<'a> {
// main design // main design
ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| { ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {
if self.pfp(note_key, &profile, ui).clicked() { if self.pfp(note_key, &profile, ui).clicked() {
open_profile = Some(Pubkey::new(*self.note.pubkey())); note_action = Some(NoteAction::OpenProfile(Pubkey::new(*self.note.pubkey())));
}; };
ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| { ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| {
@@ -548,32 +550,34 @@ impl<'a> NoteView<'a> {
self.options(), self.options(),
); );
ui.add(&mut contents); ui.add(&mut contents);
bar_action = bar_action.or(contents.action().bar_action);
open_profile = open_profile.or(contents.action().open_profile); if let Some(action) = contents.action() {
note_action = Some(*action);
}
if self.options().has_actionbar() { if self.options().has_actionbar() {
let ab = render_note_actionbar(ui, self.note.id(), note_key); if let Some(action) =
bar_action = bar_action.or(ab.inner); render_note_actionbar(ui, self.note.id(), note_key).inner
{
note_action = Some(action);
}
} }
}); });
}) })
.response .response
}; };
bar_action = check_note_hitbox( note_action = check_note_hitbox(
ui, ui,
self.note.id(), self.note.id(),
note_key, note_key,
&response, &response,
maybe_hitbox, maybe_hitbox,
bar_action, note_action,
); );
NoteResponse::new(response) NoteResponse::new(response)
.with_action(NoteActionResponse { .with_action(note_action)
bar_action,
open_profile,
})
.select_option(selected_option) .select_option(selected_option)
} }
} }
@@ -630,8 +634,8 @@ fn check_note_hitbox(
note_key: NoteKey, note_key: NoteKey,
note_response: &Response, note_response: &Response,
maybe_hitbox: Option<Response>, maybe_hitbox: Option<Response>,
prior_action: Option<BarAction>, prior_action: Option<NoteAction>,
) -> Option<BarAction> { ) -> Option<NoteAction> {
// Stash the dimensions of the note content so we can render the // Stash the dimensions of the note content so we can render the
// hitbox in the next frame // hitbox in the next frame
ui.ctx().data_mut(|d| { ui.ctx().data_mut(|d| {
@@ -640,7 +644,7 @@ fn check_note_hitbox(
// If there was an hitbox and it was clicked open the thread // If there was an hitbox and it was clicked open the thread
match maybe_hitbox { match maybe_hitbox {
Some(hitbox) if hitbox.clicked() => Some(BarAction::OpenThread(NoteId::new(*note_id))), Some(hitbox) if hitbox.clicked() => Some(NoteAction::OpenThread(NoteId::new(*note_id))),
_ => prior_action, _ => prior_action,
} }
} }
@@ -649,15 +653,15 @@ fn render_note_actionbar(
ui: &mut egui::Ui, ui: &mut egui::Ui,
note_id: &[u8; 32], note_id: &[u8; 32],
note_key: NoteKey, note_key: NoteKey,
) -> egui::InnerResponse<Option<BarAction>> { ) -> egui::InnerResponse<Option<NoteAction>> {
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); 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(NoteAction::Reply(NoteId::new(*note_id)))
} else if quote_resp.clicked() { } else if quote_resp.clicked() {
Some(BarAction::Quote(NoteId::new(*note_id))) Some(NoteAction::Quote(NoteId::new(*note_id)))
} else { } else {
None None
} }

View File

@@ -1,13 +1,14 @@
use crate::draft::{Draft, DraftSource}; use crate::draft::{Draft, Drafts};
use crate::imgcache::ImageCache; use crate::imgcache::ImageCache;
use crate::notecache::NoteCache; 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 crate::Result;
use egui::widgets::text_edit::TextEdit; use egui::widgets::text_edit::TextEdit;
use egui::{Frame, Layout}; use egui::{Frame, Layout};
use enostr::{FilledKeypair, FullKeypair, RelayPool}; use enostr::{FilledKeypair, FullKeypair, NoteId, RelayPool};
use nostrdb::{Config, Ndb, Note, Transaction}; use nostrdb::{Config, Ndb, Transaction};
use tracing::info; use tracing::info;
use super::contents::render_note_preview; use super::contents::render_note_preview;
@@ -15,35 +16,59 @@ 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>, post_type: PostType,
img_cache: &'a mut ImageCache, img_cache: &'a mut ImageCache,
note_cache: &'a mut NoteCache, note_cache: &'a mut NoteCache,
poster: FilledKeypair<'a>, poster: FilledKeypair<'a>,
id_source: Option<egui::Id>, id_source: Option<egui::Id>,
} }
pub enum PostAction { #[derive(Clone)]
Post(NewPost), pub enum PostType {
New,
Quote(NoteId),
Reply(NoteId),
}
pub struct PostAction {
post_type: PostType,
post: NewPost,
} }
impl PostAction { impl PostAction {
pub fn execute<'b>( pub fn new(post_type: PostType, post: NewPost) -> Self {
poster: FilledKeypair<'_>, PostAction { post_type, post }
action: &'b PostAction, }
pool: &mut RelayPool,
draft: &mut Draft,
get_note: impl Fn(&'b NewPost, &[u8; 32]) -> Note<'b>,
) {
match action {
PostAction::Post(np) => {
let note = get_note(np, &poster.secret_key.to_secret_bytes());
let raw_msg = format!("[\"EVENT\",{}]", note.json().unwrap()); pub fn execute(
info!("sending {}", raw_msg); &self,
pool.send(&enostr::ClientMessage::raw(raw_msg)); ndb: &Ndb,
draft.clear(); txn: &Transaction,
pool: &mut RelayPool,
drafts: &mut Drafts,
) -> Result<()> {
let seckey = self.post.account.secret_key.to_secret_bytes();
let note = match self.post_type {
PostType::New => self.post.to_note(&seckey),
PostType::Reply(target) => {
let replying_to = ndb.get_note_by_id(txn, target.bytes())?;
self.post.to_reply(&seckey, &replying_to)
} }
}
PostType::Quote(target) => {
let quoting = ndb.get_note_by_id(txn, target.bytes())?;
self.post.to_quote(&seckey, &quoting)
}
};
let raw_msg = format!("[\"EVENT\",{}]", note.json().unwrap());
info!("sending {}", raw_msg);
pool.send(&enostr::ClientMessage::raw(raw_msg));
drafts.get_from_post_type(&self.post_type).clear();
Ok(())
} }
} }
@@ -56,7 +81,7 @@ 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>, post_type: PostType,
img_cache: &'a mut ImageCache, img_cache: &'a mut ImageCache,
note_cache: &'a mut NoteCache, note_cache: &'a mut NoteCache,
poster: FilledKeypair<'a>, poster: FilledKeypair<'a>,
@@ -69,7 +94,7 @@ impl<'a> PostView<'a> {
note_cache, note_cache,
poster, poster,
id_source, id_source,
draft_source, post_type,
} }
} }
@@ -162,7 +187,7 @@ impl<'a> PostView<'a> {
let action = ui let action = ui
.horizontal(|ui| { .horizontal(|ui| {
if let DraftSource::Quote(id) = self.draft_source { 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| { ui.with_layout(Layout::left_to_right(egui::Align::TOP), |ui| {
Frame::none().show(ui, |ui| { Frame::none().show(ui, |ui| {
@@ -174,7 +199,7 @@ impl<'a> PostView<'a> {
self.note_cache, self.note_cache,
self.img_cache, self.img_cache,
txn, txn,
id, id.bytes(),
"", "",
); );
}); });
@@ -187,10 +212,11 @@ impl<'a> PostView<'a> {
.add_sized([91.0, 32.0], egui::Button::new("Post now")) .add_sized([91.0, 32.0], egui::Button::new("Post now"))
.clicked() .clicked()
{ {
Some(PostAction::Post(NewPost::new( let new_post = NewPost::new(
self.draft.buffer.clone(), self.draft.buffer.clone(),
self.poster.to_full(), self.poster.to_full(),
))) );
Some(PostAction::new(self.post_type.clone(), new_post))
} else { } else {
None None
} }
@@ -241,7 +267,7 @@ mod preview {
PostView::new( PostView::new(
&self.ndb, &self.ndb,
&mut self.draft, &mut self.draft,
DraftSource::Compose, PostType::New,
&mut self.img_cache, &mut self.img_cache,
&mut self.note_cache, &mut self.note_cache,
self.poster.to_filled(), self.poster.to_filled(),

View File

@@ -1,9 +1,9 @@
use enostr::FilledKeypair; use enostr::{FilledKeypair, NoteId};
use nostrdb::Ndb; use nostrdb::Ndb;
use crate::{draft::Draft, imgcache::ImageCache, notecache::NoteCache, ui}; use crate::{draft::Draft, imgcache::ImageCache, notecache::NoteCache, ui};
use super::PostResponse; use super::{PostResponse, PostType};
pub struct QuoteRepostView<'a> { pub struct QuoteRepostView<'a> {
ndb: &'a Ndb, ndb: &'a Ndb,
@@ -43,7 +43,7 @@ impl<'a> QuoteRepostView<'a> {
ui::PostView::new( ui::PostView::new(
self.ndb, self.ndb,
self.draft, self.draft,
crate::draft::DraftSource::Quote(quoting_note_id), PostType::Quote(NoteId::new(quoting_note_id.to_owned())),
self.img_cache, self.img_cache,
self.note_cache, self.note_cache,
self.poster, self.poster,

View File

@@ -2,8 +2,8 @@ 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::PostResponse; use crate::ui::note::{PostResponse, PostType};
use enostr::FilledKeypair; use enostr::{FilledKeypair, NoteId};
use nostrdb::Ndb; use nostrdb::Ndb;
pub struct PostReplyView<'a> { pub struct PostReplyView<'a> {
@@ -79,7 +79,7 @@ impl<'a> PostReplyView<'a> {
ui::PostView::new( ui::PostView::new(
self.ndb, self.ndb,
self.draft, self.draft,
crate::draft::DraftSource::Reply(replying_to), PostType::Reply(NoteId::new(*replying_to)),
self.img_cache, self.img_cache,
self.note_cache, self.note_cache,
self.poster, self.poster,

View File

@@ -9,7 +9,7 @@ pub use picture::ProfilePic;
pub use preview::ProfilePreview; pub use preview::ProfilePreview;
use crate::{ use crate::{
actionbar::NoteActionResponse, imgcache::ImageCache, notecache::NoteCache, actionbar::NoteAction, imgcache::ImageCache, notecache::NoteCache,
notes_holder::NotesHolderStorage, profile::Profile, notes_holder::NotesHolderStorage, profile::Profile,
}; };
@@ -46,7 +46,7 @@ impl<'a> ProfileView<'a> {
} }
} }
pub fn ui(&mut self, ui: &mut egui::Ui) -> NoteActionResponse { pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
let scroll_id = egui::Id::new(("profile_scroll", self.col_id, self.pubkey)); let scroll_id = egui::Id::new(("profile_scroll", self.col_id, self.pubkey));
ScrollArea::vertical() ScrollArea::vertical()

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
actionbar::NoteActionResponse, actionbar::NoteAction,
imgcache::ImageCache, imgcache::ImageCache,
notecache::NoteCache, notecache::NoteCache,
notes_holder::{NotesHolder, NotesHolderStorage}, notes_holder::{NotesHolder, NotesHolderStorage},
@@ -52,7 +52,7 @@ impl<'a> ThreadView<'a> {
self self
} }
pub fn ui(&mut self, ui: &mut egui::Ui) -> NoteActionResponse { pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
let txn = Transaction::new(self.ndb).expect("txn"); let txn = Transaction::new(self.ndb).expect("txn");
let selected_note_key = if let Ok(key) = self let selected_note_key = if let Ok(key) = self
@@ -63,7 +63,7 @@ impl<'a> ThreadView<'a> {
key key
} else { } else {
// TODO: render 404 ? // TODO: render 404 ?
return NoteActionResponse::default(); return None;
}; };
ui.label( ui.label(
@@ -80,7 +80,7 @@ impl<'a> ThreadView<'a> {
let note = if let Ok(note) = self.ndb.get_note_by_key(&txn, selected_note_key) { let note = if let Ok(note) = self.ndb.get_note_by_key(&txn, selected_note_key) {
note note
} else { } else {
return NoteActionResponse::default(); return None;
}; };
let root_id = { let root_id = {

View File

@@ -1,4 +1,4 @@
use crate::actionbar::{BarAction, NoteActionResponse}; use crate::actionbar::NoteAction;
use crate::timeline::TimelineTab; use crate::timeline::TimelineTab;
use crate::{ use crate::{
column::Columns, imgcache::ImageCache, notecache::NoteCache, timeline::TimelineId, ui, column::Columns, imgcache::ImageCache, notecache::NoteCache, timeline::TimelineId, ui,
@@ -41,7 +41,7 @@ impl<'a> TimelineView<'a> {
} }
} }
pub fn ui(&mut self, ui: &mut egui::Ui) -> NoteActionResponse { pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
timeline_ui( timeline_ui(
ui, ui,
self.ndb, self.ndb,
@@ -70,7 +70,7 @@ fn timeline_ui(
img_cache: &mut ImageCache, img_cache: &mut ImageCache,
reversed: bool, reversed: bool,
note_options: NoteOptions, note_options: NoteOptions,
) -> NoteActionResponse { ) -> Option<NoteAction> {
//padding(4.0, ui, |ui| ui.heading("Notifications")); //padding(4.0, ui, |ui| ui.heading("Notifications"));
/* /*
let font_id = egui::TextStyle::Body.resolve(ui.style()); let font_id = egui::TextStyle::Body.resolve(ui.style());
@@ -85,7 +85,7 @@ fn timeline_ui(
error!("tried to render timeline in column, but timeline was missing"); error!("tried to render timeline in column, but timeline was missing");
// TODO (jb55): render error when timeline is missing? // TODO (jb55): render error when timeline is missing?
// this shouldn't happen... // this shouldn't happen...
return NoteActionResponse::default(); return None;
}; };
timeline.selected_view = tabs_ui(ui); timeline.selected_view = tabs_ui(ui);
@@ -108,7 +108,7 @@ fn timeline_ui(
error!("tried to render timeline in column, but timeline was missing"); error!("tried to render timeline in column, but timeline was missing");
// TODO (jb55): render error when timeline is missing? // TODO (jb55): render error when timeline is missing?
// this shouldn't happen... // this shouldn't happen...
return NoteActionResponse::default(); return None;
}; };
let txn = Transaction::new(ndb).expect("failed to create txn"); let txn = Transaction::new(ndb).expect("failed to create txn");
@@ -241,9 +241,8 @@ impl<'a> TimelineTabView<'a> {
} }
} }
pub fn show(&mut self, ui: &mut egui::Ui) -> NoteActionResponse { pub fn show(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
let mut open_profile = None; let mut action: Option<NoteAction> = None;
let mut bar_action: Option<BarAction> = None;
let len = self.tab.notes.len(); let len = self.tab.notes.len();
self.tab self.tab
@@ -274,8 +273,9 @@ impl<'a> TimelineTabView<'a> {
.note_options(self.note_options) .note_options(self.note_options)
.show(ui); .show(ui);
bar_action = bar_action.or(resp.action.bar_action); if let Some(note_action) = resp.action {
open_profile = open_profile.or(resp.action.open_profile); action = Some(note_action)
}
if let Some(context) = resp.context_selection { if let Some(context) = resp.context_selection {
context.process(ui, &note); context.process(ui, &note);
@@ -288,9 +288,6 @@ impl<'a> TimelineTabView<'a> {
1 1
}); });
NoteActionResponse { action
open_profile,
bar_action,
}
} }
} }