notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

top_buttons.rs (4052B)


      1 /// Top buttons UI for the Dave chat interface.
      2 ///
      3 /// Contains the profile picture button, settings button, and session list toggle
      4 /// that appear at the top of the chat view.
      5 use super::DaveAction;
      6 use nostrdb::{Ndb, Transaction};
      7 use notedeck::{Accounts, AppContext, Images, MediaJobSender};
      8 use notedeck_ui::{app_images, ProfilePic};
      9 
     10 /// Result from rendering top buttons, includes action and layout info
     11 pub struct TopButtonsResult {
     12     pub action: Option<DaveAction>,
     13     /// X position after the last button (for placing inline content)
     14     pub right_edge_x: f32,
     15     /// Y position of the button row
     16     pub y: f32,
     17 }
     18 
     19 /// Render the top buttons UI (profile pic, settings, session list toggle).
     20 /// `status_dot` optionally paints a colored dot on the hamburger icon to
     21 /// indicate what kind of attention the session needs (blue = working,
     22 /// yellow = needs input, red = error).
     23 pub fn top_buttons_ui(
     24     app_ctx: &mut AppContext,
     25     ui: &mut egui::Ui,
     26     status_dot: Option<egui::Color32>,
     27 ) -> TopButtonsResult {
     28     let mut action: Option<DaveAction> = None;
     29     let mut rect = ui.available_rect_before_wrap();
     30     rect = rect.translate(egui::vec2(20.0, 20.0));
     31     rect.set_height(32.0);
     32     rect.set_width(32.0);
     33 
     34     // Show session list button on mobile/narrow screens
     35     if notedeck::ui::is_narrow(ui.ctx()) {
     36         let r = ui
     37             .put(rect, egui::Button::new("\u{2630}").frame(false))
     38             .on_hover_text("Show chats")
     39             .on_hover_cursor(egui::CursorIcon::PointingHand);
     40 
     41         // Draw notification dot when something needs attention
     42         if let Some(color) = status_dot {
     43             let dot_center = rect.right_top() + egui::vec2(-2.0, 6.0);
     44             ui.painter().circle_filled(dot_center, 4.0, color);
     45         }
     46 
     47         if r.clicked() {
     48             action = Some(DaveAction::ShowSessionList);
     49         }
     50 
     51         rect = rect.translate(egui::vec2(30.0, 0.0));
     52     }
     53 
     54     let txn = Transaction::new(app_ctx.ndb).unwrap();
     55     let r = ui
     56         .put(
     57             rect,
     58             &mut pfp_button(
     59                 &txn,
     60                 app_ctx.accounts,
     61                 app_ctx.img_cache,
     62                 app_ctx.ndb,
     63                 app_ctx.media_jobs.sender(),
     64             ),
     65         )
     66         .on_hover_cursor(egui::CursorIcon::PointingHand);
     67 
     68     if r.clicked() {
     69         action = Some(DaveAction::ToggleChrome);
     70     }
     71 
     72     // Settings button
     73     rect = rect.translate(egui::vec2(30.0, 0.0));
     74     let dark_mode = ui.visuals().dark_mode;
     75     let r = ui
     76         .put(rect, settings_button(dark_mode))
     77         .on_hover_cursor(egui::CursorIcon::PointingHand);
     78 
     79     if r.clicked() {
     80         action = Some(DaveAction::OpenSettings);
     81     }
     82 
     83     TopButtonsResult {
     84         action,
     85         right_edge_x: rect.right() + 8.0,
     86         y: rect.min.y,
     87     }
     88 }
     89 
     90 fn settings_button(dark_mode: bool) -> impl egui::Widget {
     91     move |ui: &mut egui::Ui| {
     92         let img_size = 24.0;
     93         let max_size = 32.0;
     94 
     95         let img = if dark_mode {
     96             app_images::settings_dark_image()
     97         } else {
     98             app_images::settings_light_image()
     99         }
    100         .max_width(img_size);
    101 
    102         let helper = notedeck_ui::anim::AnimationHelper::new(
    103             ui,
    104             "settings-button",
    105             egui::vec2(max_size, max_size),
    106         );
    107 
    108         let cur_img_size = helper.scale_1d_pos(img_size);
    109         img.paint_at(
    110             ui,
    111             helper
    112                 .get_animation_rect()
    113                 .shrink((max_size - cur_img_size) / 2.0),
    114         );
    115 
    116         helper.take_animation_response()
    117     }
    118 }
    119 
    120 fn pfp_button<'me, 'a>(
    121     txn: &'a Transaction,
    122     accounts: &Accounts,
    123     img_cache: &'me mut Images,
    124     ndb: &Ndb,
    125     jobs: &'me MediaJobSender,
    126 ) -> ProfilePic<'me, 'a> {
    127     let account = accounts.get_selected_account();
    128     let profile = ndb
    129         .get_profile_by_pubkey(txn, account.key.pubkey.bytes())
    130         .ok();
    131 
    132     ProfilePic::from_profile_or_default(img_cache, jobs, profile.as_ref())
    133         .size(24.0)
    134         .sense(egui::Sense::click())
    135 }