From 14b80fed4d7b36c79f0c77699b840f35a1a0ff3d Mon Sep 17 00:00:00 2001 From: Aljaz Ceru Date: Fri, 14 Nov 2025 13:45:23 +0100 Subject: [PATCH] layout working --- crates/notedeck_columns/src/app.rs | 156 ++++++++++++++++---- crates/notedeck_columns/src/nav.rs | 18 ++- crates/notedeck_columns/src/relay_config.rs | 2 +- crates/notedeck_columns/src/ui/chat_view.rs | 8 +- 4 files changed, 146 insertions(+), 38 deletions(-) diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs index eeaa560..b29cf49 100644 --- a/crates/notedeck_columns/src/app.rs +++ b/crates/notedeck_columns/src/app.rs @@ -754,7 +754,7 @@ impl Damus { info!("RelayConfig: loading from disk"); relay_config } else { - info!("RelayConfig: creating new empty config (no relays)"); + info!("RelayConfig: creating new config with default relays"); crate::relay_config::RelayConfig::default() }; @@ -903,6 +903,7 @@ fn render_damus_mobile( app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui, ) -> AppResponse { + //let routes = app.timelines[0].routes.clone(); let mut can_take_drag_from = Vec::new(); @@ -1058,12 +1059,21 @@ fn render_damus_desktop( app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui, ) -> AppResponse { + + let num_cols = get_active_columns(app_ctx.accounts, &app.decks_cache).num_columns(); let screen_size = ui.ctx().screen_rect().width(); - let calc_panel_width = (screen_size - / get_active_columns(app_ctx.accounts, &app.decks_cache).num_columns() as f32) - - 30.0; + let sidebar_width = ui::side_panel::SIDE_PANEL_WIDTH + CHANNEL_SIDEBAR_WIDTH; + let available_width = screen_size - sidebar_width; + + // Check if we need horizontal scrolling for the content area + let calc_panel_width = if num_cols > 0 { + available_width / num_cols as f32 + } else { + available_width + } - 30.0; + let min_width = 320.0; - let need_scroll = calc_panel_width < min_width; + let need_scroll = num_cols > 1 && calc_panel_width < min_width; let panel_sizes = if need_scroll { Size::exact(min_width) } else { @@ -1086,7 +1096,7 @@ fn process_chat_action( action: NoteAction, app: &mut Damus, ctx: &mut AppContext<'_>, - ui: &mut egui::Ui, + _ui: &mut egui::Ui, ) { match action { NoteAction::Note { note_id, .. } => { @@ -1147,32 +1157,15 @@ fn timelines_view( // Check if a channel is selected to determine layout let is_channel_selected = app.channels_cache.active_channels(ctx.accounts).selected_channel().is_some(); - let content_cells = if is_channel_selected { 1 } else { num_cols }; - - StripBuilder::new(ui) - .size(Size::exact(CHANNEL_SIDEBAR_WIDTH)) - .size(Size::exact(ui::side_panel::SIDE_PANEL_WIDTH)) - .sizes(sizes, content_cells) - .clip(true) - .horizontal(|mut strip| { - // Channel Sidebar - strip.cell(|ui| { - let rect = ui.available_rect_before_wrap(); - let mut channel_sidebar = - ChannelSidebar::new(&app.channels_cache, ctx.accounts, ctx.i18n); - - if let Some(response) = channel_sidebar.show(ui) { - channel_sidebar_action = Some(response.action); - } - - // vertical sidebar line - ui.painter().vline( - rect.right(), - rect.y_range(), - ui.visuals().widgets.noninteractive.bg_stroke, - ); - }); + if is_channel_selected { + // When channel is selected: Side Panel | Channel Sidebar | Content Area (remainder) + StripBuilder::new(ui) + .size(Size::exact(ui::side_panel::SIDE_PANEL_WIDTH)) + .size(Size::exact(CHANNEL_SIDEBAR_WIDTH)) + .size(Size::remainder()) + .clip(true) + .horizontal(|mut strip| { // Desktop Side Panel strip.cell(|ui| { let rect = ui.available_rect_before_wrap(); @@ -1215,6 +1208,24 @@ fn timelines_view( ); }); + // Channel Sidebar + strip.cell(|ui| { + let rect = ui.available_rect_before_wrap(); + let mut channel_sidebar = + ChannelSidebar::new(&app.channels_cache, ctx.accounts, ctx.i18n); + + if let Some(response) = channel_sidebar.show(ui) { + channel_sidebar_action = Some(response.action); + } + + // vertical sidebar line + ui.painter().vline( + rect.right(), + rect.y_range(), + ui.visuals().widgets.noninteractive.bg_stroke, + ); + }); + // Check if a channel is selected // Clone the timeline_kind to avoid borrowing app across the closure let selected_timeline_kind = app.channels_cache @@ -1293,6 +1304,89 @@ fn timelines_view( } } }); + } else { + // When no channel is selected: Side Panel | Channel Sidebar | Multiple Columns + StripBuilder::new(ui) + .size(Size::exact(ui::side_panel::SIDE_PANEL_WIDTH)) + .size(Size::exact(CHANNEL_SIDEBAR_WIDTH)) + .sizes(sizes, num_cols) + .clip(true) + .horizontal(|mut strip| { + // Desktop Side Panel + strip.cell(|ui| { + let rect = ui.available_rect_before_wrap(); + let side_panel = DesktopSidePanel::new( + ctx.accounts.get_selected_account(), + &app.decks_cache, + ctx.i18n, + ) + .show(ui); + + if let Some(side_panel) = side_panel { + if side_panel.response.clicked() || side_panel.response.secondary_clicked() { + if let Some(action) = DesktopSidePanel::perform_action( + &mut app.decks_cache, + ctx.accounts, + side_panel.action, + ctx.i18n, + ) { + side_panel_action = Some(action); + } + } + } + + // vertical sidebar line + ui.painter().vline( + rect.right(), + rect.y_range(), + ui.visuals().widgets.noninteractive.bg_stroke, + ); + }); + + // Channel Sidebar + strip.cell(|ui| { + let rect = ui.available_rect_before_wrap(); + let mut channel_sidebar = + ChannelSidebar::new(&app.channels_cache, ctx.accounts, ctx.i18n); + + if let Some(response) = channel_sidebar.show(ui) { + channel_sidebar_action = Some(response.action); + } + + // vertical sidebar line + ui.painter().vline( + rect.right(), + rect.y_range(), + ui.visuals().widgets.noninteractive.bg_stroke, + ); + }); + + // Normal column view when no channel is selected + for col_index in 0..num_cols { + strip.cell(|ui| { + let rect = ui.available_rect_before_wrap(); + let v_line_stroke = ui.visuals().widgets.noninteractive.bg_stroke; + let inner_rect = { + let mut inner = rect; + inner.set_right(rect.right() - v_line_stroke.width); + inner + }; + let resp = nav::render_nav(col_index, inner_rect, app, ctx, ui); + can_take_drag_from.extend(resp.can_take_drag_from()); + responses.push(resp); + + // vertical line + ui.painter() + .vline(rect.right(), rect.y_range(), v_line_stroke); + + // we need borrow ui context for processing, so proces + // responses in the last cell + + if col_index == num_cols - 1 {} + }); + } + }); + } // process the side panel action after so we don't change the number of columns during // StripBuilder rendering diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs index a205e05..cbab8af 100644 --- a/crates/notedeck_columns/src/nav.rs +++ b/crates/notedeck_columns/src/nav.rs @@ -1050,6 +1050,20 @@ pub fn render_nav( ) -> RenderNavResponse { let narrow = is_narrow(ui.ctx()); + // Prevent navigation layer conflicts during first-time setup + let selected_account = ctx.accounts.get_selected_account(); + let account_count = ctx.accounts.cache.into_iter().count(); + if selected_account.key.pubkey == notedeck::FALLBACK_PUBKEY() && account_count <= 1 { + // Return minimal navigation response to avoid layer conflicts + let routes = vec![Route::add_account()]; + let nav = Nav::new(&routes).id_source(egui::Id::new(("minimal_nav", col))); + let nav_response = nav.show(ui, |_, _, _| RouteResponse { + response: None, + can_take_drag_from: Vec::new(), + }); + return RenderNavResponse::new(col, NotedeckNavResponse::Nav(Box::new(nav_response))); + } + if let Some(sheet_route) = app .columns(ctx.accounts) .column(col) @@ -1073,7 +1087,7 @@ pub fn render_nav( .cloned(); if let Some(bg_route) = bg_route { let resp = PopupSheet::new(&bg_route, &sheet_route) - .id_source(egui::Id::new(("nav", col))) + .id_source(egui::Id::new(("popup_sheet_nav", col))) .navigating(navigating) .returning(returning) .with_split(split) @@ -1104,7 +1118,7 @@ pub fn render_nav( .router() .routes() .clone(); - let nav = Nav::new(&routes).id_source(egui::Id::new(("nav", col))); + let nav = Nav::new(&routes).id_source(egui::Id::new(("main_nav", col))); let nav_response = nav .navigating( diff --git a/crates/notedeck_columns/src/relay_config.rs b/crates/notedeck_columns/src/relay_config.rs index 79f406a..0de62f7 100644 --- a/crates/notedeck_columns/src/relay_config.rs +++ b/crates/notedeck_columns/src/relay_config.rs @@ -64,7 +64,7 @@ impl RelayConfig { impl Default for RelayConfig { fn default() -> Self { - Self::new() + Self::default_relays() } } diff --git a/crates/notedeck_columns/src/ui/chat_view.rs b/crates/notedeck_columns/src/ui/chat_view.rs index 134dd8d..f2cb0c2 100644 --- a/crates/notedeck_columns/src/ui/chat_view.rs +++ b/crates/notedeck_columns/src/ui/chat_view.rs @@ -28,9 +28,9 @@ struct MessageBubbleResponse { pub struct ChatView<'a, 'd> { timeline_id: &'a TimelineKind, timeline_cache: &'a mut TimelineCache, - note_options: NoteOptions, + _note_options: NoteOptions, note_context: &'a mut NoteContext<'d>, - jobs: &'a mut JobsCache, + _jobs: &'a mut JobsCache, col: usize, } @@ -46,9 +46,9 @@ impl<'a, 'd> ChatView<'a, 'd> { Self { timeline_id, timeline_cache, - note_options, + _note_options: note_options, note_context, - jobs, + _jobs: jobs, col, } }