diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs index b29cf49..c2e503e 100644 --- a/crates/notedeck_columns/src/app.rs +++ b/crates/notedeck_columns/src/app.rs @@ -1172,6 +1172,7 @@ fn timelines_view( let side_panel = DesktopSidePanel::new( ctx.accounts.get_selected_account(), &app.decks_cache, + ctx.accounts, ctx.i18n, ) .show(ui); @@ -1226,14 +1227,48 @@ fn timelines_view( ); }); - // Check if a channel is selected - // Clone the timeline_kind to avoid borrowing app across the closure + // Check if a channel is selected and if we need to show other views first let selected_timeline_kind = app.channels_cache .active_channels(ctx.accounts) .selected_channel() .map(|c| c.timeline_kind.clone()); - if let Some(timeline_kind) = selected_timeline_kind { + // Check if we need to show other views (Accounts, Relays, etc.) instead of channel + let router = get_active_columns_mut(ctx.i18n, ctx.accounts, &mut app.decks_cache).get_selected_router(); + let should_override_channel = router.routes().iter().any(|route| { + matches!(route, Route::Accounts(_) | Route::Relays | Route::AddColumn(_) | Route::ComposeNote | Route::Search | Route::NewDeck | Route::EditDeck(_)) + }); + + // Debug: Check the override condition + if should_override_channel { + println!("DEBUG: Overriding channel view, routes count: {}", router.routes().len()); + } else { + println!("DEBUG: Not overriding channel view, routes count: {}", router.routes().len()); + } + + if should_override_channel { + // Render router-based views (Accounts, Relays, etc.) + 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 + }; + + // Render navigation for the router views + println!("DEBUG: Calling nav::render_nav for column 0"); + let resp = nav::render_nav(0, inner_rect, app, ctx, ui); + println!("DEBUG: nav::render_nav completed, responses: {}", responses.len()); + 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); + }); + } else if let Some(timeline_kind) = selected_timeline_kind { // Render ChatView for the selected channel strip.cell(|ui| { let rect = ui.available_rect_before_wrap(); @@ -1318,6 +1353,7 @@ fn timelines_view( let side_panel = DesktopSidePanel::new( ctx.accounts.get_selected_account(), &app.decks_cache, + ctx.accounts, ctx.i18n, ) .show(ui); diff --git a/crates/notedeck_columns/src/ui/side_panel.rs b/crates/notedeck_columns/src/ui/side_panel.rs index af7f2f0..cfdc46b 100644 --- a/crates/notedeck_columns/src/ui/side_panel.rs +++ b/crates/notedeck_columns/src/ui/side_panel.rs @@ -5,6 +5,7 @@ use egui::{ use tracing::{error, info}; use crate::{ + accounts::AccountsRoute, app::{get_active_columns_mut, get_decks_mut}, app_style::DECK_ICON_SIZE, decks::{DecksAction, DecksCache}, @@ -26,6 +27,7 @@ static ICON_WIDTH: f32 = 40.0; pub struct DesktopSidePanel<'a> { selected_account: &'a UserAccount, decks_cache: &'a DecksCache, + accounts: &'a Accounts, i18n: &'a mut Localization, } @@ -45,6 +47,8 @@ pub enum SidePanelAction { SwitchDeck(usize), EditDeck(usize), Wallet, + Account, // Use existing Account instead of UserAccount + Settings, } pub struct SidePanelResponse { @@ -62,11 +66,13 @@ impl<'a> DesktopSidePanel<'a> { pub fn new( selected_account: &'a UserAccount, decks_cache: &'a DecksCache, + accounts: &'a Accounts, i18n: &'a mut Localization, ) -> Self { Self { selected_account, decks_cache, + accounts, i18n, } } @@ -95,6 +101,20 @@ impl<'a> DesktopSidePanel<'a> { let inner = ui .vertical(|ui| { ui.with_layout(Layout::top_down(egui::Align::Center), |ui| { + // User controls section + ui.add_space(4.0); + + // User profile button + let user_account_resp = ui.add(user_account_button(&self.selected_account, dark_mode)); + + // Add account button if no account or for switching + let add_account_resp = ui.add(add_account_button(dark_mode)); + + // Relay configuration button + let relay_resp = ui.add(relay_button(dark_mode)); + + ui.add(Separator::default().horizontal().spacing(8.0).shrink(4.0)); + // macos needs a bit of space to make room for window // minimize/close buttons //if cfg!(target_os = "macos") { @@ -136,7 +156,19 @@ impl<'a> DesktopSidePanel<'a> { expand_resp, )) */ - if compose_resp.clicked() { + if user_account_resp.clicked() { + Some(InnerResponse::new( + SidePanelAction::Account, + user_account_resp, + )) + } else if add_account_resp.clicked() { + Some(InnerResponse::new( + SidePanelAction::Account, // Reuse Account for adding account + add_account_resp, + )) + } else if relay_resp.clicked() { + Some(InnerResponse::new(SidePanelAction::Settings, relay_resp)) + } else if compose_resp.clicked() { Some(InnerResponse::new( SidePanelAction::ComposeNote, compose_resp, @@ -190,8 +222,6 @@ impl<'a> DesktopSidePanel<'a> { let router = get_active_columns_mut(i18n, accounts, decks_cache).get_selected_router(); let mut switching_response = None; match action { - /* - SidePanelAction::Panel => {} // TODO SidePanelAction::Account => { if router .routes() @@ -206,21 +236,12 @@ impl<'a> DesktopSidePanel<'a> { } SidePanelAction::Settings => { if router.routes().iter().any(|r| r == &Route::Relays) { - // return if we are already routing to accounts + // return if we are already routing to relays router.go_back(); } else { router.route_to(Route::relays()); } } - SidePanelAction::Support => { - if router.routes().iter().any(|r| r == &Route::Support) { - router.go_back(); - } else { - support.refresh(); - router.route_to(Route::Support); - } - } - */ SidePanelAction::Columns => { if router .routes() @@ -445,3 +466,96 @@ fn show_decks<'a>( } InnerResponse::new(clicked_index, resp) } + +fn user_account_button(user_account: &UserAccount, dark_mode: bool) -> impl Widget + '_ { + move |ui: &mut egui::Ui| -> egui::Response { + let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; + let helper = AnimationHelper::new(ui, "user-account-button", vec2(max_size, max_size)); + + // Show user icon if logged in, otherwise show login icon + let img = if user_account.key.secret_key.is_some() { + // User is logged in - show user/home icon + if dark_mode { + app_images::home_dark_image() + } else { + app_images::home_light_image() + } + } else { + // No user logged in - show login icon + if dark_mode { + app_images::link_dark_image() + } else { + app_images::link_light_image() + } + }; + + let cur_img_size = helper.scale_1d_pos(ICON_WIDTH - 8.0); // Slightly smaller + img.paint_at( + ui, + helper + .get_animation_rect() + .shrink((max_size - cur_img_size) / 2.0), + ); + + helper + .take_animation_response() + .on_hover_cursor(CursorIcon::PointingHand) + .on_hover_text(if user_account.key.secret_key.is_some() { + "User Account" + } else { + "Login / Create Account" + }) + } +} + +fn add_account_button(dark_mode: bool) -> impl Widget { + move |ui: &mut egui::Ui| -> egui::Response { + let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; + let helper = AnimationHelper::new(ui, "add-account-button", vec2(max_size, max_size)); + + let img = if dark_mode { + app_images::add_column_dark_image() + } else { + app_images::add_column_light_image() + }; + + let cur_img_size = helper.scale_1d_pos(ICON_WIDTH - 12.0); + img.paint_at( + ui, + helper + .get_animation_rect() + .shrink((max_size - cur_img_size) / 2.0), + ); + + helper + .take_animation_response() + .on_hover_cursor(CursorIcon::PointingHand) + .on_hover_text("Add Account") + } +} + +fn relay_button(dark_mode: bool) -> impl Widget { + move |ui: &mut egui::Ui| -> egui::Response { + let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; + let helper = AnimationHelper::new(ui, "relay-button", vec2(max_size, max_size)); + + let img = if dark_mode { + app_images::reply_dark_image() + } else { + app_images::reply_light_image() + }; + + let cur_img_size = helper.scale_1d_pos(ICON_WIDTH - 10.0); + img.paint_at( + ui, + helper + .get_animation_rect() + .shrink((max_size - cur_img_size) / 2.0), + ); + + helper + .take_animation_response() + .on_hover_cursor(CursorIcon::PointingHand) + .on_hover_text("Relay Configuration") + } +}