relays/coverage.rs: - re-style coverage to spec

This commit is contained in:
Bu5hm4nn 2023-08-29 13:43:08 -10:00
parent caec82c41c
commit a35ca11794
5 changed files with 115 additions and 50 deletions

View File

@ -681,7 +681,6 @@ impl eframe::App for GossipUi {
let (mut submenu, header_response) = self.get_openable_menu(ui, SubMenu::Relays, "Relays");
submenu.show_body_indented(&header_response, ui, |ui| {
self.add_menu_item_page(ui, Page::RelaysActivityMonitor, "Active Relays");
self.add_menu_item_page(ui, Page::RelaysCoverage, "Coverage");
self.add_menu_item_page(ui, Page::RelaysMine, "My Relays");
self.add_menu_item_page(ui, Page::RelaysKnownNetwork, "Known Network");
ui.vertical(|ui| {

View File

@ -1,65 +1,127 @@
use egui_winit::egui::{Context, Ui, self, vec2, Response};
use nostr_types::PublicKey;
use egui_winit::egui::{Context, Ui, self, vec2, Response, RichText, Align, Id};
use nostr_types::{PublicKey, RelayUrl};
use crate::{globals::GLOBALS, ui::{GossipUi, widgets, Page, SettingsTab}, comms::ToOverlordMessage};
use crate::{globals::GLOBALS, ui::{GossipUi, widgets::{self, list_entry::{TEXT_TOP, TEXT_LEFT, self, draw_text_at, TEXT_RIGHT, allocate_text_at, draw_text_galley_at}}, Page, SettingsTab}, comms::ToOverlordMessage};
struct CoverageEntry<'a> {
pk: &'a PublicKey,
count: &'a usize,
_count: &'a usize,
relays: Vec<RelayUrl>,
name: String,
}
impl<'a> CoverageEntry<'a> {
pub(super) fn new(pk: &'a PublicKey, count: &'a usize) -> Self {
let name = GossipUi::display_name_from_pubkey_lookup(pk);
pub(super) fn new(pk: &'a PublicKey, name: String, _count: &'a usize, relays: Vec<RelayUrl>) -> Self {
Self {
pk,
count,
_count,
relays,
name
}
}
pub(super) fn show(&self, ui: &mut Ui) -> Response {
let (rect, _) = widgets::list_entry::allocate_space(ui, 45.0);
fn make_id(&self, str: &str) -> Id {
(self.pk.as_hex_string() + str).into()
}
widgets::list_entry::paint_frame(ui, &rect);
pub(super) fn show(&self, ui: &mut Ui, app: &mut GossipUi) -> Response {
let available_width = ui.available_size_before_wrap().x;
let (rect, response) = ui.allocate_exact_size(vec2(available_width, 80.0), egui::Sense::click());
let id = ui.auto_id_with(self.pk.as_hex_string());
let pos = rect.min + vec2(widgets::list_entry::TEXT_LEFT, widgets::list_entry::TEXT_TOP);
let (galley, response) = widgets::list_entry::allocate_text_at(
let color = if response.hovered() {
Some(ui.style().visuals.extreme_bg_color.linear_multiply(0.2))
} else {
None
};
widgets::list_entry::paint_frame(ui, &rect, color);
// ---- title ----
let pos = rect.min + vec2(TEXT_LEFT, TEXT_TOP);
draw_text_at(
ui,
pos,
self.name.clone().into(),
egui::Align::LEFT,
id);
RichText::new(self.name.clone()).size(list_entry::TITLE_FONT_SIZE).into(),
Align::LEFT,
Some(app.settings.theme.accent_color()),
None);
widgets::list_entry::draw_text_galley_at(
// ---- pubkey ----
// copy button
{
let pos = rect.right_top() + vec2(-TEXT_RIGHT, TEXT_TOP);
let text = RichText::new(crate::ui::widgets::COPY_SYMBOL);
let id = self.make_id("copy-pubkey");
let (galley, response) = allocate_text_at(ui, pos, text.into(), Align::RIGHT, id);
if response
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked() {
ui.output_mut(|o| {
o.copied_text = self.pk.as_bech32_string();
GLOBALS
.status_queue
.write()
.write("copied to clipboard".to_owned());
});
}
draw_text_galley_at(ui, pos, galley, None, None);
}
// pubkey
let pos = rect.right_top() + vec2(-TEXT_RIGHT - 20.0, TEXT_TOP);
draw_text_at(
ui,
pos,
galley,
None,
None);
widgets::list_entry::draw_text_at(
ui,
pos + vec2(response.rect.width(), 0.0),
format!(": coverage short by {} relay(s)", self.count).into(),
egui::Align::LEFT,
self.pk.as_bech32_string().into(),
Align::RIGHT,
None,
None);
let response = response
.on_hover_text(format!("Go to profile of {}", self.name))
.on_hover_cursor(egui::CursorIcon::PointingHand);
// ---- connected relays ----
let pos = rect.min + vec2(TEXT_LEFT, TEXT_TOP + 30.0);
let relays_string = self.relays.iter().map(|f| f.to_string()).collect::<Vec<String>>().join(", ");
draw_text_at(
ui,
pos,
relays_string.into(),
Align::LEFT,
None,
None);
response
}
}
fn find_relays_for_pubkey(pk: &PublicKey) -> Vec<RelayUrl> {
GLOBALS.relay_picker.relay_assignments_iter()
.filter(|f| f.pubkeys.contains(pk))
.map(|f| f.relay_url.clone())
.collect()
}
pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) {
ui.add_space(10.0);
ui.horizontal_wrapped(|ui| {
ui.heading("Coverage Report");
ui.heading(format!("Low Coverage Report (less than {} relays)", app.settings.num_relays_per_person));
ui.add_space(10.0);
ui.with_layout(egui::Layout::right_to_left(egui::Align::Min), |ui| {
ui.add_space(20.0);
ui.spacing_mut().button_padding *= 2.0;
{
let visuals = ui.visuals_mut();
visuals.widgets.inactive.weak_bg_fill = app.settings.theme.accent_color();
visuals.widgets.inactive.fg_stroke.width = 1.0;
visuals.widgets.inactive.fg_stroke.color = app.settings.theme.get_style().visuals.extreme_bg_color;
visuals.widgets.hovered.weak_bg_fill = app.settings.theme.navigation_text_color();
visuals.widgets.hovered.fg_stroke.color = app.settings.theme.accent_color();
visuals.widgets.inactive.fg_stroke.color = app.settings.theme.get_style().visuals.extreme_bg_color;
}
if ui.button("Pick Relays Again")
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked() {
let _ = GLOBALS.to_overlord.send(ToOverlordMessage::PickRelays);
}
});
});
ui.add_space(10.0);
ui.horizontal_wrapped(|ui| {
@ -69,8 +131,6 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr
app.set_page(Page::Settings);
}
});
ui.add_space(10.0);
if GLOBALS.relay_picker.pubkey_counts_iter().count() > 0 {
ui.label(
format!("The Relay-Picker has tried to connect to at least {} relays \
@ -78,11 +138,6 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr
You can manually ask the Relay-Picker to pick again, however most of the time it has already \
tried its best.", app.settings.num_relays_per_person));
ui.add_space(10.0);
if ui.link("Pick Again").clicked() {
let _ = GLOBALS.to_overlord.send(ToOverlordMessage::PickRelays);
}
ui.add_space(10.0);
let id_source = ui.auto_id_with("relay-coverage-scroll");
egui::ScrollArea::vertical()
@ -91,12 +146,20 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr
for elem in GLOBALS.relay_picker.pubkey_counts_iter() {
let pk = elem.key();
let count = elem.value();
let name = GossipUi::display_name_from_pubkey_lookup(pk);
let relays = find_relays_for_pubkey(pk);
let hover_text = format!("Go to profile of {}", name);
let entry = CoverageEntry::new(pk, count);
if entry.show(ui).clicked() {
let entry = CoverageEntry::new(pk, name, count, relays);
if entry.show(ui, app)
.on_hover_text(hover_text)
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
app.set_page(Page::Person(*pk));
}
}
// uncomment below to mock with people entries for development
// for pk in GLOBALS.people.get_followed_pubkeys() {
// let entry = CoverageEntry::new(&pk, &0);
// if entry.show(ui).clicked() {

View File

@ -17,6 +17,8 @@ pub(crate) const TEXT_LEFT: f32 = 20.0;
pub(crate) const TEXT_RIGHT: f32 = 25.0;
/// Start of text (excl. outer margin): top
pub(crate) const TEXT_TOP: f32 = 15.0;
/// Title font size
pub(crate) const TITLE_FONT_SIZE: f32 = 16.5;
/// Thickness of separator
const HLINE_THICKNESS: f32 = 1.5;
@ -27,12 +29,12 @@ pub(crate) fn allocate_space(ui: &mut Ui, height: f32) -> (Rect, Response) {
ui.allocate_exact_size(vec2(available_width, height), Sense::hover())
}
pub(crate) fn paint_frame(ui: &mut Ui, rect: &Rect) {
pub(crate) fn paint_frame(ui: &mut Ui, rect: &Rect, fill: Option<Color32>) {
let frame_rect = Rect::from_min_max(
rect.min + vec2(OUTER_MARGIN_LEFT, OUTER_MARGIN_TOP),
rect.max - vec2(OUTER_MARGIN_RIGHT, OUTER_MARGIN_BOTTOM),
);
let fill = ui.style().visuals.extreme_bg_color;
let fill = fill.unwrap_or(ui.style().visuals.extreme_bg_color);
ui.painter().add(epaint::RectShape {
rect: frame_rect,
rounding: Rounding::same(5.0),

View File

@ -21,6 +21,9 @@ pub use relay_entry::{RelayEntry, RelayEntryView};
// ui.label(job.job);
// }
/// Copy symbol for copy button
pub(crate) const COPY_SYMBOL: &str = "\u{1F4CB}";
pub fn break_anywhere_hyperlink_to(ui: &mut Ui, text: impl Into<WidgetText>, url: impl ToString) {
let mut job = text.into().into_text_job(
ui.style(),

View File

@ -43,8 +43,6 @@ const USAGE_LINE_X_END: f32 = -10.0;
const USAGE_LINE_THICKNESS: f32 = 1.0;
/// Spacing between nip11 text rows
const NIP11_Y_SPACING: f32 = 20.0;
/// Copy symbol for nip11 items copy button
const COPY_SYMBOL: &str = "\u{2398}";
/// Status symbol for status color indicator
const STATUS_SYMBOL: &str = "\u{25CF}";
/// Space reserved for status symbol before title
@ -223,7 +221,7 @@ impl RelayEntry {
if self.relay.url.0.len() > TITLE_MAX_LEN {
title.push('\u{2026}'); // append ellipsis
}
let text = RichText::new(title).size(16.5);
let text = RichText::new(title).size(list_entry::TITLE_FONT_SIZE);
let pos = rect.min + vec2(TEXT_LEFT + STATUS_SYMBOL_SPACE, TEXT_TOP);
let rect = draw_text_at(ui, pos, text.into(), Align::LEFT, Some(self.accent), None);
ui.interact(rect, ui.next_auto_id(), Sense::hover())
@ -601,7 +599,7 @@ impl RelayEntry {
let rect = draw_text_at(ui, pos, contact.into(), align, None, None);
let id = self.make_id("copy_nip11_contact");
let pos = pos + vec2(rect.width() + ui.spacing().item_spacing.x, 0.0);
let text = RichText::new(COPY_SYMBOL);
let text = RichText::new(crate::ui::widgets::COPY_SYMBOL);
let (galley, response) = allocate_text_at(ui, pos, text.into(), align, id);
if response.clicked() {
ui.output_mut(|o| {
@ -634,7 +632,7 @@ impl RelayEntry {
let rect = draw_text_at(ui, pos, npub.clone().into(), align, None, None);
let id = self.make_id("copy_nip11_npub");
let pos = pos + vec2(rect.width() + ui.spacing().item_spacing.x, 0.0);
let text = RichText::new(COPY_SYMBOL);
let text = RichText::new(crate::ui::widgets::COPY_SYMBOL);
let (galley, response) = allocate_text_at(ui, pos, text.into(), align, id);
if response.clicked() {
ui.output_mut(|o| {
@ -1035,7 +1033,7 @@ impl RelayEntry {
// all the heavy lifting is only done if it's actually visible
if ui.is_rect_visible(rect) {
list_entry::paint_frame(ui, &rect);
list_entry::paint_frame(ui, &rect, None);
self.paint_title(ui, &rect);
response |= self.paint_edit_btn(ui, &rect);
if self.relay.usage_bits != 0 {
@ -1052,7 +1050,7 @@ impl RelayEntry {
// all the heavy lifting is only done if it's actually visible
if ui.is_rect_visible(rect) {
list_entry::paint_frame(ui, &rect);
list_entry::paint_frame(ui, &rect, None);
self.paint_title(ui, &rect);
response |= self.paint_edit_btn(ui, &rect);
self.paint_stats(ui, &rect);
@ -1070,7 +1068,7 @@ impl RelayEntry {
// all the heavy lifting is only done if it's actually visible
if ui.is_rect_visible(rect) {
list_entry::paint_frame(ui, &rect);
list_entry::paint_frame(ui, &rect, None);
self.paint_title(ui, &rect);
self.paint_stats(ui, &rect);
paint_hline(ui, &rect, HLINE_1_Y_OFFSET);