Flexible routing
Another massive refactor to change the way routing works. Now any column can route anywhere. Also things are generally just much better and more modular via the new struct split borrowing technique. I didn't even try to split this into smaller commits for my sanity. Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -2,6 +2,7 @@ use crate::colors::PINK;
|
||||
use crate::imgcache::ImageCache;
|
||||
use crate::{
|
||||
account_manager::AccountManager,
|
||||
route::{Route, Router},
|
||||
ui::{Preview, PreviewConfig, View},
|
||||
Damus,
|
||||
};
|
||||
@@ -12,22 +13,29 @@ use super::profile::preview::SimpleProfilePreview;
|
||||
use super::profile::ProfilePreviewOp;
|
||||
use super::profile_preview_controller::profile_preview_view;
|
||||
|
||||
pub struct AccountManagementView {}
|
||||
pub struct AccountsView<'a> {
|
||||
ndb: &'a Ndb,
|
||||
accounts: &'a AccountManager,
|
||||
img_cache: &'a mut ImageCache,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AccountManagementViewResponse {
|
||||
pub enum AccountsViewResponse {
|
||||
SelectAccount(usize),
|
||||
RemoveAccount(usize),
|
||||
RouteToLogin,
|
||||
}
|
||||
|
||||
impl AccountManagementView {
|
||||
pub fn ui(
|
||||
ui: &mut Ui,
|
||||
account_manager: &AccountManager,
|
||||
ndb: &Ndb,
|
||||
img_cache: &mut ImageCache,
|
||||
) -> InnerResponse<Option<AccountManagementViewResponse>> {
|
||||
impl<'a> AccountsView<'a> {
|
||||
pub fn new(ndb: &'a Ndb, accounts: &'a AccountManager, img_cache: &'a mut ImageCache) -> Self {
|
||||
AccountsView {
|
||||
ndb,
|
||||
accounts,
|
||||
img_cache,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut Ui) -> InnerResponse<Option<AccountsViewResponse>> {
|
||||
Frame::none().outer_margin(12.0).show(ui, |ui| {
|
||||
if let Some(resp) = Self::top_section_buttons_widget(ui).inner {
|
||||
return Some(resp);
|
||||
@@ -36,7 +44,7 @@ impl AccountManagementView {
|
||||
ui.add_space(8.0);
|
||||
scroll_area()
|
||||
.show(ui, |ui| {
|
||||
Self::show_accounts(ui, account_manager, ndb, img_cache)
|
||||
Self::show_accounts(ui, self.accounts, self.ndb, self.img_cache)
|
||||
})
|
||||
.inner
|
||||
})
|
||||
@@ -47,8 +55,8 @@ impl AccountManagementView {
|
||||
account_manager: &AccountManager,
|
||||
ndb: &Ndb,
|
||||
img_cache: &mut ImageCache,
|
||||
) -> Option<AccountManagementViewResponse> {
|
||||
let mut return_op: Option<AccountManagementViewResponse> = None;
|
||||
) -> Option<AccountsViewResponse> {
|
||||
let mut return_op: Option<AccountsViewResponse> = None;
|
||||
ui.allocate_ui_with_layout(
|
||||
Vec2::new(ui.available_size_before_wrap().x, 32.0),
|
||||
Layout::top_down(egui::Align::Min),
|
||||
@@ -82,11 +90,9 @@ impl AccountManagementView {
|
||||
profile_preview_view(ui, profile.as_ref(), img_cache, is_selected)
|
||||
{
|
||||
return_op = Some(match op {
|
||||
ProfilePreviewOp::SwitchTo => {
|
||||
AccountManagementViewResponse::SelectAccount(i)
|
||||
}
|
||||
ProfilePreviewOp::SwitchTo => AccountsViewResponse::SelectAccount(i),
|
||||
ProfilePreviewOp::RemoveAccount => {
|
||||
AccountManagementViewResponse::RemoveAccount(i)
|
||||
AccountsViewResponse::RemoveAccount(i)
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -98,21 +104,18 @@ impl AccountManagementView {
|
||||
|
||||
fn top_section_buttons_widget(
|
||||
ui: &mut egui::Ui,
|
||||
) -> InnerResponse<Option<AccountManagementViewResponse>> {
|
||||
ui.horizontal(|ui| {
|
||||
ui.allocate_ui_with_layout(
|
||||
Vec2::new(ui.available_size_before_wrap().x, 32.0),
|
||||
Layout::left_to_right(egui::Align::Center),
|
||||
|ui| {
|
||||
if ui.add(add_account_button()).clicked() {
|
||||
Some(AccountManagementViewResponse::RouteToLogin)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.inner
|
||||
})
|
||||
) -> InnerResponse<Option<AccountsViewResponse>> {
|
||||
ui.allocate_ui_with_layout(
|
||||
Vec2::new(ui.available_size_before_wrap().x, 32.0),
|
||||
Layout::left_to_right(egui::Align::Center),
|
||||
|ui| {
|
||||
if ui.add(add_account_button()).clicked() {
|
||||
Some(AccountsViewResponse::RouteToLogin)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,41 +209,41 @@ fn selected_widget() -> impl egui::Widget {
|
||||
mod preview {
|
||||
|
||||
use super::*;
|
||||
use crate::{account_manager::process_management_view_response_stateless, test_data};
|
||||
use crate::{account_manager::process_accounts_view_response, test_data};
|
||||
|
||||
pub struct AccountManagementPreview {
|
||||
pub struct AccountsPreview {
|
||||
app: Damus,
|
||||
router: Router<Route>,
|
||||
}
|
||||
|
||||
impl AccountManagementPreview {
|
||||
impl AccountsPreview {
|
||||
fn new() -> Self {
|
||||
let app = test_data::test_app();
|
||||
let router = Router::new(vec![Route::accounts()]);
|
||||
|
||||
AccountManagementPreview { app }
|
||||
AccountsPreview { app, router }
|
||||
}
|
||||
}
|
||||
|
||||
impl View for AccountManagementPreview {
|
||||
impl View for AccountsPreview {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
ui.add_space(24.0);
|
||||
if let Some(response) = AccountManagementView::ui(
|
||||
ui,
|
||||
&self.app.accounts,
|
||||
&self.app.ndb,
|
||||
&mut self.app.img_cache,
|
||||
)
|
||||
.inner
|
||||
// TODO(jb55): maybe just use render_nav here so we can step through routes
|
||||
if let Some(response) =
|
||||
AccountsView::new(&self.app.ndb, &self.app.accounts, &mut self.app.img_cache)
|
||||
.ui(ui)
|
||||
.inner
|
||||
{
|
||||
process_management_view_response_stateless(&mut self.app.accounts, response)
|
||||
process_accounts_view_response(self.app.accounts_mut(), response, &mut self.router);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Preview for AccountManagementView {
|
||||
type Prev = AccountManagementPreview;
|
||||
impl<'a> Preview for AccountsView<'a> {
|
||||
type Prev = AccountsPreview;
|
||||
|
||||
fn preview(_cfg: PreviewConfig) -> Self::Prev {
|
||||
AccountManagementPreview::new()
|
||||
AccountsPreview::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
account_manager::UserAccount, colors::PINK, profile::DisplayName, ui,
|
||||
ui::profile_preview_controller, Damus, Result,
|
||||
colors::PINK, profile::DisplayName, ui, ui::profile_preview_controller,
|
||||
user_account::UserAccount, Damus, Result,
|
||||
};
|
||||
|
||||
use nostrdb::Ndb;
|
||||
@@ -48,17 +48,19 @@ impl AccountSelectionWidget {
|
||||
|
||||
fn perform_action(app: &mut Damus, action: AccountSelectAction) {
|
||||
match action {
|
||||
AccountSelectAction::RemoveAccount { _index } => app.accounts.remove_account(_index),
|
||||
AccountSelectAction::RemoveAccount { _index } => {
|
||||
app.accounts_mut().remove_account(_index)
|
||||
}
|
||||
AccountSelectAction::SelectAccount { _index } => {
|
||||
app.show_account_switcher = false;
|
||||
app.accounts.select_account(_index);
|
||||
app.accounts_mut().select_account(_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show(app: &mut Damus, ui: &mut egui::Ui) -> (AccountSelectResponse, egui::Response) {
|
||||
let mut res = AccountSelectResponse::default();
|
||||
let mut selected_index = app.accounts.get_selected_account_index();
|
||||
let mut selected_index = app.accounts().get_selected_account_index();
|
||||
|
||||
let response = Frame::none()
|
||||
.outer_margin(8.0)
|
||||
@@ -75,9 +77,9 @@ impl AccountSelectionWidget {
|
||||
ui.add(add_account_button());
|
||||
|
||||
if let Some(_index) = selected_index {
|
||||
if let Some(account) = app.accounts.get_account(_index) {
|
||||
if let Some(account) = app.accounts().get_account(_index) {
|
||||
ui.add_space(8.0);
|
||||
if Self::handle_sign_out(&app.ndb, ui, account) {
|
||||
if Self::handle_sign_out(app.ndb(), ui, account) {
|
||||
res.action = Some(AccountSelectAction::RemoveAccount { _index })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,11 @@ pub mod preview;
|
||||
pub mod profile;
|
||||
pub mod relay;
|
||||
pub mod side_panel;
|
||||
pub mod stateful_account_management;
|
||||
pub mod thread;
|
||||
pub mod timeline;
|
||||
pub mod username;
|
||||
|
||||
pub use account_management::AccountManagementView;
|
||||
pub use account_management::AccountsView;
|
||||
pub use account_switcher::AccountSelectionWidget;
|
||||
pub use mention::Mention;
|
||||
pub use note::{NoteResponse, NoteView, PostReplyView, PostView};
|
||||
|
||||
@@ -17,6 +17,7 @@ use crate::{
|
||||
ui::View,
|
||||
};
|
||||
use egui::{Label, RichText, Sense};
|
||||
use enostr::NoteId;
|
||||
use nostrdb::{Ndb, Note, NoteKey, NoteReply, Transaction};
|
||||
|
||||
pub struct NoteView<'a> {
|
||||
@@ -393,7 +394,7 @@ impl<'a> NoteView<'a> {
|
||||
));
|
||||
|
||||
if self.options().has_actionbar() {
|
||||
note_action = render_note_actionbar(ui, note_key).inner;
|
||||
note_action = render_note_actionbar(ui, self.note.id(), note_key).inner;
|
||||
}
|
||||
|
||||
resp
|
||||
@@ -430,7 +431,7 @@ impl<'a> NoteView<'a> {
|
||||
));
|
||||
|
||||
if self.options().has_actionbar() {
|
||||
note_action = render_note_actionbar(ui, note_key).inner;
|
||||
note_action = render_note_actionbar(ui, self.note.id(), note_key).inner;
|
||||
}
|
||||
});
|
||||
})
|
||||
@@ -446,6 +447,7 @@ impl<'a> NoteView<'a> {
|
||||
|
||||
fn render_note_actionbar(
|
||||
ui: &mut egui::Ui,
|
||||
note_id: &[u8; 32],
|
||||
note_key: NoteKey,
|
||||
) -> egui::InnerResponse<Option<BarAction>> {
|
||||
ui.horizontal(|ui| {
|
||||
@@ -453,9 +455,9 @@ fn render_note_actionbar(
|
||||
let thread_resp = thread_button(ui, note_key);
|
||||
|
||||
if reply_resp.clicked() {
|
||||
Some(BarAction::Reply)
|
||||
Some(BarAction::Reply(NoteId::new(*note_id)))
|
||||
} else if thread_resp.clicked() {
|
||||
Some(BarAction::OpenThread)
|
||||
Some(BarAction::OpenThread(NoteId::new(*note_id)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -41,32 +41,32 @@ pub fn view_profile_previews(
|
||||
) -> Option<usize> {
|
||||
let width = ui.available_width();
|
||||
|
||||
let txn = if let Ok(txn) = Transaction::new(&app.ndb) {
|
||||
let txn = if let Ok(txn) = Transaction::new(app.ndb()) {
|
||||
txn
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
for i in 0..app.accounts.num_accounts() {
|
||||
let account = if let Some(account) = app.accounts.get_account(i) {
|
||||
for i in 0..app.accounts().num_accounts() {
|
||||
let account = if let Some(account) = app.accounts().get_account(i) {
|
||||
account
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let profile = app
|
||||
.ndb
|
||||
.ndb()
|
||||
.get_profile_by_pubkey(&txn, account.pubkey.bytes())
|
||||
.ok();
|
||||
|
||||
let preview = SimpleProfilePreview::new(profile.as_ref(), &mut app.img_cache);
|
||||
|
||||
let is_selected = if let Some(selected) = app.accounts.get_selected_account_index() {
|
||||
let is_selected = if let Some(selected) = app.accounts().get_selected_account_index() {
|
||||
i == selected
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let preview = SimpleProfilePreview::new(profile.as_ref(), app.img_cache_mut());
|
||||
|
||||
if add_preview_ui(ui, preview, width, is_selected, i) {
|
||||
return Some(i);
|
||||
}
|
||||
@@ -91,16 +91,16 @@ pub fn show_with_selected_pfp(
|
||||
ui: &mut egui::Ui,
|
||||
ui_element: fn(ui: &mut egui::Ui, pfp: ProfilePic) -> egui::Response,
|
||||
) -> Option<egui::Response> {
|
||||
let selected_account = app.accounts.get_selected_account();
|
||||
let selected_account = app.accounts().get_selected_account();
|
||||
if let Some(selected_account) = selected_account {
|
||||
if let Ok(txn) = Transaction::new(&app.ndb) {
|
||||
if let Ok(txn) = Transaction::new(app.ndb()) {
|
||||
let profile = app
|
||||
.ndb
|
||||
.ndb()
|
||||
.get_profile_by_pubkey(&txn, selected_account.pubkey.bytes());
|
||||
|
||||
return Some(ui_element(
|
||||
ui,
|
||||
ProfilePic::new(&mut app.img_cache, get_profile_url(profile.ok().as_ref())),
|
||||
ProfilePic::new(app.img_cache_mut(), get_profile_url(profile.ok().as_ref())),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -114,12 +114,12 @@ pub fn show_with_pfp(
|
||||
key: &[u8; 32],
|
||||
ui_element: fn(ui: &mut egui::Ui, pfp: ProfilePic) -> egui::Response,
|
||||
) -> Option<egui::Response> {
|
||||
if let Ok(txn) = Transaction::new(&app.ndb) {
|
||||
let profile = app.ndb.get_profile_by_pubkey(&txn, key);
|
||||
if let Ok(txn) = Transaction::new(app.ndb()) {
|
||||
let profile = app.ndb().get_profile_by_pubkey(&txn, key);
|
||||
|
||||
return Some(ui_element(
|
||||
ui,
|
||||
ProfilePic::new(&mut app.img_cache, get_profile_url(profile.ok().as_ref())),
|
||||
ProfilePic::new(app.img_cache_mut(), get_profile_url(profile.ok().as_ref())),
|
||||
));
|
||||
}
|
||||
None
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
use egui::Ui;
|
||||
use egui_nav::{Nav, NavAction};
|
||||
use nostrdb::Ndb;
|
||||
|
||||
use crate::{
|
||||
account_manager::{process_login_view_response, AccountManager},
|
||||
imgcache::ImageCache,
|
||||
login_manager::LoginState,
|
||||
routable_widget_state::RoutableWidgetState,
|
||||
route::{ManageAccountRoute, ManageAcountRouteResponse},
|
||||
Damus,
|
||||
};
|
||||
|
||||
use super::{
|
||||
account_login_view::AccountLoginView, account_management::AccountManagementViewResponse,
|
||||
AccountManagementView,
|
||||
};
|
||||
|
||||
pub struct StatefulAccountManagementView {}
|
||||
|
||||
impl StatefulAccountManagementView {
|
||||
pub fn show(
|
||||
ui: &mut Ui,
|
||||
account_management_state: &mut RoutableWidgetState<ManageAccountRoute>,
|
||||
account_manager: &mut AccountManager,
|
||||
img_cache: &mut ImageCache,
|
||||
login_state: &mut LoginState,
|
||||
ndb: &Ndb,
|
||||
) {
|
||||
let routes = account_management_state.get_routes();
|
||||
|
||||
let nav_response =
|
||||
Nav::new(routes)
|
||||
.title(false)
|
||||
.navigating(false)
|
||||
.show_mut(ui, |ui, nav| match nav.top() {
|
||||
ManageAccountRoute::AccountManagement => {
|
||||
AccountManagementView::ui(ui, account_manager, ndb, img_cache)
|
||||
.inner
|
||||
.map(ManageAcountRouteResponse::AccountManagement)
|
||||
}
|
||||
ManageAccountRoute::AddAccount => AccountLoginView::new(login_state)
|
||||
.ui(ui)
|
||||
.inner
|
||||
.map(ManageAcountRouteResponse::AddAccount),
|
||||
});
|
||||
|
||||
if let Some(resp) = nav_response.inner {
|
||||
match resp {
|
||||
ManageAcountRouteResponse::AccountManagement(response) => {
|
||||
process_management_view_response_stateful(
|
||||
response,
|
||||
account_manager,
|
||||
account_management_state,
|
||||
);
|
||||
}
|
||||
ManageAcountRouteResponse::AddAccount(response) => {
|
||||
process_login_view_response(account_manager, response);
|
||||
*login_state = Default::default();
|
||||
account_management_state.go_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(NavAction::Returned) = nav_response.action {
|
||||
account_management_state.go_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_management_view_response_stateful(
|
||||
response: AccountManagementViewResponse,
|
||||
manager: &mut AccountManager,
|
||||
state: &mut RoutableWidgetState<ManageAccountRoute>,
|
||||
) {
|
||||
match response {
|
||||
AccountManagementViewResponse::RemoveAccount(index) => {
|
||||
manager.remove_account(index);
|
||||
}
|
||||
AccountManagementViewResponse::SelectAccount(index) => {
|
||||
manager.select_account(index);
|
||||
}
|
||||
AccountManagementViewResponse::RouteToLogin => {
|
||||
state.route_to(ManageAccountRoute::AddAccount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod preview {
|
||||
use crate::{
|
||||
test_data,
|
||||
ui::{Preview, PreviewConfig, View},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct StatefulAccountManagementPreview {
|
||||
app: Damus,
|
||||
}
|
||||
|
||||
impl StatefulAccountManagementPreview {
|
||||
fn new() -> Self {
|
||||
let mut app = test_data::test_app();
|
||||
app.account_management_view_state
|
||||
.route_to(ManageAccountRoute::AccountManagement);
|
||||
|
||||
StatefulAccountManagementPreview { app }
|
||||
}
|
||||
}
|
||||
|
||||
impl View for StatefulAccountManagementPreview {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
StatefulAccountManagementView::show(
|
||||
ui,
|
||||
&mut self.app.account_management_view_state,
|
||||
&mut self.app.accounts,
|
||||
&mut self.app.img_cache,
|
||||
&mut self.app.login_state,
|
||||
&self.app.ndb,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Preview for StatefulAccountManagementView {
|
||||
type Prev = StatefulAccountManagementPreview;
|
||||
|
||||
fn preview(cfg: PreviewConfig) -> Self::Prev {
|
||||
let _ = cfg;
|
||||
StatefulAccountManagementPreview::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
101
src/ui/thread.rs
101
src/ui/thread.rs
@@ -1,55 +1,49 @@
|
||||
use crate::{
|
||||
actionbar::BarResult, column::Columns, imgcache::ImageCache, notecache::NoteCache,
|
||||
thread::Threads, timeline::TimelineSource, ui, unknowns::UnknownIds,
|
||||
actionbar::BarAction, imgcache::ImageCache, notecache::NoteCache, thread::Threads, ui,
|
||||
};
|
||||
use enostr::RelayPool;
|
||||
use nostrdb::{Ndb, NoteKey, Transaction};
|
||||
use tracing::{error, warn};
|
||||
|
||||
pub struct ThreadView<'a> {
|
||||
column: usize,
|
||||
columns: &'a mut Columns,
|
||||
threads: &'a mut Threads,
|
||||
ndb: &'a Ndb,
|
||||
pool: &'a mut RelayPool,
|
||||
note_cache: &'a mut NoteCache,
|
||||
img_cache: &'a mut ImageCache,
|
||||
unknown_ids: &'a mut UnknownIds,
|
||||
selected_note_id: &'a [u8; 32],
|
||||
textmode: bool,
|
||||
id_source: egui::Id,
|
||||
}
|
||||
|
||||
impl<'a> ThreadView<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
column: usize,
|
||||
columns: &'a mut Columns,
|
||||
threads: &'a mut Threads,
|
||||
ndb: &'a Ndb,
|
||||
note_cache: &'a mut NoteCache,
|
||||
img_cache: &'a mut ImageCache,
|
||||
unknown_ids: &'a mut UnknownIds,
|
||||
pool: &'a mut RelayPool,
|
||||
textmode: bool,
|
||||
selected_note_id: &'a [u8; 32],
|
||||
textmode: bool,
|
||||
) -> Self {
|
||||
let id_source = egui::Id::new("threadscroll_threadview");
|
||||
ThreadView {
|
||||
column,
|
||||
columns,
|
||||
threads,
|
||||
ndb,
|
||||
note_cache,
|
||||
img_cache,
|
||||
textmode,
|
||||
selected_note_id,
|
||||
unknown_ids,
|
||||
pool,
|
||||
textmode,
|
||||
id_source,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<BarResult> {
|
||||
pub fn id_source(mut self, id: egui::Id) -> Self {
|
||||
self.id_source = id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<BarAction> {
|
||||
let txn = Transaction::new(self.ndb).expect("txn");
|
||||
let mut result: Option<BarResult> = None;
|
||||
let mut action: Option<BarAction> = None;
|
||||
|
||||
let selected_note_key = if let Ok(key) = self
|
||||
.ndb
|
||||
@@ -62,21 +56,13 @@ impl<'a> ThreadView<'a> {
|
||||
return None;
|
||||
};
|
||||
|
||||
let scroll_id = {
|
||||
egui::Id::new((
|
||||
"threadscroll",
|
||||
self.columns.column(self.column).view_id(),
|
||||
selected_note_key,
|
||||
))
|
||||
};
|
||||
|
||||
ui.label(
|
||||
egui::RichText::new("Threads ALPHA! It's not done. Things will be broken.")
|
||||
.color(egui::Color32::RED),
|
||||
);
|
||||
|
||||
egui::ScrollArea::vertical()
|
||||
.id_source(scroll_id)
|
||||
.id_source(self.id_source)
|
||||
.animated(false)
|
||||
.auto_shrink([false, false])
|
||||
.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysVisible)
|
||||
@@ -99,36 +85,27 @@ impl<'a> ThreadView<'a> {
|
||||
.map_or_else(|| self.selected_note_id, |nr| nr.id)
|
||||
};
|
||||
|
||||
let thread = self.threads.thread_mut(self.ndb, &txn, root_id).get_ptr();
|
||||
|
||||
// TODO(jb55): skip poll if ThreadResult is fresh?
|
||||
|
||||
// poll for new notes and insert them into our existing notes
|
||||
if let Err(e) = TimelineSource::Thread(root_id).poll_notes_into_view(
|
||||
&txn,
|
||||
self.ndb,
|
||||
self.columns,
|
||||
self.threads,
|
||||
self.unknown_ids,
|
||||
self.note_cache,
|
||||
) {
|
||||
if let Err(e) = thread.poll_notes_into_view(&txn, self.ndb) {
|
||||
error!("Thread::poll_notes_into_view: {e}");
|
||||
}
|
||||
|
||||
let (len, list) = {
|
||||
let thread = self.threads.thread_mut(self.ndb, &txn, root_id).get_ptr();
|
||||
let len = thread.view().notes.len();
|
||||
|
||||
let len = thread.view.notes.len();
|
||||
(len, &mut thread.view.list)
|
||||
};
|
||||
|
||||
list.clone()
|
||||
.borrow_mut()
|
||||
.ui_custom_layout(ui, len, |ui, start_index| {
|
||||
thread.view().list.clone().borrow_mut().ui_custom_layout(
|
||||
ui,
|
||||
len,
|
||||
|ui, start_index| {
|
||||
ui.spacing_mut().item_spacing.y = 0.0;
|
||||
ui.spacing_mut().item_spacing.x = 4.0;
|
||||
|
||||
let ind = len - 1 - start_index;
|
||||
let note_key = {
|
||||
let thread = self.threads.thread_mut(self.ndb, &txn, root_id).get_ptr();
|
||||
thread.view.notes[ind].key
|
||||
};
|
||||
|
||||
let note_key = thread.view().notes[ind].key;
|
||||
|
||||
let note = if let Ok(note) = self.ndb.get_note_by_key(&txn, note_key) {
|
||||
note
|
||||
@@ -138,25 +115,14 @@ impl<'a> ThreadView<'a> {
|
||||
};
|
||||
|
||||
ui::padding(8.0, ui, |ui| {
|
||||
let resp =
|
||||
if let Some(bar_action) =
|
||||
ui::NoteView::new(self.ndb, self.note_cache, self.img_cache, ¬e)
|
||||
.note_previews(!self.textmode)
|
||||
.textmode(self.textmode)
|
||||
.show(ui);
|
||||
|
||||
if let Some(action) = resp.action {
|
||||
let br = action.execute(
|
||||
self.ndb,
|
||||
self.columns.column_mut(self.column),
|
||||
self.threads,
|
||||
self.note_cache,
|
||||
self.pool,
|
||||
note.id(),
|
||||
&txn,
|
||||
);
|
||||
if br.is_some() {
|
||||
result = br;
|
||||
}
|
||||
.show(ui)
|
||||
.action
|
||||
{
|
||||
action = Some(bar_action);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -164,9 +130,10 @@ impl<'a> ThreadView<'a> {
|
||||
//ui.add(egui::Separator::default().spacing(0.0));
|
||||
|
||||
1
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
result
|
||||
action
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +1,56 @@
|
||||
use crate::{
|
||||
actionbar::BarAction,
|
||||
actionbar::BarResult,
|
||||
column::{Column, ColumnKind},
|
||||
draft::Drafts,
|
||||
imgcache::ImageCache,
|
||||
notecache::NoteCache,
|
||||
thread::Threads,
|
||||
ui,
|
||||
ui::note::PostAction,
|
||||
actionbar::BarAction, column::Columns, draft::Drafts, imgcache::ImageCache,
|
||||
notecache::NoteCache, timeline::TimelineId, ui, ui::note::PostAction,
|
||||
};
|
||||
use egui::containers::scroll_area::ScrollBarVisibility;
|
||||
use egui::{Direction, Layout};
|
||||
use egui_tabs::TabColor;
|
||||
use enostr::{FilledKeypair, RelayPool};
|
||||
use nostrdb::{Ndb, Note, Transaction};
|
||||
use tracing::{debug, info, warn};
|
||||
use nostrdb::{Ndb, Transaction};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
pub struct TimelineView<'a> {
|
||||
timeline_id: TimelineId,
|
||||
columns: &'a mut Columns,
|
||||
ndb: &'a Ndb,
|
||||
column: &'a mut Column,
|
||||
note_cache: &'a mut NoteCache,
|
||||
img_cache: &'a mut ImageCache,
|
||||
threads: &'a mut Threads,
|
||||
pool: &'a mut RelayPool,
|
||||
textmode: bool,
|
||||
reverse: bool,
|
||||
}
|
||||
|
||||
impl<'a> TimelineView<'a> {
|
||||
pub fn new(
|
||||
timeline_id: TimelineId,
|
||||
columns: &'a mut Columns,
|
||||
ndb: &'a Ndb,
|
||||
column: &'a mut Column,
|
||||
note_cache: &'a mut NoteCache,
|
||||
img_cache: &'a mut ImageCache,
|
||||
threads: &'a mut Threads,
|
||||
pool: &'a mut RelayPool,
|
||||
textmode: bool,
|
||||
) -> TimelineView<'a> {
|
||||
let reverse = false;
|
||||
TimelineView {
|
||||
ndb,
|
||||
column,
|
||||
timeline_id,
|
||||
columns,
|
||||
note_cache,
|
||||
img_cache,
|
||||
threads,
|
||||
pool,
|
||||
reverse,
|
||||
textmode,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<BarAction> {
|
||||
timeline_ui(
|
||||
ui,
|
||||
self.ndb,
|
||||
self.column,
|
||||
self.timeline_id,
|
||||
self.columns,
|
||||
self.note_cache,
|
||||
self.img_cache,
|
||||
self.threads,
|
||||
self.pool,
|
||||
self.reverse,
|
||||
self.textmode,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
pub fn reversed(mut self) -> Self {
|
||||
@@ -74,14 +63,13 @@ impl<'a> TimelineView<'a> {
|
||||
fn timeline_ui(
|
||||
ui: &mut egui::Ui,
|
||||
ndb: &Ndb,
|
||||
column: &mut Column,
|
||||
timeline_id: TimelineId,
|
||||
columns: &mut Columns,
|
||||
note_cache: &mut NoteCache,
|
||||
img_cache: &mut ImageCache,
|
||||
threads: &mut Threads,
|
||||
pool: &mut RelayPool,
|
||||
reversed: bool,
|
||||
textmode: bool,
|
||||
) {
|
||||
) -> Option<BarAction> {
|
||||
//padding(4.0, ui, |ui| ui.heading("Notifications"));
|
||||
/*
|
||||
let font_id = egui::TextStyle::Body.resolve(ui.style());
|
||||
@@ -89,29 +77,37 @@ fn timeline_ui(
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
let timeline = if let ColumnKind::Timeline(timeline) = column.kind_mut() {
|
||||
let scroll_id = {
|
||||
let timeline = if let Some(timeline) = columns.find_timeline_mut(timeline_id) {
|
||||
timeline
|
||||
} else {
|
||||
return;
|
||||
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;
|
||||
};
|
||||
|
||||
timeline.selected_view = tabs_ui(ui);
|
||||
|
||||
// need this for some reason??
|
||||
ui.add_space(3.0);
|
||||
}
|
||||
|
||||
let scroll_id = egui::Id::new(("tlscroll", column.view_id()));
|
||||
egui::Id::new(("tlscroll", timeline.view_id()))
|
||||
};
|
||||
|
||||
let mut bar_action: Option<BarAction> = None;
|
||||
egui::ScrollArea::vertical()
|
||||
.id_source(scroll_id)
|
||||
.animated(false)
|
||||
.auto_shrink([false, false])
|
||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysVisible)
|
||||
.show(ui, |ui| {
|
||||
let timeline = if let ColumnKind::Timeline(timeline) = column.kind_mut() {
|
||||
let timeline = if let Some(timeline) = columns.find_timeline_mut(timeline_id) {
|
||||
timeline
|
||||
} else {
|
||||
error!("tried to render timeline in column, but timeline was missing");
|
||||
// TODO (jb55): render error when timeline is missing?
|
||||
// this shouldn't happen...
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -124,7 +120,6 @@ fn timeline_ui(
|
||||
return 0;
|
||||
};
|
||||
|
||||
let mut bar_action: Option<(BarAction, Note)> = None;
|
||||
view.list
|
||||
.clone()
|
||||
.borrow_mut()
|
||||
@@ -154,7 +149,7 @@ fn timeline_ui(
|
||||
.show(ui);
|
||||
|
||||
if let Some(ba) = resp.action {
|
||||
bar_action = Some((ba, note));
|
||||
bar_action = Some(ba);
|
||||
} else if resp.response.clicked() {
|
||||
debug!("clicked note");
|
||||
}
|
||||
@@ -166,25 +161,10 @@ fn timeline_ui(
|
||||
1
|
||||
});
|
||||
|
||||
// handle any actions from the virtual list
|
||||
if let Some((action, note)) = bar_action {
|
||||
if let Some(br) =
|
||||
action.execute(ndb, column, threads, note_cache, pool, note.id(), &txn)
|
||||
{
|
||||
match br {
|
||||
// update the thread for next render if we have new notes
|
||||
BarResult::NewThreadNotes(new_notes) => {
|
||||
let thread = threads
|
||||
.thread_mut(ndb, &txn, new_notes.root_id.bytes())
|
||||
.get_ptr();
|
||||
new_notes.process(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
|
||||
});
|
||||
|
||||
bar_action
|
||||
}
|
||||
|
||||
pub fn postbox_view<'a>(
|
||||
|
||||
Reference in New Issue
Block a user