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 }