mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-19 09:34:19 +01:00
prop drag id through responses instead of manual wiring
Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
@@ -7,6 +7,7 @@ use notedeck_ui::nip51_set::Nip51SetUiCache;
|
||||
pub use crate::accounts::route::AccountsResponse;
|
||||
use crate::app::get_active_columns_mut;
|
||||
use crate::decks::DecksCache;
|
||||
use crate::nav::BodyResponse;
|
||||
use crate::onboarding::Onboarding;
|
||||
use crate::profile::send_new_contact_list;
|
||||
use crate::subscriptions::Subscriptions;
|
||||
@@ -81,7 +82,7 @@ pub fn render_accounts_route(
|
||||
onboarding: &mut Onboarding,
|
||||
follow_packs_ui: &mut Nip51SetUiCache,
|
||||
route: AccountsRoute,
|
||||
) -> Option<AccountsResponse> {
|
||||
) -> BodyResponse<AccountsResponse> {
|
||||
match route {
|
||||
AccountsRoute::Accounts => AccountsView::new(
|
||||
app_ctx.ndb,
|
||||
@@ -90,15 +91,15 @@ pub fn render_accounts_route(
|
||||
app_ctx.i18n,
|
||||
)
|
||||
.ui(ui)
|
||||
.inner
|
||||
.map(AccountsRouteResponse::Accounts)
|
||||
.map(AccountsResponse::Account),
|
||||
.map_output(AccountsRouteResponse::Accounts)
|
||||
.map_output(AccountsResponse::Account),
|
||||
AccountsRoute::AddAccount => {
|
||||
AccountLoginView::new(login_state, app_ctx.clipboard, app_ctx.i18n)
|
||||
let action = AccountLoginView::new(login_state, app_ctx.clipboard, app_ctx.i18n)
|
||||
.ui(ui)
|
||||
.inner
|
||||
.map(AccountsRouteResponse::AddAccount)
|
||||
.map(AccountsResponse::Account)
|
||||
.map(AccountsResponse::Account);
|
||||
BodyResponse::output(action)
|
||||
}
|
||||
AccountsRoute::Onboarding => FollowPackOnboardingView::new(
|
||||
onboarding,
|
||||
@@ -110,7 +111,7 @@ pub fn render_accounts_route(
|
||||
jobs,
|
||||
)
|
||||
.ui(ui)
|
||||
.map(|r| match r {
|
||||
.map_output(|r| match r {
|
||||
OnboardingResponse::FollowPacks(follow_packs_response) => {
|
||||
AccountsResponse::Account(AccountsRouteResponse::AddAccount(
|
||||
AccountLoginResponse::Onboarding(follow_packs_response),
|
||||
|
||||
@@ -33,6 +33,7 @@ use crate::{
|
||||
Damus,
|
||||
};
|
||||
|
||||
use egui::scroll_area::ScrollAreaOutput;
|
||||
use egui_nav::{Nav, NavAction, NavResponse, NavUiType, Percent, PopupResponse, PopupSheet};
|
||||
use enostr::ProfileState;
|
||||
use nostrdb::{Filter, Ndb, Transaction};
|
||||
@@ -532,7 +533,7 @@ fn render_nav_body(
|
||||
depth: usize,
|
||||
col: usize,
|
||||
inner_rect: egui::Rect,
|
||||
) -> Option<RenderNavAction> {
|
||||
) -> BodyResponse<RenderNavAction> {
|
||||
let mut note_context = NoteContext {
|
||||
ndb: ctx.ndb,
|
||||
accounts: ctx.accounts,
|
||||
@@ -555,7 +556,7 @@ fn render_nav_body(
|
||||
.is_some_and(|ind| ind == col)
|
||||
&& app.options.contains(AppOptions::ScrollToTop);
|
||||
|
||||
let nav_action = render_timeline_route(
|
||||
let resp = render_timeline_route(
|
||||
&mut app.timeline_cache,
|
||||
kind,
|
||||
col,
|
||||
@@ -574,7 +575,7 @@ fn render_nav_body(
|
||||
app.options.remove(AppOptions::ScrollToTop);
|
||||
}
|
||||
|
||||
nav_action
|
||||
resp
|
||||
}
|
||||
Route::Thread(selection) => render_thread_route(
|
||||
&mut app.threads,
|
||||
@@ -585,8 +586,8 @@ fn render_nav_body(
|
||||
&mut note_context,
|
||||
&mut app.jobs,
|
||||
),
|
||||
Route::Accounts(amr) => 's: {
|
||||
let Some(action) = render_accounts_route(
|
||||
Route::Accounts(amr) => {
|
||||
let resp = render_accounts_route(
|
||||
ui,
|
||||
ctx,
|
||||
&mut app.jobs,
|
||||
@@ -594,11 +595,9 @@ fn render_nav_body(
|
||||
&mut app.onboarding,
|
||||
&mut app.view_state.follow_packs,
|
||||
*amr,
|
||||
) else {
|
||||
break 's None;
|
||||
};
|
||||
);
|
||||
|
||||
match action {
|
||||
resp.map_output_maybe(|action| match action {
|
||||
AccountsResponse::ViewProfile(pubkey) => {
|
||||
Some(RenderNavAction::NoteAction(NoteAction::Profile(pubkey)))
|
||||
}
|
||||
@@ -611,11 +610,11 @@ fn render_nav_body(
|
||||
.accounts_action
|
||||
.map(|f| RenderNavAction::SwitchingAction(SwitchingAction::Accounts(f)))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Route::Relays => RelayView::new(ctx.pool, &mut app.view_state.id_string_map, ctx.i18n)
|
||||
.ui(ui)
|
||||
.map(RenderNavAction::RelayAction),
|
||||
.map_output(RenderNavAction::RelayAction),
|
||||
|
||||
Route::Settings => SettingsView::new(
|
||||
ctx.settings.get_settings_mut(),
|
||||
@@ -624,7 +623,7 @@ fn render_nav_body(
|
||||
&mut app.jobs,
|
||||
)
|
||||
.ui(ui)
|
||||
.map(RenderNavAction::SettingsAction),
|
||||
.map_output(RenderNavAction::SettingsAction),
|
||||
|
||||
Route::Reply(id) => {
|
||||
let txn = if let Ok(txn) = Transaction::new(ctx.ndb) {
|
||||
@@ -635,7 +634,7 @@ fn render_nav_body(
|
||||
"Reply to unknown note",
|
||||
"Error message when reply note cannot be found"
|
||||
));
|
||||
return None;
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
let note = if let Ok(note) = ctx.ndb.get_note_by_id(&txn, id.bytes()) {
|
||||
@@ -646,18 +645,20 @@ fn render_nav_body(
|
||||
"Reply to unknown note",
|
||||
"Error message when reply note cannot be found"
|
||||
));
|
||||
return None;
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
let poster = ctx.accounts.selected_filled()?;
|
||||
let Some(poster) = ctx.accounts.selected_filled() else {
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
let action = {
|
||||
let resp = {
|
||||
let draft = app.drafts.reply_mut(note.id());
|
||||
|
||||
let mut options = app.note_options;
|
||||
options.set(NoteOptions::Wide, false);
|
||||
|
||||
let response = ui::PostReplyView::new(
|
||||
ui::PostReplyView::new(
|
||||
&mut note_context,
|
||||
poster,
|
||||
draft,
|
||||
@@ -667,12 +668,10 @@ fn render_nav_body(
|
||||
&mut app.jobs,
|
||||
col,
|
||||
)
|
||||
.show(ui);
|
||||
|
||||
response.action
|
||||
.show(ui)
|
||||
};
|
||||
|
||||
action.map(Into::into)
|
||||
resp.map_output_maybe(|o| Some(o.action?.into()))
|
||||
}
|
||||
Route::Quote(id) => {
|
||||
let txn = Transaction::new(ctx.ndb).expect("txn");
|
||||
@@ -685,10 +684,13 @@ fn render_nav_body(
|
||||
"Quote of unknown note",
|
||||
"Error message when quote note cannot be found"
|
||||
));
|
||||
return None;
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
let Some(poster) = ctx.accounts.selected_filled() else {
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
let poster = ctx.accounts.selected_filled()?;
|
||||
let draft = app.drafts.quote_mut(note.id());
|
||||
|
||||
let response = crate::ui::note::QuoteRepostView::new(
|
||||
@@ -703,10 +705,12 @@ fn render_nav_body(
|
||||
)
|
||||
.show(ui);
|
||||
|
||||
response.action.map(Into::into)
|
||||
response.map_output_maybe(|o| Some(o.action?.into()))
|
||||
}
|
||||
Route::ComposeNote => {
|
||||
let kp = ctx.accounts.get_selected_account().key.to_full()?;
|
||||
let Some(kp) = ctx.accounts.get_selected_account().key.to_full() else {
|
||||
return BodyResponse::none();
|
||||
};
|
||||
let draft = app.drafts.compose_mut();
|
||||
|
||||
let txn = Transaction::new(ctx.ndb).expect("txn");
|
||||
@@ -721,16 +725,16 @@ fn render_nav_body(
|
||||
)
|
||||
.ui(&txn, ui);
|
||||
|
||||
post_response.action.map(Into::into)
|
||||
post_response.map_output_maybe(|o| Some(o.action?.into()))
|
||||
}
|
||||
Route::AddColumn(route) => {
|
||||
render_add_column_routes(ui, app, ctx, col, route);
|
||||
|
||||
None
|
||||
BodyResponse::none()
|
||||
}
|
||||
Route::Support => {
|
||||
SupportView::new(&mut app.support, ctx.i18n).show(ui);
|
||||
None
|
||||
BodyResponse::none()
|
||||
}
|
||||
Route::Search => {
|
||||
let id = ui.id().with(("search", depth, col));
|
||||
@@ -759,7 +763,7 @@ fn render_nav_body(
|
||||
&mut app.jobs,
|
||||
)
|
||||
.show(ui)
|
||||
.map(RenderNavAction::NoteAction)
|
||||
.map_output(RenderNavAction::NoteAction)
|
||||
}
|
||||
Route::NewDeck => {
|
||||
let id = ui.id().with("new-deck");
|
||||
@@ -784,7 +788,8 @@ fn render_nav_body(
|
||||
.get_selected_router()
|
||||
.go_back();
|
||||
}
|
||||
resp
|
||||
|
||||
BodyResponse::output(resp)
|
||||
}
|
||||
Route::EditDeck(index) => {
|
||||
let mut action = None;
|
||||
@@ -816,31 +821,37 @@ fn render_nav_body(
|
||||
.go_back();
|
||||
}
|
||||
|
||||
action
|
||||
BodyResponse::output(action)
|
||||
}
|
||||
Route::EditProfile(pubkey) => {
|
||||
let mut action = None;
|
||||
let Some(kp) = ctx.accounts.get_full(pubkey) else {
|
||||
error!("Pubkey in EditProfile route did not have an nsec attached in Accounts");
|
||||
return None;
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
let Some(state) = app.view_state.pubkey_to_profile_state.get_mut(kp.pubkey) else {
|
||||
tracing::error!(
|
||||
"No profile state when navigating to EditProfile... was handle_navigating_edit_profile not called?"
|
||||
);
|
||||
return action;
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
if EditProfileView::new(ctx.i18n, state, ctx.img_cache, ctx.clipboard).ui(ui) {
|
||||
if let Some(state) = app.view_state.pubkey_to_profile_state.get(kp.pubkey) {
|
||||
action = Some(RenderNavAction::ProfileAction(ProfileAction::SaveChanges(
|
||||
EditProfileView::new(ctx.i18n, state, ctx.img_cache, ctx.clipboard)
|
||||
.ui(ui)
|
||||
.map_output_maybe(|save| {
|
||||
if save {
|
||||
app.view_state
|
||||
.pubkey_to_profile_state
|
||||
.get(kp.pubkey)
|
||||
.map(|state| {
|
||||
RenderNavAction::ProfileAction(ProfileAction::SaveChanges(
|
||||
SaveProfileChanges::new(kp.to_full(), state.clone()),
|
||||
)))
|
||||
))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
action
|
||||
})
|
||||
}
|
||||
Route::Wallet(wallet_type) => {
|
||||
let state = match wallet_type {
|
||||
@@ -887,13 +898,13 @@ fn render_nav_body(
|
||||
}
|
||||
};
|
||||
|
||||
WalletView::new(state, ctx.i18n, ctx.clipboard)
|
||||
.ui(ui)
|
||||
.map(RenderNavAction::WalletAction)
|
||||
BodyResponse::output(WalletView::new(state, ctx.i18n, ctx.clipboard).ui(ui))
|
||||
.map_output(RenderNavAction::WalletAction)
|
||||
}
|
||||
Route::CustomizeZapAmount(target) => {
|
||||
let txn = Transaction::new(ctx.ndb).expect("txn");
|
||||
let default_msats = get_current_default_msats(ctx.accounts, ctx.global_wallet);
|
||||
BodyResponse::output(
|
||||
CustomZapView::new(
|
||||
ctx.i18n,
|
||||
ctx.img_cache,
|
||||
@@ -902,8 +913,9 @@ fn render_nav_body(
|
||||
&target.zap_recipient,
|
||||
default_msats,
|
||||
)
|
||||
.ui(ui)
|
||||
.map(|msats| {
|
||||
.ui(ui),
|
||||
)
|
||||
.map_output(|msats| {
|
||||
get_active_columns_mut(ctx.i18n, ctx.accounts, &mut app.decks_cache)
|
||||
.column_mut(col)
|
||||
.router_mut()
|
||||
@@ -919,6 +931,87 @@ fn render_nav_body(
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BodyResponse<R> {
|
||||
pub drag_id: Option<egui::Id>, // the id which was used for dragging.
|
||||
pub output: Option<R>,
|
||||
}
|
||||
|
||||
impl<R> BodyResponse<R> {
|
||||
pub fn none() -> Self {
|
||||
Self {
|
||||
drag_id: None,
|
||||
output: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll(output: ScrollAreaOutput<Option<R>>) -> Self {
|
||||
Self {
|
||||
drag_id: Some(Self::scroll_output_to_drag_id(output.id)),
|
||||
output: output.inner,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_scroll_id(&mut self, output: &ScrollAreaOutput<Option<R>>) {
|
||||
self.drag_id = Some(Self::scroll_output_to_drag_id(output.id));
|
||||
}
|
||||
|
||||
pub fn output(output: Option<R>) -> Self {
|
||||
Self {
|
||||
drag_id: None,
|
||||
output,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_output(&mut self, output: R) {
|
||||
self.output = Some(output);
|
||||
}
|
||||
|
||||
/// The id of an `egui::ScrollAreaOutput`
|
||||
/// Should use `Self::scroll` when possible
|
||||
pub fn scroll_raw(mut self, id: egui::Id) -> Self {
|
||||
self.drag_id = Some(Self::scroll_output_to_drag_id(id));
|
||||
self
|
||||
}
|
||||
|
||||
/// The id which is directly used for dragging
|
||||
pub fn set_drag_id_raw(&mut self, id: egui::Id) {
|
||||
self.drag_id = Some(id);
|
||||
}
|
||||
|
||||
fn scroll_output_to_drag_id(id: egui::Id) -> egui::Id {
|
||||
id.with("area")
|
||||
}
|
||||
|
||||
pub fn map_output<S>(self, f: impl FnOnce(R) -> S) -> BodyResponse<S> {
|
||||
BodyResponse {
|
||||
drag_id: self.drag_id,
|
||||
output: self.output.map(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_output_maybe<S>(self, f: impl FnOnce(R) -> Option<S>) -> BodyResponse<S> {
|
||||
BodyResponse {
|
||||
drag_id: self.drag_id,
|
||||
output: self.output.and_then(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_map_output<S>(self, f: impl FnOnce(Option<R>) -> S) -> BodyResponse<S> {
|
||||
BodyResponse {
|
||||
drag_id: self.drag_id,
|
||||
output: Some(f(self.output)),
|
||||
}
|
||||
}
|
||||
|
||||
/// insert the contents of the new BodyResponse if they are empty in Self
|
||||
pub fn insert(&mut self, body: BodyResponse<R>) {
|
||||
self.drag_id = self.drag_id.or(body.drag_id);
|
||||
if self.output.is_none() {
|
||||
self.output = body.output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use = "RenderNavResponse must be handled by calling .process_render_nav_response(..)"]
|
||||
pub fn render_nav(
|
||||
col: usize,
|
||||
@@ -967,7 +1060,9 @@ pub fn render_nav(
|
||||
.show_move_button(!narrow)
|
||||
.show_delete_button(!narrow)
|
||||
.show(ui),
|
||||
NavUiType::Body => render_nav_body(ui, app, ctx, route, 1, col, inner_rect),
|
||||
NavUiType::Body => {
|
||||
render_nav_body(ui, app, ctx, route, 1, col, inner_rect).output
|
||||
}
|
||||
});
|
||||
|
||||
return RenderNavResponse::new(col, NotedeckNavResponse::Popup(Box::new(resp)));
|
||||
@@ -1047,8 +1142,9 @@ pub fn render_nav(
|
||||
if let Some(top) = nav.routes().last() {
|
||||
render_nav_body(ui, app, ctx, top, nav.routes().len(), col, inner_rect)
|
||||
} else {
|
||||
None
|
||||
BodyResponse::none()
|
||||
}
|
||||
.output
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
nav::RenderNavAction,
|
||||
nav::{BodyResponse, RenderNavAction},
|
||||
profile::ProfileAction,
|
||||
timeline::{thread::Threads, ThreadSelection, TimelineCache, TimelineKind},
|
||||
ui::{self, ProfileView},
|
||||
@@ -20,7 +20,7 @@ pub fn render_timeline_route(
|
||||
note_context: &mut NoteContext,
|
||||
jobs: &mut JobsCache,
|
||||
scroll_to_top: bool,
|
||||
) -> Option<RenderNavAction> {
|
||||
) -> BodyResponse<RenderNavAction> {
|
||||
match kind {
|
||||
TimelineKind::List(_)
|
||||
| TimelineKind::Search(_)
|
||||
@@ -29,11 +29,11 @@ pub fn render_timeline_route(
|
||||
| TimelineKind::Universe
|
||||
| TimelineKind::Hashtag(_)
|
||||
| TimelineKind::Generic(_) => {
|
||||
let note_action =
|
||||
let resp =
|
||||
ui::TimelineView::new(kind, timeline_cache, note_context, note_options, jobs, col)
|
||||
.ui(ui);
|
||||
|
||||
note_action.map(RenderNavAction::NoteAction)
|
||||
resp.map_output(RenderNavAction::NoteAction)
|
||||
}
|
||||
|
||||
TimelineKind::Profile(pubkey) => {
|
||||
@@ -49,7 +49,7 @@ pub fn render_timeline_route(
|
||||
)
|
||||
} else {
|
||||
// we render profiles like timelines if they are at the root
|
||||
let note_action = ui::TimelineView::new(
|
||||
let resp = ui::TimelineView::new(
|
||||
kind,
|
||||
timeline_cache,
|
||||
note_context,
|
||||
@@ -60,7 +60,7 @@ pub fn render_timeline_route(
|
||||
.scroll_to_top(scroll_to_top)
|
||||
.ui(ui);
|
||||
|
||||
note_action.map(RenderNavAction::NoteAction)
|
||||
resp.map_output(RenderNavAction::NoteAction)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ pub fn render_thread_route(
|
||||
ui: &mut egui::Ui,
|
||||
note_context: &mut NoteContext,
|
||||
jobs: &mut JobsCache,
|
||||
) -> Option<RenderNavAction> {
|
||||
) -> BodyResponse<RenderNavAction> {
|
||||
// don't truncate thread notes for now, since they are
|
||||
// default truncated everywher eelse
|
||||
note_options.set(NoteOptions::Truncate, false);
|
||||
@@ -92,7 +92,7 @@ pub fn render_thread_route(
|
||||
col,
|
||||
)
|
||||
.ui(ui)
|
||||
.map(Into::into)
|
||||
.map_output(RenderNavAction::NoteAction)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -104,7 +104,7 @@ pub fn render_profile_route(
|
||||
note_options: NoteOptions,
|
||||
note_context: &mut NoteContext,
|
||||
jobs: &mut JobsCache,
|
||||
) -> Option<RenderNavAction> {
|
||||
) -> BodyResponse<RenderNavAction> {
|
||||
let profile_view = ProfileView::new(
|
||||
pubkey,
|
||||
col,
|
||||
@@ -115,8 +115,7 @@ pub fn render_profile_route(
|
||||
)
|
||||
.ui(ui);
|
||||
|
||||
if let Some(action) = profile_view {
|
||||
match action {
|
||||
profile_view.map_output_maybe(|action| match action {
|
||||
ui::profile::ProfileViewAction::EditProfile => note_context
|
||||
.accounts
|
||||
.get_full(pubkey)
|
||||
@@ -124,14 +123,11 @@ pub fn render_profile_route(
|
||||
ui::profile::ProfileViewAction::Note(note_action) => {
|
||||
Some(RenderNavAction::NoteAction(note_action))
|
||||
}
|
||||
ui::profile::ProfileViewAction::Follow(target_key) => Some(
|
||||
RenderNavAction::ProfileAction(ProfileAction::Follow(target_key)),
|
||||
),
|
||||
ui::profile::ProfileViewAction::Follow(target_key) => Some(RenderNavAction::ProfileAction(
|
||||
ProfileAction::Follow(target_key),
|
||||
)),
|
||||
ui::profile::ProfileViewAction::Unfollow(target_key) => Some(
|
||||
RenderNavAction::ProfileAction(ProfileAction::Unfollow(target_key)),
|
||||
),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ use notedeck_ui::profile::preview::SimpleProfilePreview;
|
||||
|
||||
use notedeck_ui::app_images;
|
||||
|
||||
use crate::nav::BodyResponse;
|
||||
|
||||
pub struct AccountsView<'a> {
|
||||
ndb: &'a Ndb,
|
||||
accounts: &'a Accounts,
|
||||
@@ -44,20 +46,26 @@ impl<'a> AccountsView<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut Ui) -> InnerResponse<Option<AccountsViewResponse>> {
|
||||
pub fn ui(&mut self, ui: &mut Ui) -> BodyResponse<AccountsViewResponse> {
|
||||
let mut out = BodyResponse::none();
|
||||
Frame::new().outer_margin(12.0).show(ui, |ui| {
|
||||
if let Some(resp) = Self::top_section_buttons_widget(ui, self.i18n).inner {
|
||||
return Some(resp);
|
||||
out.set_output(resp);
|
||||
}
|
||||
|
||||
ui.add_space(8.0);
|
||||
scroll_area()
|
||||
let scroll_out = scroll_area()
|
||||
.id_salt(AccountsView::scroll_id())
|
||||
.show(ui, |ui| {
|
||||
Self::show_accounts(ui, self.accounts, self.ndb, self.img_cache, self.i18n)
|
||||
})
|
||||
.inner
|
||||
})
|
||||
});
|
||||
|
||||
out.set_scroll_id(&scroll_out);
|
||||
if let Some(scroll_output) = scroll_out.inner {
|
||||
out.set_output(scroll_output);
|
||||
}
|
||||
});
|
||||
out
|
||||
}
|
||||
|
||||
pub fn scroll_id() -> egui::Id {
|
||||
|
||||
@@ -11,6 +11,8 @@ use notedeck_ui::{
|
||||
};
|
||||
use tracing::error;
|
||||
|
||||
use crate::nav::BodyResponse;
|
||||
|
||||
/// Displays user profiles for the user to pick from.
|
||||
/// Useful for manually typing a username and selecting the profile desired
|
||||
pub struct MentionPickerView<'a> {
|
||||
@@ -64,7 +66,11 @@ impl<'a> MentionPickerView<'a> {
|
||||
MentionPickerResponse::SelectResult(selection)
|
||||
}
|
||||
|
||||
pub fn show_in_rect(&mut self, rect: egui::Rect, ui: &mut egui::Ui) -> MentionPickerResponse {
|
||||
pub fn show_in_rect(
|
||||
&mut self,
|
||||
rect: egui::Rect,
|
||||
ui: &mut egui::Ui,
|
||||
) -> BodyResponse<MentionPickerResponse> {
|
||||
let widget_id = ui.id().with("mention_results");
|
||||
let area_resp = egui::Area::new(widget_id)
|
||||
.order(egui::Order::Foreground)
|
||||
@@ -102,15 +108,17 @@ impl<'a> MentionPickerView<'a> {
|
||||
let scroll_resp = ScrollArea::vertical()
|
||||
.max_width(rect.width())
|
||||
.auto_shrink(Vec2b::FALSE)
|
||||
.show(ui, |ui| self.show(ui, width));
|
||||
.show(ui, |ui| Some(self.show(ui, width)));
|
||||
ui.advance_cursor_after_rect(rect);
|
||||
|
||||
BodyResponse::scroll(scroll_resp).map_output(|o| {
|
||||
if close_button_resp {
|
||||
MentionPickerResponse::DeleteMention
|
||||
} else {
|
||||
scroll_resp.inner
|
||||
o
|
||||
}
|
||||
})
|
||||
})
|
||||
.inner
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::draft::{Draft, Drafts, MentionHint};
|
||||
use crate::media_upload::nostrbuild_nip96_upload;
|
||||
use crate::nav::BodyResponse;
|
||||
use crate::post::{downcast_post_buffer, MentionType, NewPost};
|
||||
use crate::ui::mentions_picker::MentionPickerView;
|
||||
use crate::ui::{self, Preview, PreviewConfig};
|
||||
@@ -143,7 +144,7 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
self
|
||||
}
|
||||
|
||||
fn editbox(&mut self, txn: &nostrdb::Transaction, ui: &mut egui::Ui) -> egui::Response {
|
||||
fn editbox(&mut self, txn: &nostrdb::Transaction, ui: &mut egui::Ui) -> EditBoxResponse {
|
||||
ui.spacing_mut().item_spacing.x = 12.0;
|
||||
|
||||
let pfp_size = 24.0;
|
||||
@@ -221,37 +222,42 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
self.draft.buffer.selected_mention = false;
|
||||
}
|
||||
|
||||
let mention_hints_drag_id =
|
||||
if let Some(cursor_index) = get_cursor_index(&out.state.cursor.char_range()) {
|
||||
self.show_mention_hints(txn, ui, cursor_index, &out);
|
||||
}
|
||||
self.show_mention_hints(txn, ui, cursor_index, &out)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let focused = out.response.has_focus();
|
||||
|
||||
ui.ctx()
|
||||
.data_mut(|d| d.insert_temp(PostView::id(), focused));
|
||||
|
||||
out.response
|
||||
EditBoxResponse {
|
||||
resp: out.response,
|
||||
mention_hints_drag_id,
|
||||
}
|
||||
}
|
||||
|
||||
// Displays the mention picker and handles when one is selected.
|
||||
// returns the drag id of the mention hint widget
|
||||
fn show_mention_hints(
|
||||
&mut self,
|
||||
txn: &nostrdb::Transaction,
|
||||
ui: &mut egui::Ui,
|
||||
cursor_index: usize,
|
||||
textedit_output: &TextEditOutput,
|
||||
) {
|
||||
let Some(mention) = self.draft.buffer.get_mention(cursor_index) else {
|
||||
return;
|
||||
};
|
||||
) -> Option<egui::Id> {
|
||||
let mention = self.draft.buffer.get_mention(cursor_index)?;
|
||||
|
||||
if mention.info.mention_type != MentionType::Pending {
|
||||
return;
|
||||
return None;
|
||||
}
|
||||
|
||||
if ui.ctx().input(|r| r.key_pressed(egui::Key::Escape)) {
|
||||
self.draft.buffer.delete_mention(mention.index);
|
||||
return;
|
||||
return None;
|
||||
}
|
||||
|
||||
let mention_str = self.draft.buffer.get_mention_string(&mention);
|
||||
@@ -274,10 +280,8 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
}
|
||||
|
||||
let hint_rect = {
|
||||
let hint = if let Some(hint) = &self.draft.cur_mention_hint {
|
||||
hint
|
||||
} else {
|
||||
return;
|
||||
let Some(hint) = &self.draft.cur_mention_hint else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut hint_rect = self.inner_rect;
|
||||
@@ -285,9 +289,11 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
hint_rect
|
||||
};
|
||||
|
||||
let Ok(res) = self.note_context.ndb.search_profile(txn, mention_str, 10) else {
|
||||
return;
|
||||
};
|
||||
let res = self
|
||||
.note_context
|
||||
.ndb
|
||||
.search_profile(txn, mention_str, 10)
|
||||
.ok()?;
|
||||
|
||||
let resp = MentionPickerView::new(
|
||||
self.note_context.img_cache,
|
||||
@@ -298,7 +304,12 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
.show_in_rect(hint_rect, ui);
|
||||
|
||||
let mut selection_made = None;
|
||||
match resp {
|
||||
|
||||
let Some(out) = resp.output else {
|
||||
return resp.drag_id;
|
||||
};
|
||||
|
||||
match out {
|
||||
ui::mentions_picker::MentionPickerResponse::SelectResult(selection) => {
|
||||
if let Some(hint_index) = selection {
|
||||
if let Some(pk) = res.get(hint_index) {
|
||||
@@ -326,6 +337,8 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
if let Some(selection) = selection_made {
|
||||
selection.process(ui.ctx(), textedit_output);
|
||||
}
|
||||
|
||||
resp.drag_id
|
||||
}
|
||||
|
||||
fn focused(&self, ui: &egui::Ui) -> bool {
|
||||
@@ -341,14 +354,25 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
12
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, txn: &Transaction, ui: &mut egui::Ui) -> PostResponse {
|
||||
ScrollArea::vertical()
|
||||
pub fn ui(&mut self, txn: &Transaction, ui: &mut egui::Ui) -> BodyResponse<PostResponse> {
|
||||
let scroll_out = ScrollArea::vertical()
|
||||
.id_salt(PostView::scroll_id())
|
||||
.show(ui, |ui| self.ui_no_scroll(txn, ui))
|
||||
.inner
|
||||
.show(ui, |ui| Some(self.ui_no_scroll(txn, ui)));
|
||||
|
||||
let scroll_id = scroll_out.id;
|
||||
if let Some(inner) = scroll_out.inner {
|
||||
inner // should override the PostView scroll for the mention scroll
|
||||
} else {
|
||||
BodyResponse::none()
|
||||
}
|
||||
.scroll_raw(scroll_id)
|
||||
}
|
||||
|
||||
pub fn ui_no_scroll(&mut self, txn: &Transaction, ui: &mut egui::Ui) -> PostResponse {
|
||||
pub fn ui_no_scroll(
|
||||
&mut self,
|
||||
txn: &Transaction,
|
||||
ui: &mut egui::Ui,
|
||||
) -> BodyResponse<PostResponse> {
|
||||
while let Some(selected_file) = get_next_selected_file() {
|
||||
match selected_file {
|
||||
Ok(selected_media) => {
|
||||
@@ -393,7 +417,7 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
.inner
|
||||
}
|
||||
|
||||
fn input_ui(&mut self, txn: &Transaction, ui: &mut egui::Ui) -> PostResponse {
|
||||
fn input_ui(&mut self, txn: &Transaction, ui: &mut egui::Ui) -> BodyResponse<PostResponse> {
|
||||
let edit_response = ui.horizontal(|ui| self.editbox(txn, ui)).inner;
|
||||
|
||||
let note_response = if let PostType::Quote(id) = self.post_type {
|
||||
@@ -445,10 +469,14 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
.and_then(|nr| nr.action.map(PostAction::QuotedNoteAction))
|
||||
.or(post_action.map(PostAction::NewPostAction));
|
||||
|
||||
PostResponse {
|
||||
action,
|
||||
edit_response,
|
||||
let mut resp = BodyResponse::output(action);
|
||||
if let Some(drag_id) = edit_response.mention_hints_drag_id {
|
||||
resp.set_drag_id_raw(drag_id);
|
||||
}
|
||||
resp.maybe_map_output(|action| PostResponse {
|
||||
action,
|
||||
edit_response: edit_response.resp,
|
||||
})
|
||||
}
|
||||
|
||||
fn input_buttons(&mut self, ui: &mut egui::Ui) -> Option<NewPostAction> {
|
||||
@@ -596,6 +624,11 @@ impl<'a, 'd> PostView<'a, 'd> {
|
||||
}
|
||||
}
|
||||
|
||||
struct EditBoxResponse {
|
||||
resp: egui::Response,
|
||||
mention_hints_drag_id: Option<egui::Id>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn render_post_view_media(
|
||||
ui: &mut egui::Ui,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::{PostResponse, PostType};
|
||||
use crate::{
|
||||
draft::Draft,
|
||||
nav::BodyResponse,
|
||||
ui::{self},
|
||||
};
|
||||
|
||||
@@ -52,14 +53,22 @@ impl<'a, 'd> QuoteRepostView<'a, 'd> {
|
||||
QuoteRepostView::id(col, note_id).with("scroll")
|
||||
}
|
||||
|
||||
pub fn show(&mut self, ui: &mut egui::Ui) -> PostResponse {
|
||||
ScrollArea::vertical()
|
||||
pub fn show(&mut self, ui: &mut egui::Ui) -> BodyResponse<PostResponse> {
|
||||
let scroll_out = ScrollArea::vertical()
|
||||
.id_salt(self.scroll_id)
|
||||
.show(ui, |ui| self.show_internal(ui))
|
||||
.inner
|
||||
.show(ui, |ui| Some(self.show_internal(ui)));
|
||||
|
||||
let scroll_id = scroll_out.id;
|
||||
|
||||
if let Some(inner) = scroll_out.inner {
|
||||
inner
|
||||
} else {
|
||||
BodyResponse::none()
|
||||
}
|
||||
.scroll_raw(scroll_id)
|
||||
}
|
||||
|
||||
fn show_internal(&mut self, ui: &mut egui::Ui) -> PostResponse {
|
||||
fn show_internal(&mut self, ui: &mut egui::Ui) -> BodyResponse<PostResponse> {
|
||||
let quoting_note_id = self.quoting_note.id();
|
||||
|
||||
let post_resp = ui::PostView::new(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::draft::Draft;
|
||||
use crate::nav::BodyResponse;
|
||||
use crate::ui::{
|
||||
self,
|
||||
note::{PostAction, PostResponse, PostType},
|
||||
@@ -52,16 +53,23 @@ impl<'a, 'd> PostReplyView<'a, 'd> {
|
||||
PostReplyView::id(col, note_id).with("scroll")
|
||||
}
|
||||
|
||||
pub fn show(&mut self, ui: &mut egui::Ui) -> PostResponse {
|
||||
ScrollArea::vertical()
|
||||
pub fn show(&mut self, ui: &mut egui::Ui) -> BodyResponse<PostResponse> {
|
||||
let scroll_out = ScrollArea::vertical()
|
||||
.id_salt(self.scroll_id)
|
||||
.stick_to_bottom(true)
|
||||
.show(ui, |ui| self.show_internal(ui))
|
||||
.inner
|
||||
.show(ui, |ui| Some(self.show_internal(ui)));
|
||||
|
||||
let scroll_id = scroll_out.id;
|
||||
if let Some(inner) = scroll_out.inner {
|
||||
inner
|
||||
} else {
|
||||
BodyResponse::none()
|
||||
}
|
||||
.scroll_raw(scroll_id)
|
||||
}
|
||||
|
||||
// no scroll
|
||||
fn show_internal(&mut self, ui: &mut egui::Ui) -> PostResponse {
|
||||
fn show_internal(&mut self, ui: &mut egui::Ui) -> BodyResponse<PostResponse> {
|
||||
ui.vertical(|ui| {
|
||||
let avail_rect = ui.available_rect_before_wrap();
|
||||
|
||||
@@ -103,17 +111,22 @@ impl<'a, 'd> PostReplyView<'a, 'd> {
|
||||
.ui_no_scroll(self.note.txn().unwrap(), ui)
|
||||
};
|
||||
|
||||
post_response.action = post_response
|
||||
post_response = post_response.map_output(|mut o| {
|
||||
o.action = o
|
||||
.action
|
||||
.or(quoted_note.action.map(PostAction::QuotedNoteAction));
|
||||
o
|
||||
});
|
||||
|
||||
if let Some(p) = &post_response.output {
|
||||
reply_line_ui(
|
||||
&rect_before_post,
|
||||
&post_response.edit_response,
|
||||
&p.edit_response,
|
||||
pfp_offset as f32,
|
||||
&avail_rect,
|
||||
ui,
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// NOTE(jb55): We add some space so that you can scroll to
|
||||
|
||||
@@ -8,7 +8,7 @@ use notedeck_ui::{
|
||||
nip51_set::{Nip51SetUiCache, Nip51SetWidget, Nip51SetWidgetAction, Nip51SetWidgetFlags},
|
||||
};
|
||||
|
||||
use crate::{onboarding::Onboarding, ui::widgets::styled_button};
|
||||
use crate::{nav::BodyResponse, onboarding::Onboarding, ui::widgets::styled_button};
|
||||
|
||||
/// Display Follow Packs for the user to choose from authors trusted by the Damus team
|
||||
pub struct FollowPackOnboardingView<'a> {
|
||||
@@ -56,17 +56,17 @@ impl<'a> FollowPackOnboardingView<'a> {
|
||||
egui::Id::new("follow_pack_onboarding")
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<OnboardingResponse> {
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> BodyResponse<OnboardingResponse> {
|
||||
let Some(follow_pack_state) = self.onboarding.get_follow_packs() else {
|
||||
return Some(OnboardingResponse::FollowPacks(
|
||||
return BodyResponse::output(Some(OnboardingResponse::FollowPacks(
|
||||
FollowPacksResponse::NoFollowPacks,
|
||||
));
|
||||
)));
|
||||
};
|
||||
|
||||
let max_height = ui.available_height() - 48.0;
|
||||
|
||||
let mut action = None;
|
||||
ScrollArea::vertical()
|
||||
let scroll_out = ScrollArea::vertical()
|
||||
.id_salt(Self::scroll_id())
|
||||
.max_height(max_height)
|
||||
.show(ui, |ui| {
|
||||
@@ -114,6 +114,6 @@ impl<'a> FollowPackOnboardingView<'a> {
|
||||
}
|
||||
});
|
||||
|
||||
action
|
||||
BodyResponse::output(action).scroll_raw(scroll_out.id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ use notedeck::{profile::unwrap_profile_url, tr, Images, Localization, NotedeckTe
|
||||
use notedeck_ui::context_menu::{input_context, PasteBehavior};
|
||||
use notedeck_ui::{profile::banner, ProfilePic};
|
||||
|
||||
use crate::nav::BodyResponse;
|
||||
|
||||
pub struct EditProfileView<'a> {
|
||||
state: &'a mut ProfileState,
|
||||
clipboard: &'a mut Clipboard,
|
||||
@@ -34,8 +36,8 @@ impl<'a> EditProfileView<'a> {
|
||||
}
|
||||
|
||||
// return true to save
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> bool {
|
||||
ScrollArea::vertical()
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> BodyResponse<bool> {
|
||||
let scroll_out = ScrollArea::vertical()
|
||||
.id_salt(EditProfileView::scroll_id())
|
||||
.stick_to_bottom(true)
|
||||
.show(ui, |ui| {
|
||||
@@ -71,9 +73,9 @@ impl<'a> EditProfileView<'a> {
|
||||
});
|
||||
});
|
||||
|
||||
save
|
||||
})
|
||||
.inner
|
||||
Some(save)
|
||||
});
|
||||
BodyResponse::scroll(scroll_out)
|
||||
}
|
||||
|
||||
fn inner(&mut self, ui: &mut egui::Ui, padding: f32) {
|
||||
|
||||
@@ -10,6 +10,7 @@ use robius_open::Uri;
|
||||
use tracing::error;
|
||||
|
||||
use crate::{
|
||||
nav::BodyResponse,
|
||||
timeline::{TimelineCache, TimelineKind},
|
||||
ui::timeline::{tabs_ui, TimelineTabView},
|
||||
};
|
||||
@@ -68,13 +69,16 @@ impl<'a, 'd> ProfileView<'a, 'd> {
|
||||
egui::Id::new(("profile_scroll", col_id, profile_pubkey))
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<ProfileViewAction> {
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> BodyResponse<ProfileViewAction> {
|
||||
let scroll_id = ProfileView::scroll_id(self.col_id, self.pubkey);
|
||||
let scroll_area = ScrollArea::vertical().id_salt(scroll_id).animated(false);
|
||||
|
||||
let profile_timeline = self
|
||||
let Some(profile_timeline) = self
|
||||
.timeline_cache
|
||||
.get_mut(&TimelineKind::Profile(*self.pubkey))?;
|
||||
.get_mut(&TimelineKind::Profile(*self.pubkey))
|
||||
else {
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
let output = scroll_area.show(ui, |ui| {
|
||||
let mut action = None;
|
||||
@@ -132,7 +136,7 @@ impl<'a, 'd> ProfileView<'a, 'd> {
|
||||
// only allow front insert when the profile body is fully obstructed
|
||||
profile_timeline.enable_front_insert = output.inner.body_end_pos < ui.clip_rect().top();
|
||||
|
||||
output.inner.action
|
||||
BodyResponse::output(output.inner.action).scroll_raw(output.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::nav::BodyResponse;
|
||||
use crate::ui::{Preview, PreviewConfig};
|
||||
use egui::{Align, Button, CornerRadius, Frame, Id, Layout, Margin, Rgba, RichText, Ui, Vec2};
|
||||
use enostr::{RelayPool, RelayStatus};
|
||||
@@ -17,9 +18,8 @@ pub struct RelayView<'a> {
|
||||
}
|
||||
|
||||
impl RelayView<'_> {
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<RelayAction> {
|
||||
let mut action = None;
|
||||
Frame::new()
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> BodyResponse<RelayAction> {
|
||||
let scroll_out = Frame::new()
|
||||
.inner_margin(Margin::symmetric(10, 0))
|
||||
.show(ui, |ui| {
|
||||
ui.add_space(24.0);
|
||||
@@ -40,6 +40,7 @@ impl RelayView<'_> {
|
||||
.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden)
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
let mut action = None;
|
||||
if let Some(relay_to_remove) = self.show_relays(ui) {
|
||||
action = Some(RelayAction::Remove(relay_to_remove));
|
||||
}
|
||||
@@ -47,10 +48,12 @@ impl RelayView<'_> {
|
||||
if let Some(relay_to_add) = self.show_add_relay_ui(ui) {
|
||||
action = Some(RelayAction::Add(relay_to_add));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
action
|
||||
})
|
||||
})
|
||||
.inner;
|
||||
|
||||
BodyResponse::scroll(scroll_out)
|
||||
}
|
||||
|
||||
pub fn scroll_id() -> egui::Id {
|
||||
|
||||
@@ -3,6 +3,7 @@ use enostr::{NoteId, Pubkey};
|
||||
use state::TypingType;
|
||||
|
||||
use crate::{
|
||||
nav::BodyResponse,
|
||||
timeline::{TimelineTab, TimelineUnits},
|
||||
ui::timeline::TimelineTabView,
|
||||
};
|
||||
@@ -49,11 +50,11 @@ impl<'a, 'd> SearchView<'a, 'd> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
|
||||
pub fn show(&mut self, ui: &mut egui::Ui) -> BodyResponse<NoteAction> {
|
||||
padding(8.0, ui, |ui| self.show_impl(ui)).inner
|
||||
}
|
||||
|
||||
pub fn show_impl(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
|
||||
pub fn show_impl(&mut self, ui: &mut egui::Ui) -> BodyResponse<NoteAction> {
|
||||
ui.spacing_mut().item_spacing = egui::vec2(0.0, 12.0);
|
||||
|
||||
let search_resp = search_box(
|
||||
@@ -67,7 +68,7 @@ impl<'a, 'd> SearchView<'a, 'd> {
|
||||
search_resp.process(self.query);
|
||||
|
||||
let mut search_action = None;
|
||||
let mut note_action = None;
|
||||
let mut body_resp = BodyResponse::none();
|
||||
match &self.query.state {
|
||||
SearchState::New | SearchState::Navigating => {}
|
||||
SearchState::Typing(TypingType::Mention(mention_name)) => 's: {
|
||||
@@ -87,7 +88,11 @@ impl<'a, 'd> SearchView<'a, 'd> {
|
||||
)
|
||||
.show_in_rect(ui.available_rect_before_wrap(), ui);
|
||||
|
||||
search_action = match search_res {
|
||||
let Some(res) = search_res.output else {
|
||||
break 's;
|
||||
};
|
||||
|
||||
search_action = match res {
|
||||
MentionPickerResponse::SelectResult(Some(index)) => {
|
||||
let Some(pk_bytes) = results.get(index) else {
|
||||
break 's;
|
||||
@@ -120,7 +125,7 @@ impl<'a, 'd> SearchView<'a, 'd> {
|
||||
&mut self.query.notes,
|
||||
);
|
||||
search_action = Some(SearchAction::Searched);
|
||||
note_action = self.show_search_results(ui);
|
||||
body_resp.insert(self.show_search_results(ui));
|
||||
}
|
||||
SearchState::Searched => {
|
||||
ui.label(tr_plural!(
|
||||
@@ -131,7 +136,7 @@ impl<'a, 'd> SearchView<'a, 'd> {
|
||||
self.query.notes.units.len(), // count
|
||||
query = &self.query.string
|
||||
));
|
||||
note_action = self.show_search_results(ui);
|
||||
body_resp.insert(self.show_search_results(ui));
|
||||
}
|
||||
SearchState::Typing(TypingType::AutoSearch) => {
|
||||
ui.label(tr!(
|
||||
@@ -141,7 +146,7 @@ impl<'a, 'd> SearchView<'a, 'd> {
|
||||
query = &self.query.string
|
||||
));
|
||||
|
||||
note_action = self.show_search_results(ui);
|
||||
body_resp.insert(self.show_search_results(ui));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -149,11 +154,11 @@ impl<'a, 'd> SearchView<'a, 'd> {
|
||||
resp.process(self.query);
|
||||
}
|
||||
|
||||
note_action
|
||||
body_resp
|
||||
}
|
||||
|
||||
fn show_search_results(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
|
||||
egui::ScrollArea::vertical()
|
||||
fn show_search_results(&mut self, ui: &mut egui::Ui) -> BodyResponse<NoteAction> {
|
||||
let scroll_out = egui::ScrollArea::vertical()
|
||||
.id_salt(SearchView::scroll_id())
|
||||
.show(ui, |ui| {
|
||||
TimelineTabView::new(
|
||||
@@ -164,8 +169,9 @@ impl<'a, 'd> SearchView<'a, 'd> {
|
||||
self.jobs,
|
||||
)
|
||||
.show(ui)
|
||||
})
|
||||
.inner
|
||||
});
|
||||
|
||||
BodyResponse::scroll(scroll_out)
|
||||
}
|
||||
|
||||
pub fn scroll_id() -> egui::Id {
|
||||
|
||||
@@ -16,7 +16,11 @@ use notedeck_ui::{
|
||||
AnimationHelper, NoteOptions, NoteView,
|
||||
};
|
||||
|
||||
use crate::{nav::RouterAction, ui::account_login_view::eye_button, Damus, Route};
|
||||
use crate::{
|
||||
nav::{BodyResponse, RouterAction},
|
||||
ui::account_login_view::eye_button,
|
||||
Damus, Route,
|
||||
};
|
||||
|
||||
const PREVIEW_NOTE_ID: &str = "note1edjc8ggj07hwv77g2405uh6j2jkk5aud22gktxrvc2wnre4vdwgqzlv2gw";
|
||||
|
||||
@@ -638,13 +642,12 @@ impl<'a> SettingsView<'a> {
|
||||
action
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<SettingsAction> {
|
||||
let mut action: Option<SettingsAction> = None;
|
||||
|
||||
Frame::default()
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> BodyResponse<SettingsAction> {
|
||||
let scroll_out = Frame::default()
|
||||
.inner_margin(Margin::symmetric(10, 10))
|
||||
.show(ui, |ui| {
|
||||
ScrollArea::vertical().show(ui, |ui| {
|
||||
let mut action = None;
|
||||
if let Some(new_action) = self.appearance_section(ui) {
|
||||
action = Some(new_action);
|
||||
}
|
||||
@@ -670,10 +673,12 @@ impl<'a> SettingsView<'a> {
|
||||
if let Some(new_action) = self.manage_relays_section(ui) {
|
||||
action = Some(new_action);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
action
|
||||
})
|
||||
})
|
||||
.inner;
|
||||
|
||||
BodyResponse::scroll(scroll_out)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use notedeck::{NoteAction, NoteContext};
|
||||
use notedeck_ui::note::NoteResponse;
|
||||
use notedeck_ui::{NoteOptions, NoteView};
|
||||
|
||||
use crate::nav::BodyResponse;
|
||||
use crate::timeline::thread::{NoteSeenFlags, ParentState, Threads};
|
||||
|
||||
pub struct ThreadView<'a, 'd> {
|
||||
@@ -42,7 +43,7 @@ impl<'a, 'd> ThreadView<'a, 'd> {
|
||||
egui::Id::new(("threadscroll", selected_note_id, col))
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> BodyResponse<NoteAction> {
|
||||
let txn = Transaction::new(self.note_context.ndb).expect("txn");
|
||||
|
||||
let scroll_id = ThreadView::scroll_id(self.selected_note_id, self.col);
|
||||
@@ -60,6 +61,7 @@ impl<'a, 'd> ThreadView<'a, 'd> {
|
||||
|
||||
let output = scroll_area.show(ui, |ui| self.notes(ui, &txn));
|
||||
|
||||
let out_id = output.id;
|
||||
let mut resp = output.inner;
|
||||
|
||||
if let Some(NoteAction::Note {
|
||||
@@ -71,7 +73,7 @@ impl<'a, 'd> ThreadView<'a, 'd> {
|
||||
*scroll_offset = output.state.offset.y;
|
||||
}
|
||||
|
||||
resp
|
||||
BodyResponse::output(resp).scroll_raw(out_id)
|
||||
}
|
||||
|
||||
fn notes(&mut self, ui: &mut egui::Ui, txn: &Transaction) -> Option<NoteAction> {
|
||||
|
||||
@@ -12,6 +12,7 @@ use notedeck_ui::{ProfilePic, ProfilePreview};
|
||||
use std::f32::consts::PI;
|
||||
use tracing::{error, warn};
|
||||
|
||||
use crate::nav::BodyResponse;
|
||||
use crate::timeline::{
|
||||
CompositeType, CompositeUnit, NoteUnit, ReactionUnit, RepostUnit, TimelineCache, TimelineKind,
|
||||
TimelineTab, ViewFilter,
|
||||
@@ -56,7 +57,7 @@ impl<'a, 'd> TimelineView<'a, 'd> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> BodyResponse<NoteAction> {
|
||||
timeline_ui(
|
||||
ui,
|
||||
self.timeline_id,
|
||||
@@ -94,7 +95,7 @@ fn timeline_ui(
|
||||
jobs: &mut JobsCache,
|
||||
col: usize,
|
||||
scroll_to_top: bool,
|
||||
) -> Option<NoteAction> {
|
||||
) -> BodyResponse<NoteAction> {
|
||||
//padding(4.0, ui, |ui| ui.heading("Notifications"));
|
||||
/*
|
||||
let font_id = egui::TextStyle::Body.resolve(ui.style());
|
||||
@@ -102,7 +103,9 @@ fn timeline_ui(
|
||||
|
||||
*/
|
||||
|
||||
let scroll_id = TimelineView::scroll_id(timeline_cache, timeline_id, col)?;
|
||||
let Some(scroll_id) = TimelineView::scroll_id(timeline_cache, timeline_id, col) else {
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
{
|
||||
let timeline = if let Some(timeline) = timeline_cache.get_mut(timeline_id) {
|
||||
@@ -111,7 +114,7 @@ fn timeline_ui(
|
||||
error!("tried to render timeline in column, but timeline was missing");
|
||||
// TODO (jb55): render error when timeline is missing?
|
||||
// this shouldn't happen...
|
||||
return None;
|
||||
return BodyResponse::none();
|
||||
};
|
||||
|
||||
timeline.selected_view = tabs_ui(
|
||||
@@ -204,7 +207,9 @@ fn timeline_ui(
|
||||
.data_mut(|d| d.insert_temp(show_top_button_id, true));
|
||||
}
|
||||
|
||||
scroll_output.inner.or_else(|| {
|
||||
let scroll_id = scroll_output.id;
|
||||
|
||||
let action = scroll_output.inner.or_else(|| {
|
||||
// if we're scrolling, return that as a response. We need this
|
||||
// for auto-closing the side menu
|
||||
|
||||
@@ -215,7 +220,9 @@ fn timeline_ui(
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
BodyResponse::output(action).scroll_raw(scroll_id)
|
||||
}
|
||||
|
||||
fn goto_top_button(center: Pos2) -> impl egui::Widget {
|
||||
|
||||
Reference in New Issue
Block a user