commit e436be400e12720f74e2943d145672c072a70e3c
parent 366ca24ac1d45cbe9e862d9d721bd9c73f7091b6
Author: Ken Sedgwick <ken@bonsai.com>
Date: Sat, 18 Jan 2025 12:53:30 -0800
add add relay GUI
Diffstat:
6 files changed, 121 insertions(+), 18 deletions(-)
diff --git a/assets/icons/add_relay_icon_4x.png b/assets/icons/add_relay_icon_4x.png
Binary files differ.
diff --git a/crates/enostr/src/relay/pool.rs b/crates/enostr/src/relay/pool.rs
@@ -286,6 +286,24 @@ impl RelayPool {
}
}
+ /// check whether a relay url is valid to add
+ pub fn is_valid_url(&self, url: &str) -> bool {
+ if url.is_empty() {
+ return false;
+ }
+ let url = match Url::parse(url) {
+ Ok(parsed_url) => parsed_url.to_string(),
+ Err(_err) => {
+ // debug!("bad relay url \"{}\": {:?}", url, err);
+ return false;
+ }
+ };
+ if self.has(&url) {
+ return false;
+ }
+ true
+ }
+
// Adds a websocket url to the RelayPool.
pub fn add_url(
&mut self,
diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs
@@ -291,7 +291,7 @@ fn render_nav_body(
}
Route::Relays => {
let manager = RelayPoolManager::new(ctx.pool);
- RelayView::new(manager).ui(ui);
+ RelayView::new(manager, &mut app.view_state.id_string_map).ui(ui);
None
}
Route::ComposeNote => {
diff --git a/crates/notedeck_columns/src/relay_pool_manager.rs b/crates/notedeck_columns/src/relay_pool_manager.rs
@@ -44,6 +44,11 @@ impl<'a> RelayPoolManager<'a> {
pub fn add_relay(&mut self, ctx: &egui::Context, relay_url: String) {
let _ = self.pool.add_url(relay_url, create_wakeup(ctx));
}
+
+ /// check whether a relay url is valid
+ pub fn is_valid_relay(&self, url: &str) -> bool {
+ self.pool.is_valid_url(url)
+ }
}
pub fn create_wakeup(ctx: &egui::Context) -> impl Fn() + Send + Sync + Clone + 'static {
diff --git a/crates/notedeck_columns/src/ui/add_column.rs b/crates/notedeck_columns/src/ui/add_column.rs
@@ -447,7 +447,7 @@ fn add_column_button() -> impl Widget {
sized_button("Add")
}
-fn sized_button(text: &str) -> impl Widget + '_ {
+pub(crate) fn sized_button(text: &str) -> impl Widget + '_ {
move |ui: &mut egui::Ui| -> egui::Response {
let painter = ui.painter();
let galley = painter.layout(
diff --git a/crates/notedeck_columns/src/ui/relay.rs b/crates/notedeck_columns/src/ui/relay.rs
@@ -1,12 +1,21 @@
+use std::collections::HashMap;
+
+use crate::colors::PINK;
use crate::relay_pool_manager::{RelayPoolManager, RelayStatus};
use crate::ui::{Preview, PreviewConfig, View};
-use egui::{Align, Button, Frame, Layout, Margin, Rgba, RichText, Rounding, Ui, Vec2};
+use egui::{Align, Button, Frame, Id, Image, Layout, Margin, Rgba, RichText, Rounding, Ui, Vec2};
use enostr::RelayPool;
use notedeck::NotedeckTextStyle;
+use tracing::debug;
+
+use super::add_column::sized_button;
+use super::padding;
+
pub struct RelayView<'a> {
manager: RelayPoolManager<'a>,
+ id_string_map: &'a mut HashMap<Id, String>,
}
impl View for RelayView<'_> {
@@ -19,13 +28,6 @@ impl View for RelayView<'_> {
RichText::new("Relays").text_style(NotedeckTextStyle::Heading2.text_style()),
);
});
-
- // TODO: implement manually adding relays
- // ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
- // if ui.add(add_relay_button()).clicked() {
- // // TODO: navigate to 'add relay view'
- // };
- // });
});
ui.add_space(8.0);
@@ -37,13 +39,20 @@ impl View for RelayView<'_> {
if let Some(indices) = self.show_relays(ui) {
self.manager.remove_relays(indices);
}
+ ui.add_space(8.0);
+ if let Some(add_relay) = self.show_add_relay_ui(ui) {
+ debug!("add relay \"{}\"", add_relay);
+ }
});
}
}
impl<'a> RelayView<'a> {
- pub fn new(manager: RelayPoolManager<'a>) -> Self {
- RelayView { manager }
+ pub fn new(manager: RelayPoolManager<'a>, id_string_map: &'a mut HashMap<Id, String>) -> Self {
+ RelayView {
+ manager,
+ id_string_map,
+ }
}
pub fn panel(&mut self, ui: &mut egui::Ui) {
@@ -102,6 +111,81 @@ impl<'a> RelayView<'a> {
indices_to_remove
}
+
+ const RELAY_PREFILL: &'static str = "wss://";
+
+ fn show_add_relay_ui(&mut self, ui: &mut Ui) -> Option<String> {
+ let id = ui.id().with("add-relay)");
+ match self.id_string_map.get(&id) {
+ None => {
+ ui.with_layout(Layout::top_down(Align::Min), |ui| {
+ let relay_button = add_relay_button();
+ if ui.add(relay_button).clicked() {
+ debug!("add relay clicked");
+ self.id_string_map
+ .insert(id, Self::RELAY_PREFILL.to_string());
+ };
+ });
+ None
+ }
+ Some(_) => {
+ ui.with_layout(Layout::top_down(Align::Min), |ui| {
+ self.add_relay_entry(ui, id)
+ })
+ .inner
+ }
+ }
+ }
+
+ pub fn add_relay_entry(&mut self, ui: &mut Ui, id: Id) -> Option<String> {
+ padding(16.0, ui, |ui| {
+ let text_buffer = self
+ .id_string_map
+ .entry(id)
+ .or_insert_with(|| Self::RELAY_PREFILL.to_string());
+ let is_enabled = self.manager.is_valid_relay(text_buffer);
+ let text_edit = egui::TextEdit::singleline(text_buffer)
+ .hint_text(
+ RichText::new("Enter the relay here")
+ .text_style(NotedeckTextStyle::Body.text_style()),
+ )
+ .vertical_align(Align::Center)
+ .desired_width(f32::INFINITY)
+ .min_size(Vec2::new(0.0, 40.0))
+ .margin(Margin::same(12.0));
+ ui.add(text_edit);
+ ui.add_space(8.0);
+ if ui
+ .add_sized(egui::vec2(50.0, 40.0), add_relay_button2(is_enabled))
+ .clicked()
+ {
+ self.id_string_map.remove(&id) // remove and return the value
+ } else {
+ None
+ }
+ })
+ .inner
+ }
+}
+
+fn add_relay_button() -> Button<'static> {
+ let img_data = egui::include_image!("../../../../assets/icons/add_relay_icon_4x.png");
+ let img = Image::new(img_data).fit_to_exact_size(Vec2::new(48.0, 48.0));
+ Button::image_and_text(
+ img,
+ RichText::new(" Add relay")
+ .size(16.0)
+ // TODO: this color should not be hard coded. Find some way to add it to the visuals
+ .color(PINK),
+ )
+ .frame(false)
+}
+
+fn add_relay_button2(is_enabled: bool) -> impl egui::Widget + 'static {
+ move |ui: &mut egui::Ui| -> egui::Response {
+ let button_widget = sized_button("Add");
+ ui.add_enabled(is_enabled, button_widget)
+ }
}
fn get_right_side_width(status: RelayStatus) -> f32 {
@@ -112,11 +196,6 @@ fn get_right_side_width(status: RelayStatus) -> f32 {
}
}
-#[allow(unused)]
-fn add_relay_button() -> egui::Button<'static> {
- Button::new("+ Add relay").min_size(Vec2::new(0.0, 32.0))
-}
-
fn delete_button(_dark_mode: bool) -> egui::Button<'static> {
/*
let img_data = if dark_mode {
@@ -201,7 +280,8 @@ mod preview {
impl App for RelayViewPreview {
fn update(&mut self, _app: &mut AppContext<'_>, ui: &mut egui::Ui) {
self.pool.try_recv();
- RelayView::new(RelayPoolManager::new(&mut self.pool)).ui(ui);
+ let mut id_string_map = HashMap::new();
+ RelayView::new(RelayPoolManager::new(&mut self.pool), &mut id_string_map).ui(ui);
}
}