notedeck

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

relay.rs (7809B)


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