notedeck

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

relay.rs (7924B)


      1 use crate::relay_pool_manager::{RelayPoolManager, RelayStatus};
      2 use crate::ui::{Preview, PreviewConfig, View};
      3 use egui::{Align, Button, Frame, Layout, Margin, Rgba, RichText, Rounding, Ui, Vec2};
      4 
      5 use enostr::RelayPool;
      6 use notedeck::NotedeckTextStyle;
      7 
      8 pub struct RelayView<'a> {
      9     manager: RelayPoolManager<'a>,
     10 }
     11 
     12 impl View for RelayView<'_> {
     13     fn ui(&mut self, ui: &mut egui::Ui) {
     14         ui.add_space(24.0);
     15 
     16         ui.horizontal(|ui| {
     17             ui.with_layout(Layout::left_to_right(Align::Center), |ui| {
     18                 ui.label(
     19                     RichText::new("Relays").text_style(NotedeckTextStyle::Heading2.text_style()),
     20                 );
     21             });
     22 
     23             // TODO: implement manually adding relays
     24             // ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
     25             //     if ui.add(add_relay_button()).clicked() {
     26             //         // TODO: navigate to 'add relay view'
     27             //     };
     28             // });
     29         });
     30 
     31         ui.add_space(8.0);
     32 
     33         egui::ScrollArea::vertical()
     34             .scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden)
     35             .auto_shrink([false; 2])
     36             .show(ui, |ui| {
     37                 if let Some(indices) = self.show_relays(ui) {
     38                     self.manager.remove_relays(indices);
     39                 }
     40             });
     41     }
     42 }
     43 
     44 impl<'a> RelayView<'a> {
     45     pub fn new(manager: RelayPoolManager<'a>) -> Self {
     46         RelayView { manager }
     47     }
     48 
     49     pub fn panel(&mut self, ui: &mut egui::Ui) {
     50         egui::CentralPanel::default().show(ui.ctx(), |ui| self.ui(ui));
     51     }
     52 
     53     /// Show the current relays, and returns the indices of relays the user requested to delete
     54     fn show_relays(&'a self, ui: &mut Ui) -> Option<Vec<usize>> {
     55         let mut indices_to_remove: Option<Vec<usize>> = None;
     56         for (index, relay_info) in self.manager.get_relay_infos().iter().enumerate() {
     57             ui.add_space(8.0);
     58             ui.vertical_centered_justified(|ui| {
     59                 relay_frame(ui).show(ui, |ui| {
     60                     ui.horizontal(|ui| {
     61                         ui.with_layout(Layout::left_to_right(Align::Center), |ui| {
     62                             Frame::none()
     63                                 // This frame is needed to add margin because the label will be added to the outer frame first and centered vertically before the connection status is added so the vertical centering isn't accurate.
     64                                 // TODO: remove this hack and actually center the url & status at the same time
     65                                 .inner_margin(Margin::symmetric(0.0, 4.0))
     66                                 .show(ui, |ui| {
     67                                     egui::ScrollArea::horizontal()
     68                                         .id_salt(index)
     69                                         .max_width(
     70                                             ui.max_rect().width()
     71                                                 - get_right_side_width(relay_info.status),
     72                                         ) // TODO: refactor to dynamically check the size of the 'right to left' portion and set the max width to be the screen width minus padding minus 'right to left' width
     73                                         .show(ui, |ui| {
     74                                             ui.label(
     75                                                 RichText::new(relay_info.relay_url)
     76                                                     .text_style(
     77                                                         NotedeckTextStyle::Monospace.text_style(),
     78                                                     )
     79                                                     .color(
     80                                                         ui.style()
     81                                                             .visuals
     82                                                             .noninteractive()
     83                                                             .fg_stroke
     84                                                             .color,
     85                                                     ),
     86                                             );
     87                                         });
     88                                 });
     89                         });
     90 
     91                         ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
     92                             if ui.add(delete_button(ui.visuals().dark_mode)).clicked() {
     93                                 indices_to_remove.get_or_insert_with(Vec::new).push(index);
     94                             };
     95 
     96                             show_connection_status(ui, relay_info.status);
     97                         });
     98                     });
     99                 });
    100             });
    101         }
    102 
    103         indices_to_remove
    104     }
    105 }
    106 
    107 fn get_right_side_width(status: &RelayStatus) -> f32 {
    108     match status {
    109         RelayStatus::Connected => 150.0,
    110         RelayStatus::Connecting => 160.0,
    111         RelayStatus::Disconnected => 175.0,
    112     }
    113 }
    114 
    115 #[allow(unused)]
    116 fn add_relay_button() -> egui::Button<'static> {
    117     Button::new("+ Add relay").min_size(Vec2::new(0.0, 32.0))
    118 }
    119 
    120 fn delete_button(_dark_mode: bool) -> egui::Button<'static> {
    121     /*
    122     let img_data = if dark_mode {
    123         egui::include_image!("../../assets/icons/delete_icon_4x.png")
    124     } else {
    125         // TODO: use light delete icon
    126         egui::include_image!("../../assets/icons/delete_icon_4x.png")
    127     };
    128     */
    129     let img_data = egui::include_image!("../../../../assets/icons/delete_icon_4x.png");
    130 
    131     egui::Button::image(egui::Image::new(img_data).max_width(10.0)).frame(false)
    132 }
    133 
    134 fn relay_frame(ui: &mut Ui) -> Frame {
    135     Frame::none()
    136         .inner_margin(Margin::same(8.0))
    137         .rounding(ui.style().noninteractive().rounding)
    138         .stroke(ui.style().visuals.noninteractive().bg_stroke)
    139 }
    140 
    141 fn show_connection_status(ui: &mut Ui, status: &RelayStatus) {
    142     let fg_color = match status {
    143         RelayStatus::Connected => ui.visuals().selection.bg_fill,
    144         RelayStatus::Connecting => ui.visuals().warn_fg_color,
    145         RelayStatus::Disconnected => ui.visuals().error_fg_color,
    146     };
    147     let bg_color = egui::lerp(Rgba::from(fg_color)..=Rgba::BLACK, 0.8).into();
    148 
    149     let label_text = match status {
    150         RelayStatus::Connected => "Connected",
    151         RelayStatus::Connecting => "Connecting...",
    152         RelayStatus::Disconnected => "Not Connected",
    153     };
    154 
    155     let frame = Frame::none()
    156         .rounding(Rounding::same(100.0))
    157         .fill(bg_color)
    158         .inner_margin(Margin::symmetric(12.0, 4.0));
    159 
    160     frame.show(ui, |ui| {
    161         ui.label(RichText::new(label_text).color(fg_color));
    162         ui.add(get_connection_icon(status));
    163     });
    164 }
    165 
    166 fn get_connection_icon(status: &RelayStatus) -> egui::Image<'static> {
    167     let img_data = match status {
    168         RelayStatus::Connected => {
    169             egui::include_image!("../../../../assets/icons/connected_icon_4x.png")
    170         }
    171         RelayStatus::Connecting => {
    172             egui::include_image!("../../../../assets/icons/connecting_icon_4x.png")
    173         }
    174         RelayStatus::Disconnected => {
    175             egui::include_image!("../../../../assets/icons/disconnected_icon_4x.png")
    176         }
    177     };
    178 
    179     egui::Image::new(img_data)
    180 }
    181 
    182 // PREVIEWS
    183 
    184 mod preview {
    185     use super::*;
    186     use crate::test_data::sample_pool;
    187 
    188     pub struct RelayViewPreview {
    189         pool: RelayPool,
    190     }
    191 
    192     impl RelayViewPreview {
    193         fn new() -> Self {
    194             RelayViewPreview {
    195                 pool: sample_pool(),
    196             }
    197         }
    198     }
    199 
    200     impl View for RelayViewPreview {
    201         fn ui(&mut self, ui: &mut egui::Ui) {
    202             self.pool.try_recv();
    203             RelayView::new(RelayPoolManager::new(&mut self.pool)).ui(ui);
    204         }
    205     }
    206 
    207     impl Preview for RelayView<'_> {
    208         type Prev = RelayViewPreview;
    209 
    210         fn preview(_cfg: PreviewConfig) -> Self::Prev {
    211             RelayViewPreview::new()
    212         }
    213     }
    214 }