Skip to content

Conversation

@mmalmi
Copy link
Contributor

@mmalmi mmalmi commented Nov 7, 2025

No description provided.

@jb55 jb55 requested review from Copilot, jb55 and kernelkind November 7, 2025 20:21
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request implements a comprehensive UI/UX overhaul including new navigation, search functionality, profile features, and settings redesign. The changes add clickable usernames, profile badges for followed users, recent search history, enhanced settings with nested routes, profile statistics, and mouse navigation support.

Key Changes

  • Added clickable usernames and profile badges indicating followed users
  • Implemented recent search history with keyboard navigation
  • Redesigned settings UI with categorized sections and nested routing
  • Added profile statistics (following count) and "View as" context menu option
  • Implemented mouse back/forward button navigation for columns

Reviewed Changes

Copilot reviewed 34 out of 34 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
crates/notedeck_ui/src/widgets.rs Added new button widgets (rounded, segmented) and helper functions for side panel styling
crates/notedeck_ui/src/username.rs Made usernames clickable and added unused helper function
crates/notedeck_ui/src/profile/picture.rs Added badge display for followed users on profile pictures
crates/notedeck_ui/src/profile/mod.rs Added expandable/truncatable about section variants
crates/notedeck_ui/src/note/mod.rs Made note headers clickable to navigate to profiles
crates/notedeck_columns/src/ui/widgets.rs Added UserRow widget for displaying user information
crates/notedeck_columns/src/ui/side_panel.rs Major redesign with new navigation buttons and connectivity indicator
crates/notedeck_columns/src/ui/settings.rs Complete settings UI redesign with nested routes and modern layout
crates/notedeck_columns/src/ui/search/mod.rs Added recent search history, keyboard navigation, and user search suggestions
crates/notedeck_columns/src/ui/search/state.rs Added Default derive for FocusState enum
crates/notedeck_columns/src/ui/profile/mod.rs Added profile statistics display and contacts list view
crates/notedeck_columns/src/route.rs Added SettingsRoute enum and Following/FollowedBy routes
crates/notedeck_columns/src/app.rs Added mouse back/forward navigation and hovered column tracking

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +107 to +125
fn ui_abbreviate_name_clickable(ui: &mut egui::Ui, name: &str, len: usize, color: Option<Color32>) -> bool {
let should_abbrev = name.len() > len;
let name = if should_abbrev {
let closest = notedeck::abbrev::floor_char_boundary(name, len);
&name[..closest]
} else {
name
};

let resp1 = ui.add(egui::Label::new(colored_name(name, color)).sense(egui::Sense::click()));

let resp2 = if should_abbrev {
ui.add(egui::Label::new(colored_name("..", color)).sense(egui::Sense::click()))
} else {
resp1.clone()
};

resp1.clicked() || resp2.clicked()
}
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function ui_abbreviate_name_clickable is defined but never used in the codebase. This appears to be dead code that should either be removed or integrated into the username clickability implementation if it was intended to replace the current approach.

Copilot uses AI. Check for mistakes.
mod state;

pub use state::{FocusState, SearchQueryState, SearchState};
pub use state::{FocusState, RecentSearchItem, SearchQueryState, SearchState};
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RecentSearchItem is exported from the state module but is not defined in state.rs. This will cause a compilation error. The type needs to be defined in the state module or the export should be removed.

Suggested change
pub use state::{FocusState, RecentSearchItem, SearchQueryState, SearchState};
pub use state::{FocusState, SearchQueryState, SearchState};

Copilot uses AI. Check for mistakes.
})
SearchState::New | SearchState::Navigating | SearchState::Typing(TypingType::Mention(_)) => {
if !self.query.string.is_empty() && !self.query.string.starts_with('@') {
self.query.user_results = self.note_context.ndb.search_profile(self.txn, &self.query.string, 10)
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field user_results is accessed on SearchQueryState but is not defined in the struct in state.rs. This field needs to be added to the SearchQueryState struct definition.

Copilot uses AI. Check for mistakes.
self.handle_mention_search(ui, &mut search_action);
} else {
self.query.user_results.clear();
self.query.selected_index = -1;
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field selected_index is accessed on SearchQueryState but is not defined in the struct in state.rs. This field needs to be added to the SearchQueryState struct definition.

Copilot uses AI. Check for mistakes.
}

fn show_recent_searches(&mut self, ui: &mut egui::Ui, keyboard_resp: KeyboardResponse) -> Option<SearchAction> {
if self.query.recent_searches.is_empty() {
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field recent_searches is accessed on SearchQueryState but is not defined in the struct in state.rs. This field needs to be added to the SearchQueryState struct definition with an appropriate type (likely Vec<RecentSearchItem>).

Copilot uses AI. Check for mistakes.
ui.label("Recent");
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if ui.button(RichText::new("Clear all").size(14.0)).clicked() {
self.query.clear_recent_searches();
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method clear_recent_searches is called on SearchQueryState but is not defined. This method needs to be implemented on the SearchQueryState type.

Copilot uses AI. Check for mistakes.
}

if resp.secondary_clicked() || (is_selected && ui.input(|i| i.key_pressed(Key::Delete))) {
self.query.remove_recent_search(i);
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method remove_recent_search is called on SearchQueryState but is not defined. This method needs to be implemented on the SearchQueryState type to handle removal of search history items by index.

Copilot uses AI. Check for mistakes.
None
}
SearchAction::NavigateToProfile(pubkey) => {
state.add_recent_profile(pubkey, state.string.clone());
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method add_recent_profile is called on SearchQueryState but is not defined. This method needs to be implemented on the SearchQueryState type to handle adding profiles to recent search history.

Copilot uses AI. Check for mistakes.
state.state = SearchState::Searched;
state.selected_index = -1;
state.user_results.clear();
state.add_recent_query(state.string.clone());
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method add_recent_query is called on SearchQueryState but is not defined. This method needs to be implemented on the SearchQueryState type to handle adding queries to recent search history.

Copilot uses AI. Check for mistakes.
Some(SidePanelResponse::new(SidePanelAction::Relays, connectivity_resp))
} else if home_resp.clicked() {
Some(SidePanelResponse::new(SidePanelAction::Home, home_resp))
} else if opt_messages_resp.as_ref().map_or(false, |r| r.clicked()) {
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Messages route variant is referenced in the side panel action handling but Route::Messages is not defined in the Route enum in route.rs. This will cause a compilation error when trying to navigate to messages.

Copilot uses AI. Check for mistakes.
@kernelkind
Copy link
Member

Couple issues I found glancing around:

  1. clicking on the side panel buttons without going back, and then going back all the way makes the contacts timeline go blank.
  2. if you click the back button before the animation has finished it doesn't go back
  3. the follow list view has incredibly poor performance. On android on a Pixel 9 pro loading elsat's contact list took 2.5 seconds on the first frame, took ~100 - 150 ms for about 80 frames and then stabilized around 50 ms after that
image

@jb55
Copy link
Contributor

jb55 commented Nov 20, 2025

i cherry-picked everything that wasn't a conflict:

Martti Malmi (6):
      add view as to profile dropdown menu
      app draggable by whole header area
      autofocus new post form
      follows list
      follows view
      fix warnings

i decided to not pick:

271f56095503 ("more neutral colored post button")

since it doesn't fit our theme. but maybe we can just make customizable themes in the future

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants