From 510896935e998aeee4064b6deaa97531f013c044 Mon Sep 17 00:00:00 2001 From: Bu5hm4nn <“bu5hm4nn@users.noreply.github.com”> Date: Wed, 6 Sep 2023 17:33:49 -0400 Subject: [PATCH 01/46] relay lists: restyle option drop down --- src/ui/relays/mod.rs | 37 +++++++++++++++++++++++++++---------- src/ui/theme/classic.rs | 19 +++++++++++++++++++ src/ui/theme/default.rs | 19 +++++++++++++++++++ src/ui/theme/mod.rs | 8 ++++++++ src/ui/theme/roundy.rs | 19 +++++++++++++++++++ src/ui/widgets/mod.rs | 2 ++ 6 files changed, 94 insertions(+), 10 deletions(-) diff --git a/src/ui/relays/mod.rs b/src/ui/relays/mod.rs index 0230048a..e1669111 100644 --- a/src/ui/relays/mod.rs +++ b/src/ui/relays/mod.rs @@ -1,8 +1,8 @@ use std::cmp::Ordering; -use super::{GossipUi, Page}; +use super::{GossipUi, Page, widgets}; use crate::{comms::ToOverlordMessage, globals::GLOBALS, relay::Relay}; -use eframe::egui; +use eframe::{egui, epaint::PathShape}; use egui::{Context, Ui}; use egui_winit::egui::{vec2, Id, Rect, RichText}; use nostr_types::RelayUrl; @@ -468,9 +468,8 @@ pub(super) fn configure_list_btn(app: &mut GossipUi, ui: &mut Ui) { app.relays.configure_list_menu_active ^= true; } - let mut seen_on_popup_position = response.rect.center_bottom(); - seen_on_popup_position.x -= 150.0; - seen_on_popup_position.y += 18.0; // drop below the icon itself + let button_center_bottom = response.rect.center_bottom(); + let seen_on_popup_position = button_center_bottom + vec2( -150.0, widgets::DROPDOWN_DISTANCE ); let id: Id = "configure-list-menu".into(); let mut frame = egui::Frame::popup(ui.style()); @@ -482,14 +481,32 @@ pub(super) fn configure_list_btn(app: &mut GossipUi, ui: &mut Ui) { .constrain(true); if app.relays.configure_list_menu_active { let menuresp = area.show(ui.ctx(), |ui| { - frame.fill = ui.visuals().extreme_bg_color; + frame.fill = app.settings.theme.accent_color(); + frame.stroke = egui::Stroke::NONE; + // frame.shadow = egui::epaint::Shadow::NONE; frame.inner_margin = egui::Margin::symmetric(20.0, 10.0); frame.show(ui, |ui| { + let path = PathShape::convex_polygon( + [ button_center_bottom, + button_center_bottom + vec2(widgets::DROPDOWN_DISTANCE, widgets::DROPDOWN_DISTANCE), + button_center_bottom + vec2(-widgets::DROPDOWN_DISTANCE, widgets::DROPDOWN_DISTANCE)] + .to_vec(), + app.settings.theme.accent_color(), + egui::Stroke::NONE); + ui.painter().add(path); let size = ui.spacing().interact_size.y * egui::vec2(1.6, 0.8); - crate::ui::components::switch_with_size(ui, &mut app.relays.show_details, size); - ui.label("Show details"); - crate::ui::components::switch_with_size(ui, &mut app.relays.show_hidden, size); - ui.label("Show hidden relays"); + + // since we are displaying over an accent color background, load that style + *ui.style_mut() = app.settings.theme.get_on_accent_style(); + + ui.horizontal(|ui|{ + crate::ui::components::switch_with_size(ui, &mut app.relays.show_details, size); + ui.label("Show details"); + }); + ui.horizontal(|ui|{ + crate::ui::components::switch_with_size(ui, &mut app.relays.show_hidden, size); + ui.label("Show hidden relays"); + }); }); }); if menuresp.response.clicked_elsewhere() && !response.clicked() { diff --git a/src/ui/theme/classic.rs b/src/ui/theme/classic.rs index e1e4c1ee..7eeceb80 100644 --- a/src/ui/theme/classic.rs +++ b/src/ui/theme/classic.rs @@ -272,6 +272,25 @@ impl ThemeDef for ClassicTheme { style } + /// the style to use when displaying on-top of an accent-colored background + fn get_on_accent_style(dark_mode: bool) -> Style { + let mut style = Self::get_style(!dark_mode); + if dark_mode { + todo!() + } else { + style.visuals.widgets.noninteractive.fg_stroke.color = Color32::WHITE; + style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); + style.visuals.widgets.inactive.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); + style.visuals.widgets.active.bg_fill = Color32::from_black_alpha(20); + style.visuals.widgets.active.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); + style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(8); + style.visuals.widgets.hovered.fg_stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); + style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); + style.visuals.selection.stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); + } + style + } + fn font_definitions() -> FontDefinitions { super::font_definitions() // use default gossip font definitions } diff --git a/src/ui/theme/default.rs b/src/ui/theme/default.rs index f16ebee4..d823dd12 100644 --- a/src/ui/theme/default.rs +++ b/src/ui/theme/default.rs @@ -272,6 +272,25 @@ impl ThemeDef for DefaultTheme { style } + /// the style to use when displaying on-top of an accent-colored background + fn get_on_accent_style(dark_mode: bool) -> Style { + let mut style = Self::get_style(!dark_mode); + if dark_mode { + todo!() + } else { + style.visuals.widgets.noninteractive.fg_stroke.color = Color32::WHITE; + style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); + style.visuals.widgets.inactive.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); + style.visuals.widgets.active.bg_fill = Color32::from_black_alpha(20); + style.visuals.widgets.active.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); + style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(8); + style.visuals.widgets.hovered.fg_stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); + style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); + style.visuals.selection.stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); + } + style + } + fn font_definitions() -> FontDefinitions { super::font_definitions() // use default gossip font definitions } diff --git a/src/ui/theme/mod.rs b/src/ui/theme/mod.rs index dceb9368..bc4d12db 100644 --- a/src/ui/theme/mod.rs +++ b/src/ui/theme/mod.rs @@ -93,6 +93,12 @@ macro_rules! theme_dispatch { } } + pub fn get_on_accent_style(&self) -> Style { + match self.variant { + $( $variant => $class::get_on_accent_style(self.dark_mode), )+ + } + } + pub fn font_definitions(&self) -> FontDefinitions { match self.variant { $( $variant => $class::font_definitions(), )+ @@ -342,6 +348,8 @@ pub trait ThemeDef: Send + Sync { // These styles are used by egui by default for widgets if you don't override them // in place. fn get_style(dark_mode: bool) -> Style; + /// the style to use when displaying ontop an accent-colored background + fn get_on_accent_style(dark_mode: bool) -> Style; fn font_definitions() -> FontDefinitions; fn text_styles() -> BTreeMap; diff --git a/src/ui/theme/roundy.rs b/src/ui/theme/roundy.rs index 0630c372..2ae90d39 100644 --- a/src/ui/theme/roundy.rs +++ b/src/ui/theme/roundy.rs @@ -278,6 +278,25 @@ impl ThemeDef for RoundyTheme { style } + /// the style to use when displaying on-top of an accent-colored background + fn get_on_accent_style(dark_mode: bool) -> Style { + let mut style = Self::get_style(!dark_mode); + if dark_mode { + todo!() + } else { + style.visuals.widgets.noninteractive.fg_stroke.color = Color32::WHITE; + style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); + style.visuals.widgets.inactive.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); + style.visuals.widgets.active.bg_fill = Color32::from_black_alpha(20); + style.visuals.widgets.active.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); + style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(8); + style.visuals.widgets.hovered.fg_stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); + style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); + style.visuals.selection.stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); + } + style + } + fn font_definitions() -> FontDefinitions { super::font_definitions() // use default gossip font definitions } diff --git a/src/ui/widgets/mod.rs b/src/ui/widgets/mod.rs index 2a7cf01d..6d0fb0a9 100644 --- a/src/ui/widgets/mod.rs +++ b/src/ui/widgets/mod.rs @@ -11,6 +11,8 @@ use eframe::egui::widgets::TextEdit; use eframe::egui::{FontSelection, Ui, WidgetText}; use egui_winit::egui::{vec2, Rect, Response, Sense}; +pub const DROPDOWN_DISTANCE: f32 = 10.0; + // pub fn break_anywhere_label(ui: &mut Ui, text: impl Into) { // let mut job = text.into().into_text_job( // ui.style(), From 0f95f9e9411f2a6d170334d0a266392cd2688054 Mon Sep 17 00:00:00 2001 From: Bu5hm4nn <“bu5hm4nn@users.noreply.github.com”> Date: Thu, 7 Sep 2023 22:43:45 -0400 Subject: [PATCH 02/46] relay lists: hide hover text when dropdown open --- src/ui/relays/mod.rs | 9 ++++++--- src/ui/theme/mod.rs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ui/relays/mod.rs b/src/ui/relays/mod.rs index a37e2dea..b2d7bbda 100644 --- a/src/ui/relays/mod.rs +++ b/src/ui/relays/mod.rs @@ -448,9 +448,12 @@ fn entry_dialog_step2(ui: &mut Ui, app: &mut GossipUi) { /// pub(super) fn configure_list_btn(app: &mut GossipUi, ui: &mut Ui) { let (response, painter) = ui.allocate_painter(vec2(20.0, 20.0), egui::Sense::click()); - let response = response - .on_hover_cursor(egui::CursorIcon::PointingHand) - .on_hover_text("Configure List View"); + let response = response.on_hover_cursor(egui::CursorIcon::PointingHand); + let response = if !app.relays.configure_list_menu_active { + response.on_hover_text("Configure List View") + } else { + response + }; let btn_rect = response.rect; let color = if response.hovered() { app.settings.theme.accent_color() diff --git a/src/ui/theme/mod.rs b/src/ui/theme/mod.rs index bc4d12db..2a1403af 100644 --- a/src/ui/theme/mod.rs +++ b/src/ui/theme/mod.rs @@ -348,7 +348,7 @@ pub trait ThemeDef: Send + Sync { // These styles are used by egui by default for widgets if you don't override them // in place. fn get_style(dark_mode: bool) -> Style; - /// the style to use when displaying ontop an accent-colored background + /// the style to use when displaying on-top of an accent-colored background fn get_on_accent_style(dark_mode: bool) -> Style; fn font_definitions() -> FontDefinitions; From de7f44827048c353912ad8e7d81471f672e81415 Mon Sep 17 00:00:00 2001 From: Bu5hm4nn Date: Sun, 24 Sep 2023 17:22:14 -0600 Subject: [PATCH 03/46] relay drop down: don't crash on dark mode, show what the default would have --- src/ui/theme/default.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/theme/default.rs b/src/ui/theme/default.rs index f1d27c01..dd9b009f 100644 --- a/src/ui/theme/default.rs +++ b/src/ui/theme/default.rs @@ -276,7 +276,7 @@ impl ThemeDef for DefaultTheme { fn get_on_accent_style(dark_mode: bool) -> Style { let mut style = Self::get_style(!dark_mode); if dark_mode { - todo!() + // TODO style dark mode } else { style.visuals.widgets.noninteractive.fg_stroke.color = Color32::WHITE; style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); From 30de6e02e7f671b0380f3a22249c99dbe40928a1 Mon Sep 17 00:00:00 2001 From: Bu5hm4nn Date: Tue, 26 Sep 2023 19:58:26 -0600 Subject: [PATCH 04/46] Relay Lists: Update configure dropdown styling (rounding, text colors and position) --- src/ui/relays/mod.rs | 3 ++- src/ui/theme/default.rs | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ui/relays/mod.rs b/src/ui/relays/mod.rs index e3e7d347..dfb715a7 100644 --- a/src/ui/relays/mod.rs +++ b/src/ui/relays/mod.rs @@ -473,7 +473,7 @@ pub(super) fn configure_list_btn(app: &mut GossipUi, ui: &mut Ui) { } let button_center_bottom = response.rect.center_bottom(); - let seen_on_popup_position = button_center_bottom + vec2( -150.0, widgets::DROPDOWN_DISTANCE ); + let seen_on_popup_position = button_center_bottom + vec2( -180.0, widgets::DROPDOWN_DISTANCE ); let id: Id = "configure-list-menu".into(); let mut frame = egui::Frame::popup(ui.style()); @@ -488,6 +488,7 @@ pub(super) fn configure_list_btn(app: &mut GossipUi, ui: &mut Ui) { frame.fill = app.settings.theme.accent_color(); frame.stroke = egui::Stroke::NONE; // frame.shadow = egui::epaint::Shadow::NONE; + frame.rounding = egui::Rounding::same(5.0); frame.inner_margin = egui::Margin::symmetric(20.0, 10.0); frame.show(ui, |ui| { let path = PathShape::convex_polygon( diff --git a/src/ui/theme/default.rs b/src/ui/theme/default.rs index dd9b009f..4872f3ee 100644 --- a/src/ui/theme/default.rs +++ b/src/ui/theme/default.rs @@ -280,11 +280,11 @@ impl ThemeDef for DefaultTheme { } else { style.visuals.widgets.noninteractive.fg_stroke.color = Color32::WHITE; style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.inactive.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); + style.visuals.widgets.inactive.fg_stroke.color = Self::navigation_text_color(dark_mode); style.visuals.widgets.active.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.active.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); + style.visuals.widgets.active.fg_stroke.color = Self::navigation_text_active_color(dark_mode); style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(8); - style.visuals.widgets.hovered.fg_stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); + style.visuals.widgets.hovered.fg_stroke.color = Self::navigation_text_hover_color(dark_mode); style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); style.visuals.selection.stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); } From e09b0f1aed0c45a3da56d2d761e7c9eec958f09e Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Thu, 5 Oct 2023 08:07:05 +0200 Subject: [PATCH 05/46] Add vscode to ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3a5d1af0..09ab3eab 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ perf.data perf.data.old flamegraph.svg +.vscode/ From ab0c1ea42ddac40dd6dac6c0e3cf9bf27efcfd0e Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Thu, 5 Oct 2023 08:17:18 +0200 Subject: [PATCH 06/46] Move doc into folder and improve markdown --- README.md | 45 +++++++++++++-------------- DEVELOPING.md => docs/DEVELOPING.md | 15 +++++---- PERFORMANCE.md => docs/PERFORMANCE.md | 2 +- 3 files changed, 32 insertions(+), 30 deletions(-) rename DEVELOPING.md => docs/DEVELOPING.md (94%) rename PERFORMANCE.md => docs/PERFORMANCE.md (96%) diff --git a/README.md b/README.md index f7c06c1d..3a28b804 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Gossip -## Gossip is a desktop client for nostr. +## Gossip is a desktop client for NOSTR -Nostr is an open social media protocol empowering lots of software such as this client. The experience is kind of like Twitter except that you control your own account, and you can post to many different independent places called "relays". People are finding many additional uses for nostr that go far beyond micro-blogging or chatting, but this client is focused on those. +Nostr is an open social media protocol empowering lots of software such as this client. The experience is kind of like Twitter except that you control your own account, and you can post to many different independent places called "relays". People are finding many additional uses for NOSTR that go far beyond micro-blogging or chatting, but this client is focused on those. Nostr stands for "Notes and Other Stuff Transmitted by Relays." @@ -91,8 +91,8 @@ The following features make gossip different than most other nostr clients so fa If when you pull gossip it doesn't pull cleanly, I may have done a rare force-push. Run these commands to reset your master branch: ````bash -$ git fetch -$ git reset --hard origin/master +git fetch +git reset --hard origin/master ```` ### Step 1 - Install Rust @@ -112,25 +112,25 @@ Most dependencies are probably already installed in your base operating system. #### macOS -a. Install rust with rust-up: https://rustup.rs/ -b. Install homebrew if you don't have it yet https://brew.sh/ +a. Install rust with rust-up: +b. Install homebrew if you don't have it yet c. Install these dependencies: -``` +```bash brew install cmake sdl2 pkg-config ffmpeg ``` ### Step 3 - Clone this Repository ````bash -$ git clone https://github.com/mikedilger/gossip +git clone https://github.com/mikedilger/gossip ```` ### Step 4 - Compile ````bash -$ cd gossip -$ cargo build --release +cd gossip +cargo build --release ```` The output will be a binary executable in `target/release/gossip` @@ -140,7 +140,7 @@ This binary should be portable to similar systems with similar hardware and oper If you want a binary optimized for your exact processor with the newest features enabled: ````bash -$ RUSTFLAGS="-C target-cpu=native --cfg tokio_unstable" cargo build --release +RUSTFLAGS="-C target-cpu=native --cfg tokio_unstable" cargo build --release ```` Everything gossip needs (fonts, icons) is baked into this executable. It doesn't need to find assets. So you can move it and run it from anywhere. @@ -148,7 +148,7 @@ Everything gossip needs (fonts, icons) is baked into this executable. It doesn't To make the binary smaller, ````bash -$ strip gossip +strip gossip ```` ### Step 5 - Do it all again @@ -156,10 +156,10 @@ $ strip gossip The `master` branch changes quickly. When you want to update, do it all again, something like this: ````bash -$ git pull -$ cargo build --release -$ strip ./target/release/gossip -$ ./target/release/gossip +git pull +cargo build --release +strip ./target/release/gossip +./target/release/gossip ```` ## Compile Options @@ -179,7 +179,6 @@ If you wish to switch to your native TLS provider, use the following compile opt ### Language Support - #### Chinese, Japanese and Korean character sets Gossip by default does not include the CJK font because it is larger than all other languages put together, and most gossip users don't recognize those characters. If you do recognize such characters, you can compile in that font with: @@ -206,7 +205,7 @@ Compile with ### Performance issues -If you are having performance issues, please see [PERFORMANCE.md](PERFORMANCE.md). +If you are having performance issues, please see [PERFORMANCE.md](docs/PERFORMANCE.md). ## Technology Involved @@ -220,11 +219,11 @@ If you are having performance issues, please see [PERFORMANCE.md](PERFORMANCE.md ## License - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +MIT license ([LICENSE-MIT](LICENSE-MIT) or ) ### Contribution -All contributions welcome, please check the [development guidelines](DEVELOPING.md) before starting to code. +All contributions welcome, please check the [development guidelines](docs/DEVELOPING.md) before starting to code. Anyone interested in replacing the GUI with something much better, or keeping it as egui but making it much better, would be greatly appreciated. @@ -232,13 +231,13 @@ Unless you explicitly state otherwise, any contribution intentionally submitted ## On Nostr -### The official gossip account: +### The official gossip account nprofile1qqsrjerj9rhamu30sjnuudk3zxeh3njl852mssqng7z4up9jfj8yupqpzamhxue69uhhyetvv9ujumn0wd68ytnfdenx7tcpz4mhxue69uhkummnw3ezummcw3ezuer9wchszxmhwden5te0dehhxarj9ekkj6m9v35kcem9wghxxmmd9uq3xamnwvaz7tm0venxx6rpd9hzuur4vghsz8nhwden5te0dehhxarj94c82c3wwajkcmr0wfjx2u3wdejhgtcsfx2xk npub189j8y280mhezlp98ecmdzydn0r8970g4hpqpx3u9tcztynywfczqqr3tg8 -### Mike Dilger: +### Mike Dilger nprofile1qqswuyd9ml6qcxd92h6pleptfrcqucvvjy39vg4wx7mv9wm8kakyujgpzamhxue69uhhyetvv9ujumn0wd68ytnfdenx7tcprpmhxue69uhkzapwdehhxarjwahhy6mn9e3k7mf0qyt8wumn8ghj7etyv4hzumn0wd68ytnvv9hxgtcprdmhxue69uhkummnw3ezumtfddjkg6tvvajhytnrdakj7qgnwaehxw309ahkvenrdpskjm3wwp6kytcpremhxue69uhkummnw3ez6ur4vgh8wetvd3hhyer9wghxuet59uq32amnwvaz7tmwdaehgu3wdau8gu3wv3jhvtct8l34m @@ -248,4 +247,4 @@ You can also my NIP-05 address of `mike@mikedilger.com` which will also hook you I'd prefer if you trusted `mike@mikedilger.com` higher than my public key at this point in time since key management is still pretty bad. That is the inverse of the normal recommendation, but my private key has not been treated very carefully as I never intended it to be my long-term keypair (it just became that over time). Also, I fully intend to rollover my keys once gossip supports the key-rollover NIP, whatever that is (or will be). -You can tip me at my Bitcoin Lighting address: decentbun13@walletofsatoshi.com == lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkgetrv4h8gcn4dccnxv563ep +You can tip me at my Bitcoin Lighting address: == lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkgetrv4h8gcn4dccnxv563ep diff --git a/DEVELOPING.md b/docs/DEVELOPING.md similarity index 94% rename from DEVELOPING.md rename to docs/DEVELOPING.md index 19a31356..913f8a8d 100644 --- a/DEVELOPING.md +++ b/docs/DEVELOPING.md @@ -4,18 +4,20 @@ Gossip is architected with the following components: - A User Interface thread, synchronous - Tokio asynchronous runtime running - - An overlord (handles most jobs) - - A set of minions (each one handles one relay) + - An overlord (handles most jobs) + - A set of minions (each one handles one relay) ## Keeping the UI responsive The most important thing to be aware of is that the User Interface thread repeatedly calculates what to draw and potentially redraws up to 60 frames per second, therefore it **must** not run any slow code. To that end, the following are allowed from the UI thread: + - Locking global variables (since nearly all locks in gossip are intended to be rapidly released) - Sending messages to the overlord. The following is NOT appreciated when done from the UI thread: + - Database calls, or calls to functions that do database calls - Internet queries, or calls to functions that query over the Internet @@ -31,7 +33,8 @@ The overlord generally is the one to send messages to minions using the GLOBALS. ## Flow -The flow generally happens like this +The flow generally happens like this: + - The user interacts with the UI - The UI requests something of the Overlord - The overlord either does it, or spawns a task to do it if it takes too long (the overlord should also remain somewhat responsive). @@ -45,16 +48,16 @@ The flow generally happens like this ## Pull Requests -I prefer that you run and make pass +I prefer that you run and make pass: ````sh -$ cargo clippy +cargo clippy ```` and then ````sh -$ cargo fmt +cargo fmt ```` before you issue a pull request. Otherwise I'll have to do it for you. diff --git a/PERFORMANCE.md b/docs/PERFORMANCE.md similarity index 96% rename from PERFORMANCE.md rename to docs/PERFORMANCE.md index 8a47fdee..8a60a72d 100644 --- a/PERFORMANCE.md +++ b/docs/PERFORMANCE.md @@ -41,7 +41,7 @@ This issue will be ameliorated somewhat in the future when you can have differen Gossip should be compiled in release mode. You can also compile it for your individual processor to squeeze out the most performance (the following line leaves out feature flags, you'll wnat to determine which ones are right for you): ````bash -$ RUSTFLAGS="-C target-cpu=native --cfg tokio_unstable" cargo build --release +RUSTFLAGS="-C target-cpu=native --cfg tokio_unstable" cargo build --release ```` ### Dumb Programmers From 9dbf65945deb02d2d8d48aeec6b7cbf7e1c70095 Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Thu, 5 Oct 2023 08:32:42 +0200 Subject: [PATCH 07/46] Add telegram channel --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3a28b804..dc2fdeb4 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,8 @@ MIT license ([LICENSE-MIT](LICENSE-MIT) or ) All contributions welcome, please check the [development guidelines](docs/DEVELOPING.md) before starting to code. +Please join [Gossip Telegram Channel](https://t.me/gossipclient). + Anyone interested in replacing the GUI with something much better, or keeping it as egui but making it much better, would be greatly appreciated. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, shall be licensed as above, without any additional terms or conditions. From d13c60441bffad3280bffbe5e6d037cfa7cacf90 Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Thu, 5 Oct 2023 08:34:39 +0200 Subject: [PATCH 08/46] Improve markdown --- packaging/windows/README.txt | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packaging/windows/README.txt b/packaging/windows/README.txt index 234f42a1..0a905af1 100644 --- a/packaging/windows/README.txt +++ b/packaging/windows/README.txt @@ -5,16 +5,22 @@ Prerequisite for packaging: Compile: - $ rustup update - $ cargo build --features=lang-cjk --release +```` + rustup update + cargo build --features=lang-cjk --release +```` Copy the binary to the packaging diretory - $ cp ..\..\target\release\gossip.exe . +```` + cp ..\..\target\release\gossip.exe . +```` Copy the gossip.png here - $ cp ..\..\gossip.png . +```` + cp ..\..\gossip.png . +```` For new versions of gossip, update gossip.wxs * UPDATE the Package.Version, SummaryInformation.Description @@ -24,7 +30,9 @@ For new versions of gossip, update gossip.wxs Packaging: - $ wix build gossip.VERSION.wxs +```` + wix build gossip.VERSION.wxs +```` Upload to github releases. @@ -32,8 +40,12 @@ Upload to github releases. ---- To install the package, either double-click the MSI, or - $ msiexec gossip.msi +```` + msiexec gossip.msi +```` To remove the package from your windows computer: - $ msiexec /x gossip.msi +```` + msiexec /x gossip.msi +```` From 70fee5b08582d9e42b028d7924c997eb85bc4e9a Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Thu, 5 Oct 2023 08:38:42 +0200 Subject: [PATCH 09/46] Create folder for logo files --- gossip-bin/src/ui/mod.rs | 4 ++-- gossip.png => logo/gossip.png | Bin gossip.svg => logo/gossip.svg | 0 icon.png => logo/icon.png | 0 packaging/windows/README.txt | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) rename gossip.png => logo/gossip.png (100%) rename gossip.svg => logo/gossip.svg (100%) rename icon.png => logo/icon.png (100%) diff --git a/gossip-bin/src/ui/mod.rs b/gossip-bin/src/ui/mod.rs index 5e8172f7..617f5d8e 100644 --- a/gossip-bin/src/ui/mod.rs +++ b/gossip-bin/src/ui/mod.rs @@ -56,7 +56,7 @@ use self::widgets::NavItem; use self::wizard::{WizardPage, WizardState}; pub fn run() -> Result<(), Error> { - let icon_bytes = include_bytes!("../../../gossip.png"); + let icon_bytes = include_bytes!("../../../logo/gossip.png"); let icon = image::load_from_memory(icon_bytes)?.to_rgba8(); let (icon_width, icon_height) = icon.dimensions(); @@ -479,7 +479,7 @@ impl GossipUi { submenu_ids.insert(SubMenu::Help, egui::Id::new(SubMenu::Help.to_id_str())); let icon_texture_handle = { - let bytes = include_bytes!("../../../gossip.png"); + let bytes = include_bytes!("../../../logo/gossip.png"); let image = image::load_from_memory(bytes).unwrap(); let size = [image.width() as _, image.height() as _]; let image_buffer = image.to_rgba8(); diff --git a/gossip.png b/logo/gossip.png similarity index 100% rename from gossip.png rename to logo/gossip.png diff --git a/gossip.svg b/logo/gossip.svg similarity index 100% rename from gossip.svg rename to logo/gossip.svg diff --git a/icon.png b/logo/icon.png similarity index 100% rename from icon.png rename to logo/icon.png diff --git a/packaging/windows/README.txt b/packaging/windows/README.txt index 0a905af1..ed988d3a 100644 --- a/packaging/windows/README.txt +++ b/packaging/windows/README.txt @@ -19,7 +19,7 @@ Copy the binary to the packaging diretory Copy the gossip.png here ```` - cp ..\..\gossip.png . + cp ..\..\logo\gossip.png . ```` For new versions of gossip, update gossip.wxs From de252a19b9fef80b900232b084f9c631bac37220 Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Thu, 5 Oct 2023 08:49:14 +0200 Subject: [PATCH 10/46] Improve markdown and convert txt to md --- docs/DEVELOPING.md | 4 +- packaging/{RELEASE.txt => RELEASE.md} | 67 ++++++++++++--------- packaging/windows/{README.txt => README.md} | 25 ++++---- 3 files changed, 55 insertions(+), 41 deletions(-) rename packaging/{RELEASE.txt => RELEASE.md} (75%) rename packaging/windows/{README.txt => README.md} (61%) diff --git a/docs/DEVELOPING.md b/docs/DEVELOPING.md index 913f8a8d..ed9718b7 100644 --- a/docs/DEVELOPING.md +++ b/docs/DEVELOPING.md @@ -50,13 +50,13 @@ The flow generally happens like this: I prefer that you run and make pass: -````sh +````bash cargo clippy ```` and then -````sh +````bash cargo fmt ```` diff --git a/packaging/RELEASE.txt b/packaging/RELEASE.md similarity index 75% rename from packaging/RELEASE.txt rename to packaging/RELEASE.md index 243f6376..8bea25dd 100644 --- a/packaging/RELEASE.txt +++ b/packaging/RELEASE.md @@ -1,3 +1,4 @@ +# RELEASE 0. DON'T update dependencies. DON'T 'cargo update'. Do that kind of stuff right after releasing. Because that stuff presents risk. @@ -9,9 +10,11 @@ 2. Stabilize the code. Make all these happy: - $ cargo clippy - $ cargo fmt - $ cargo test + ````bash + cargo clippy + cargo fmt + cargo test + ```` 3. Edit Cargo.toml and change the version (remove the -unstable). Compile so you get a new Cargo.lock @@ -28,24 +31,33 @@ 5. Build the debian: - $ cd debian - $ ./deb.sh + ````bash + cd debian + ./deb.sh + ```` -6. Build the appimage +6. Build the appimage: - $ cd appimage - $ cargo appimage --features="lang-cjk,video-ffmpeg" + ````bash + cd appimage + cargo appimage --features="lang-cjk,video-ffmpeg" + ```` -7. Build the windows +7. Build the windows: - $ cd windows - Follow the windows/README.txt + ````bash + cd windows + ```` -8. Build the macos + and follow the [Windows README](windows/README.md) - $ cd macos - $ ./build_macos.sh - $ ./build_macos_intel.sh +8. Build the macos: + + ````bash + cd macos + ./build_macos.sh + ./build_macos_intel.sh + ```` 9. Bundle the files, create SHA256 hashes @@ -55,10 +67,8 @@ 12. Announce release on nostr under gossip account - ----------------- - This is a draft of the steps taken to make a release. I intend to flesh this out as I actually make releases. @@ -77,10 +87,9 @@ gossip ├── nostr-types └── qrcode - Try to push our dependency changes upstream: - https://github.com/mikedilger/qrcode-rust (unlikely, stale for >3 years) - https://github.com/mikedilger/egui + (unlikely, stale for >3 years) + nostr-types -- cargo update, and check for new versions, maybe update dependencies @@ -118,19 +127,23 @@ gossip -- master -- version 0.N+1.0-unstable ------------------------------ +----------------- + Package & Publish of gossip: Package for windows: - * main version, as .msi - * main version with lang-cjk, as .msi + +* main version, as .msi +* main version with lang-cjk, as .msi Package for debian: - * main version, as .msi - * main version with lang-cjk, as .msi + +* main version, as .msi +* main version with lang-cjk, as .msi Create github release (it will create source tar files) - * Post the windows .msi files - * Post the debian .deb files + +* Post the windows .msi files +* Post the debian .deb files Update aur.archlinux.org PKGBUILD diff --git a/packaging/windows/README.txt b/packaging/windows/README.md similarity index 61% rename from packaging/windows/README.txt rename to packaging/windows/README.md index ed988d3a..b6715edf 100644 --- a/packaging/windows/README.txt +++ b/packaging/windows/README.md @@ -1,3 +1,4 @@ +# WINDOWS Prerequisite for packaging: @@ -5,47 +6,47 @@ Prerequisite for packaging: Compile: -```` +````sh rustup update cargo build --features=lang-cjk --release ```` Copy the binary to the packaging diretory -```` +````sh cp ..\..\target\release\gossip.exe . ```` Copy the gossip.png here -```` +````sh cp ..\..\logo\gossip.png . ```` -For new versions of gossip, update gossip.wxs - * UPDATE the Package.Version, SummaryInformation.Description - * UPDATE the Package.ProductCode GUID to a new one - * KEEP the UpgradeCode GUID (it should never change, it ties different versions together) - * Change a component GUID ONLY IF the absolute path changes. +For new versions of gossip, update `gossip.wxs`: + +* UPDATE the Package.Version, SummaryInformation.Description +* UPDATE the Package.ProductCode GUID to a new one +* KEEP the UpgradeCode GUID (it should never change, it ties different versions together) +* Change a component GUID ONLY IF the absolute path changes. Packaging: -```` +````sh wix build gossip.VERSION.wxs ```` Upload to github releases. - ---- To install the package, either double-click the MSI, or -```` +````sh msiexec gossip.msi ```` To remove the package from your windows computer: -```` +````sh msiexec /x gossip.msi ```` From 4c0c47d6fe464013ea8bd42ece1e655d4030a1d1 Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Thu, 5 Oct 2023 09:01:21 +0200 Subject: [PATCH 11/46] Remove files --- devrun.sh | 4 ---- filescontaining.sh | 4 ---- find.sh | 3 --- findfile.sh | 4 ---- 4 files changed, 15 deletions(-) delete mode 100755 devrun.sh delete mode 100755 filescontaining.sh delete mode 100755 find.sh delete mode 100755 findfile.sh diff --git a/devrun.sh b/devrun.sh deleted file mode 100755 index 8bbf4527..00000000 --- a/devrun.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -cargo build --features=lang-cjk,video-ffmpeg && \ - RUST_BACKTRACE=1 RUST_LOG="info,gossip=debug" ./target/debug/gossip diff --git a/filescontaining.sh b/filescontaining.sh deleted file mode 100755 index e26eb76e..00000000 --- a/filescontaining.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -find . -name .git -prune -o -name target -prune -o -type f -exec grep -H "$1" {} \; \ - | awk -F: '{print $1}' | uniq diff --git a/find.sh b/find.sh deleted file mode 100755 index 28f9e211..00000000 --- a/find.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -find . -name .git -prune -o -name target -prune -o -type f -exec grep -H "$1" {} \; diff --git a/findfile.sh b/findfile.sh deleted file mode 100755 index 73cf1aa6..00000000 --- a/findfile.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -find . -name .git -prune -o -name target -prune -o -name "$1" -print - From 9c9b6f442792912ad48970820882194f6791c15b Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Thu, 5 Oct 2023 09:03:12 +0200 Subject: [PATCH 12/46] Add file for generating rust doc --- docs/DOCUMENTATION.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docs/DOCUMENTATION.md diff --git a/docs/DOCUMENTATION.md b/docs/DOCUMENTATION.md new file mode 100644 index 00000000..95dc0bab --- /dev/null +++ b/docs/DOCUMENTATION.md @@ -0,0 +1,15 @@ +# DOCUMENTATION + +You may want to generate the Gossip Rust Documentation from root folder: + +````bash + cargo doc --lib +```` + +The output in `target/doc/gossip_lib/index.html` may be browsed. + +For lasiest people the following will directly open the browser: + +````bash + cargo doc --lib --open +```` From 73c2d7d7dbf61957bf136d428955c08d253d6ffb Mon Sep 17 00:00:00 2001 From: Bu5hm4nn Date: Thu, 5 Oct 2023 12:11:12 -0600 Subject: [PATCH 13/46] Separate build scripts for bin and library to fix macos ffmpeg library linking --- gossip-bin/build.rs | 8 ++++++++ gossip-lib/build.rs | 7 ------- 2 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 gossip-bin/build.rs diff --git a/gossip-bin/build.rs b/gossip-bin/build.rs new file mode 100644 index 00000000..d2fd4645 --- /dev/null +++ b/gossip-bin/build.rs @@ -0,0 +1,8 @@ +fn main() { + // link to bundled libraries + #[cfg(target_os = "macos")] + println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path"); + + #[cfg(target_os = "linux")] + println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN"); +} diff --git a/gossip-lib/build.rs b/gossip-lib/build.rs index 01037e71..39c42977 100644 --- a/gossip-lib/build.rs +++ b/gossip-lib/build.rs @@ -6,11 +6,4 @@ fn main() { .unwrap(); let git_hash = String::from_utf8(output.stdout).unwrap(); println!("cargo:rustc-env=GIT_HASH={git_hash}"); - - // link to bundled libraries - #[cfg(target_os = "macos")] - println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path"); - - #[cfg(target_os = "linux")] - println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN"); } From 62b8affe4b87c2baf21fd00f84aeace7642ae006 Mon Sep 17 00:00:00 2001 From: Aaron Carlton Date: Fri, 6 Oct 2023 10:48:20 +1300 Subject: [PATCH 14/46] When launching from a desktop icon, don't allow multiple gossip windows at once --- gossip-bin/Cargo.toml | 2 +- gossip-bin/src/ui/mod.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gossip-bin/Cargo.toml b/gossip-bin/Cargo.toml index 58afa0a1..4269685a 100644 --- a/gossip-bin/Cargo.toml +++ b/gossip-bin/Cargo.toml @@ -18,7 +18,7 @@ rustls-tls = [ "gossip-lib/rustls-tls" ] [dependencies] bech32 = "0.9" -eframe = { git = "https://github.com/mikedilger/egui", rev = "50393e4f34ac6246b8c2424e42fbe5b95e4b4452", features = [ "persistence" ] } +eframe = { git = "https://github.com/mikedilger/egui", rev = "50393e4f34ac6246b8c2424e42fbe5b95e4b4452", features = [ "persistence", "wayland" ] } egui-winit = { git = "https://github.com/mikedilger/egui", rev = "50393e4f34ac6246b8c2424e42fbe5b95e4b4452", features = [ "default" ] } egui-video = { git = "https://github.com/mikedilger/egui-video", rev = "81cc3ee58818754272582397161cc55ff11bde18", features = [ "from_bytes" ], optional = true } gossip-relay-picker = { git = "https://github.com/mikedilger/gossip-relay-picker", rev = "39f9c14b1c201842c512754920f4da4987cd68b6" } diff --git a/gossip-bin/src/ui/mod.rs b/gossip-bin/src/ui/mod.rs index 5e8172f7..f8ce67ac 100644 --- a/gossip-bin/src/ui/mod.rs +++ b/gossip-bin/src/ui/mod.rs @@ -61,6 +61,8 @@ pub fn run() -> Result<(), Error> { let (icon_width, icon_height) = icon.dimensions(); let options = eframe::NativeOptions { + #[cfg(target_os = "linux")] + app_id: Some("gossip".to_string()), decorated: true, #[cfg(target_os = "macos")] fullsize_content: true, From 8b16d2a16cceddc31122fa63b6eb8908c7061af7 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Thu, 5 Oct 2023 17:41:53 +1300 Subject: [PATCH 15/46] Clarification in the README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f7c06c1d..69e2a801 100644 --- a/README.md +++ b/README.md @@ -137,10 +137,10 @@ The output will be a binary executable in `target/release/gossip` This binary should be portable to similar systems with similar hardware and operating system. -If you want a binary optimized for your exact processor with the newest features enabled: +If you want a binary optimized for your exact processor with the newest CPU features enabled, and all gossip features enabled: ````bash -$ RUSTFLAGS="-C target-cpu=native --cfg tokio_unstable" cargo build --release +$ RUSTFLAGS="-C target-cpu=native --cfg tokio_unstable" cargo build --features=lang-cjk,video-ffmpeg --release ```` Everything gossip needs (fonts, icons) is baked into this executable. It doesn't need to find assets. So you can move it and run it from anywhere. From 67ef7038dbf792d57a0a1599aba5d20d46d52018 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Fri, 6 Oct 2023 11:23:43 +1300 Subject: [PATCH 16/46] add NIP-24 to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 69e2a801..5e294852 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ The following features make gossip different than most other nostr clients so fa - [x] NIP-21 - nostr: URL scheme - [x] NIP-22 - Event created_at Limits - [ ] NIP-23 - Long-form Content [Optional viewing, but not creating] +- [ ] NIP-24 - Extra metadata fields and tags - [x] NIP-25 - Reactions - [x] NIP-26 - Delegated Event Signing - [x] NIP-27 - Text Note References From 3723d1ab4982687e76c0a512f7e47501e6357b15 Mon Sep 17 00:00:00 2001 From: Aaron Carlucci Date: Thu, 5 Oct 2023 18:02:00 +0200 Subject: [PATCH 17/46] Add Wayland app_id to egui eframe NativeOptions and enable Wayland feature for eframe crate --- gossip-bin/Cargo.toml | 2 +- gossip-bin/src/ui/mod.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gossip-bin/Cargo.toml b/gossip-bin/Cargo.toml index 58afa0a1..4269685a 100644 --- a/gossip-bin/Cargo.toml +++ b/gossip-bin/Cargo.toml @@ -18,7 +18,7 @@ rustls-tls = [ "gossip-lib/rustls-tls" ] [dependencies] bech32 = "0.9" -eframe = { git = "https://github.com/mikedilger/egui", rev = "50393e4f34ac6246b8c2424e42fbe5b95e4b4452", features = [ "persistence" ] } +eframe = { git = "https://github.com/mikedilger/egui", rev = "50393e4f34ac6246b8c2424e42fbe5b95e4b4452", features = [ "persistence", "wayland" ] } egui-winit = { git = "https://github.com/mikedilger/egui", rev = "50393e4f34ac6246b8c2424e42fbe5b95e4b4452", features = [ "default" ] } egui-video = { git = "https://github.com/mikedilger/egui-video", rev = "81cc3ee58818754272582397161cc55ff11bde18", features = [ "from_bytes" ], optional = true } gossip-relay-picker = { git = "https://github.com/mikedilger/gossip-relay-picker", rev = "39f9c14b1c201842c512754920f4da4987cd68b6" } diff --git a/gossip-bin/src/ui/mod.rs b/gossip-bin/src/ui/mod.rs index 5e8172f7..f8ce67ac 100644 --- a/gossip-bin/src/ui/mod.rs +++ b/gossip-bin/src/ui/mod.rs @@ -61,6 +61,8 @@ pub fn run() -> Result<(), Error> { let (icon_width, icon_height) = icon.dimensions(); let options = eframe::NativeOptions { + #[cfg(target_os = "linux")] + app_id: Some("gossip".to_string()), decorated: true, #[cfg(target_os = "macos")] fullsize_content: true, From 8f0aed85a79ba8a1d7f877c33b1d2d191ebab13f Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Fri, 6 Oct 2023 00:32:47 +0200 Subject: [PATCH 18/46] Reference to gossip.png file --- packaging/macos/build_macos.sh | 2 +- packaging/macos/build_macos_intel.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/macos/build_macos.sh b/packaging/macos/build_macos.sh index 7ef3836a..7229a175 100755 --- a/packaging/macos/build_macos.sh +++ b/packaging/macos/build_macos.sh @@ -39,7 +39,7 @@ cp macos_launch.sh $APP_DIR/Contents/MacOS/$APP_NAME echo "Copying Icon" mkdir -p $APP_DIR/Contents/Resources cat Info.plist | sed s/__VERSION__/$VERSION/g > $APP_DIR/Contents/Info.plist -cp ../../$NAME.png ../../$NAME.svg $APP_DIR/Contents/Resources +cp ../../logo/$NAME.png ../../logo/$NAME.svg $APP_DIR/Contents/Resources echo "Creating dmg" mkdir -p $APP_NAME diff --git a/packaging/macos/build_macos_intel.sh b/packaging/macos/build_macos_intel.sh index 62e0ec70..49c45b61 100755 --- a/packaging/macos/build_macos_intel.sh +++ b/packaging/macos/build_macos_intel.sh @@ -39,7 +39,7 @@ cp macos_launch.sh $APP_DIR/Contents/MacOS/$APP_NAME echo "Copying Icon" mkdir -p $APP_DIR/Contents/Resources cat Info.plist | sed s/__VERSION__/$VERSION/g > $APP_DIR/Contents/Info.plist -cp ../../$NAME.png ../../$NAME.svg $APP_DIR/Contents/Resources +cp ../../logo/$NAME.png ../../logo/$NAME.svg $APP_DIR/Contents/Resources echo "Creating dmg" mkdir -p $APP_NAME From c4c9476f1754c4710bdc93843b73565514fa1822 Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Fri, 6 Oct 2023 00:33:01 +0200 Subject: [PATCH 19/46] Reference to gossip.png file --- packaging/windows/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packaging/windows/README.md b/packaging/windows/README.md index b6715edf..3c379105 100644 --- a/packaging/windows/README.md +++ b/packaging/windows/README.md @@ -6,20 +6,20 @@ Prerequisite for packaging: Compile: -````sh +````dos rustup update cargo build --features=lang-cjk --release ```` Copy the binary to the packaging diretory -````sh +````dos cp ..\..\target\release\gossip.exe . ```` Copy the gossip.png here -````sh +````dos cp ..\..\logo\gossip.png . ```` @@ -32,7 +32,7 @@ For new versions of gossip, update `gossip.wxs`: Packaging: -````sh +````dos wix build gossip.VERSION.wxs ```` @@ -41,12 +41,12 @@ Upload to github releases. ---- To install the package, either double-click the MSI, or -````sh +````dos msiexec gossip.msi ```` To remove the package from your windows computer: -````sh +````dos msiexec /x gossip.msi ```` From 9a2766284fb20e7f3ff0808e90426bb48d0ca940 Mon Sep 17 00:00:00 2001 From: "nico.benaz" <52411515+nbenaglia@users.noreply.github.com> Date: Fri, 6 Oct 2023 00:36:18 +0200 Subject: [PATCH 20/46] Update DOCUMENTATION.md --- docs/DOCUMENTATION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/DOCUMENTATION.md b/docs/DOCUMENTATION.md index 95dc0bab..3bd1bcb3 100644 --- a/docs/DOCUMENTATION.md +++ b/docs/DOCUMENTATION.md @@ -3,7 +3,7 @@ You may want to generate the Gossip Rust Documentation from root folder: ````bash - cargo doc --lib +cargo doc --lib ```` The output in `target/doc/gossip_lib/index.html` may be browsed. @@ -11,5 +11,5 @@ The output in `target/doc/gossip_lib/index.html` may be browsed. For lasiest people the following will directly open the browser: ````bash - cargo doc --lib --open +cargo doc --lib --open ```` From a8077afb1d95ead92ae865c87548c13937928f05 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Fri, 6 Oct 2023 11:38:13 +1300 Subject: [PATCH 21/46] storage: event_tag_index --- gossip-lib/src/error.rs | 2 + gossip-lib/src/storage/event_tag_index1.rs | 125 ++++++++++++++++++ gossip-lib/src/storage/events1.rs | 1 + gossip-lib/src/storage/mod.rs | 110 +++++++++++++++ .../src/storage/unindexed_giftwraps1.rs | 1 + 5 files changed, 239 insertions(+) create mode 100644 gossip-lib/src/storage/event_tag_index1.rs diff --git a/gossip-lib/src/error.rs b/gossip-lib/src/error.rs index 464a0443..1bc49e85 100644 --- a/gossip-lib/src/error.rs +++ b/gossip-lib/src/error.rs @@ -37,6 +37,7 @@ pub enum ErrorKind { SliceError(std::array::TryFromSliceError), Speedy(speedy::Error), Svg(usvg::Error), + TagNotIndexed(String), Timeout(tokio::time::error::Elapsed), UnknownCommand(String), UrlHasEmptyHostname, @@ -104,6 +105,7 @@ impl std::fmt::Display for Error { SliceError(e) => write!(f, "Slice: {e}"), Speedy(e) => write!(f, "Speedy: {e}"), Svg(e) => write!(f, "SVG: {e}"), + TagNotIndexed(s) => write!(f, "Tag not indexed: {s}"), Timeout(e) => write!(f, "Timeout: {e}"), UnknownCommand(s) => write!(f, "Unknown command: {s}"), UrlHasEmptyHostname => write!(f, "URL has empty hostname"), diff --git a/gossip-lib/src/storage/event_tag_index1.rs b/gossip-lib/src/storage/event_tag_index1.rs new file mode 100644 index 00000000..bf962656 --- /dev/null +++ b/gossip-lib/src/storage/event_tag_index1.rs @@ -0,0 +1,125 @@ +use crate::error::{Error, ErrorKind}; +use crate::globals::GLOBALS; +use crate::storage::{RawDatabase, Storage}; +use heed::{types::UnalignedSlice, DatabaseFlags, RwTxn}; +use nostr_types::{Event, EventKind, PublicKeyHex}; +use std::sync::Mutex; + +// NOTE: "innerp" is a fake tag. We store events that reference a person internally under it. +pub(super) const INDEXED_TAGS: [&str; 4] = ["a", "d", "p", "delegation"]; + +// TagKey:QUOTE:TagValue -> Id +// (dup keys, so multiple Ids per key) +// val: id.as_slice() | Id(val[0..32].try_into()?) + +static EVENT_TAG_INDEX1_DB_CREATE_LOCK: Mutex<()> = Mutex::new(()); +static mut EVENT_TAG_INDEX1_DB: Option = None; + +impl Storage { + pub(super) fn db_event_tag_index1(&self) -> Result { + unsafe { + if let Some(db) = EVENT_TAG_INDEX1_DB { + Ok(db) + } else { + // Lock. This drops when anything returns. + let _lock = EVENT_TAG_INDEX1_DB_CREATE_LOCK.lock(); + + // In case of a race, check again + if let Some(db) = EVENT_TAG_INDEX1_DB { + return Ok(db); + } + + // Create it. We know that nobody else is doing this and that + // it cannot happen twice. + let mut txn = self.env.write_txn()?; + let db = self + .env + .database_options() + .types::, UnalignedSlice>() + .flags(DatabaseFlags::DUP_SORT | DatabaseFlags::DUP_FIXED) + .name("event_tag_index") + .create(&mut txn)?; + txn.commit()?; + EVENT_TAG_INDEX1_DB = Some(db); + Ok(db) + } + } + } + + pub fn write_event_tag_index1<'a>( + &'a self, + event: &Event, + rw_txn: Option<&mut RwTxn<'a>>, + ) -> Result<(), Error> { + let f = |txn: &mut RwTxn<'a>| -> Result<(), Error> { + let mut event = event; + + let mut rumor_event: Event; + if event.kind == EventKind::GiftWrap { + match GLOBALS.signer.unwrap_giftwrap(event) { + Ok(rumor) => { + rumor_event = rumor.into_event_with_bad_signature(); + rumor_event.id = event.id; // lie, so it indexes it under the giftwrap + event = &rumor_event; + } + Err(e) => { + if matches!(e.kind, ErrorKind::NoPrivateKey) { + // Store as unindexed for later indexing + let bytes = vec![]; + self.db_unindexed_giftwraps()? + .put(txn, event.id.as_slice(), &bytes)?; + } + } + } + } + + // our user's public key + let pk: Option = self.read_setting_public_key().map(|p| p.into()); + + for tag in &event.tags { + let tagname = tag.tagname(); + let value = match tag.value(1) { + Ok(v) => v, + Err(_) => continue, // no tag value, not indexable. + }; + + // Only index tags we intend to lookup later by tag. + // If that set changes, (1) add to this code and (2) do a reindex migration + if !INDEXED_TAGS.contains(&&*tagname) { + continue; + } + // For 'p' tags, only index them if 'p' is our user + if tagname == "p" { + match &pk { + None => continue, + Some(pk) => { + if value != pk.as_str() { + continue; + } + } + } + } + + let mut key: Vec = tagname.as_bytes().to_owned(); + key.push(b'\"'); // double quote separator, unlikely to be inside of a tagname + key.extend(value.as_bytes()); + let key = key!(&key); // limit the size + let bytes = event.id.as_slice(); + self.db_event_tag_index()?.put(txn, key, bytes)?; + } + + Ok(()) + }; + + match rw_txn { + Some(txn) => f(txn)?, + None => { + let mut txn = self.env.write_txn()?; + f(&mut txn)?; + txn.commit()?; + } + }; + + Ok(()) + } +} diff --git a/gossip-lib/src/storage/events1.rs b/gossip-lib/src/storage/events1.rs index d1eee4fa..a6b7d0f5 100644 --- a/gossip-lib/src/storage/events1.rs +++ b/gossip-lib/src/storage/events1.rs @@ -58,6 +58,7 @@ impl Storage { // also index the event self.write_event_ek_pk_index(event, Some(txn))?; self.write_event_ek_c_index(event, Some(txn))?; + self.write_event_tag_index(event, Some(txn))?; self.write_event_references_person(event, Some(txn))?; for hashtag in event.hashtags() { if hashtag.is_empty() { diff --git a/gossip-lib/src/storage/mod.rs b/gossip-lib/src/storage/mod.rs index 1d361ece..98920abd 100644 --- a/gossip-lib/src/storage/mod.rs +++ b/gossip-lib/src/storage/mod.rs @@ -21,6 +21,7 @@ mod event_ek_c_index1; mod event_ek_pk_index1; mod event_references_person1; mod event_seen_on_relay1; +mod event_tag_index1; mod event_viewed1; mod events1; mod hashtags1; @@ -52,6 +53,8 @@ use speedy::{Readable, Writable}; use std::collections::{HashMap, HashSet}; use std::ops::Bound; +use self::event_tag_index1::INDEXED_TAGS; + // Macro to define read-and-write into "general" database, largely for settings // The type must implemented Speedy Readable and Writable macro_rules! def_setting { @@ -179,6 +182,7 @@ impl Storage { let _ = self.db_event_ek_c_index()?; let _ = self.db_event_ek_pk_index()?; let _ = self.db_event_references_person()?; + let _ = self.db_event_tag_index()?; let _ = self.db_events()?; let _ = self.db_event_seen_on_relay()?; let _ = self.db_event_viewed()?; @@ -235,6 +239,11 @@ impl Storage { self.db_event_references_person1() } + #[inline] + pub(crate) fn db_event_tag_index(&self) -> Result { + self.db_event_tag_index1() + } + #[inline] pub(crate) fn db_events(&self) -> Result { self.db_events1() @@ -341,6 +350,12 @@ impl Storage { Ok(self.db_event_references_person()?.len(&txn)?) } + /// The number of records in the event_tag index table + pub fn get_event_tag_index_len(&self) -> Result { + let txn = self.env.read_txn()?; + Ok(self.db_event_tag_index()?.len(&txn)?) + } + /// The number of records in the relationships table pub fn get_relationships_len(&self) -> Result { let txn = self.env.read_txn()?; @@ -1654,6 +1669,68 @@ impl Storage { Ok(()) } + fn write_event_tag_index<'a>( + &'a self, + event: &Event, + rw_txn: Option<&mut RwTxn<'a>>, + ) -> Result<(), Error> { + self.write_event_tag_index1(event, rw_txn) + } + + /// Find events having a given tag, and passing the filter. + /// Only some tags are indxed: "a", "d", "delegation", and "p" for the gossip user only + pub fn find_tagged_events( + &self, + tagname: &str, + tagvalue: Option<&str>, + f: F, + sort: bool, + ) -> Result, Error> + where + F: Fn(&Event) -> bool, + { + // Make sure we are asking for something that we have indexed + if !INDEXED_TAGS.contains(&tagname) { + return Err(ErrorKind::TagNotIndexed(tagname.to_owned()).into()); + } + + let mut ids: HashSet = HashSet::new(); + let txn = self.env.read_txn()?; + + let mut start_key: Vec = tagname.as_bytes().to_owned(); + start_key.push(b'\"'); // double quote separator, unlikely to be inside of a tagname + if let Some(tv) = tagvalue { + start_key.extend(tv.as_bytes()); + } + let start_key = key!(&start_key); // limit the size + let iter = self.db_event_tag_index()?.prefix_iter(&txn, start_key)?; + for result in iter { + let (_key, val) = result?; + // Take the event + let id = Id(val[0..32].try_into()?); + ids.insert(id); + } + + // Now that we have that Ids, fetch and filter the events + let txn = self.env.read_txn()?; + let mut events: Vec = Vec::new(); + for id in ids { + // this is like self.read_event(), but we supply our existing transaction + if let Some(bytes) = self.db_events()?.get(&txn, id.as_slice())? { + let event = Event::read_from_buffer(bytes)?; + if f(&event) { + events.push(event); + } + } + } + + if sort { + events.sort_by(|a, b| b.created_at.cmp(&a.created_at)); + } + + Ok(events) + } + // We don't call this externally. Whenever we write an event, we do this. #[inline] fn write_event_references_person<'a>( @@ -2133,6 +2210,7 @@ impl Storage { // Erase all indices first self.db_event_ek_pk_index()?.clear(txn)?; self.db_event_ek_c_index()?.clear(txn)?; + self.db_event_tag_index()?.clear(txn)?; self.db_event_references_person()?.clear(txn)?; self.db_hashtags()?.clear(txn)?; @@ -2142,6 +2220,7 @@ impl Storage { let event = Event::read_from_buffer(val)?; self.write_event_ek_pk_index(&event, Some(txn))?; self.write_event_ek_c_index(&event, Some(txn))?; + self.write_event_tag_index(&event, Some(txn))?; self.write_event_references_person(&event, Some(txn))?; for hashtag in event.hashtags() { if hashtag.is_empty() { @@ -2167,6 +2246,37 @@ impl Storage { Ok(()) } + pub fn rebuild_event_tags_index<'a>( + &'a self, + rw_txn: Option<&mut RwTxn<'a>>, + ) -> Result<(), Error> { + let f = |txn: &mut RwTxn<'a>| -> Result<(), Error> { + // Erase the index first + self.db_event_tag_index()?.clear(txn)?; + + let loop_txn = self.env.read_txn()?; + for result in self.db_events()?.iter(&loop_txn)? { + let (_key, val) = result?; + let event = Event::read_from_buffer(val)?; + self.write_event_tag_index(&event, Some(txn))?; + } + Ok(()) + }; + + match rw_txn { + Some(txn) => { + f(txn)?; + } + None => { + let mut txn = self.env.write_txn()?; + f(&mut txn)?; + txn.commit()?; + } + }; + + Ok(()) + } + /// Read person lists pub fn read_person_lists(&self, pubkey: &PublicKey) -> Result, Error> { self.read_person_lists1(pubkey) diff --git a/gossip-lib/src/storage/unindexed_giftwraps1.rs b/gossip-lib/src/storage/unindexed_giftwraps1.rs index 34c5a0be..bc667e53 100644 --- a/gossip-lib/src/storage/unindexed_giftwraps1.rs +++ b/gossip-lib/src/storage/unindexed_giftwraps1.rs @@ -63,6 +63,7 @@ impl Storage { if let Some(event) = self.read_event(id)? { self.write_event_ek_pk_index(&event, Some(&mut txn))?; self.write_event_ek_c_index(&event, Some(&mut txn))?; + self.write_event_tag_index(&event, Some(&mut txn))?; self.write_event_references_person(&event, Some(&mut txn))?; } self.db_unindexed_giftwraps1()? From b4075405394f2d70e909e60f738029351063b7a8 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Tue, 3 Oct 2023 10:03:50 +1300 Subject: [PATCH 22/46] UI stats on new index --- gossip-bin/src/ui/help/stats.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gossip-bin/src/ui/help/stats.rs b/gossip-bin/src/ui/help/stats.rs index 5886b004..4fa5b5ef 100644 --- a/gossip-bin/src/ui/help/stats.rs +++ b/gossip-bin/src/ui/help/stats.rs @@ -76,6 +76,12 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr )); ui.add_space(6.0); + ui.label(format!( + "Event Index (Tags): {} records", + GLOBALS.storage.get_event_tag_index_len().unwrap_or(0) + )); + ui.add_space(6.0); + ui.label(format!( "Event Index (References Person): {} records", GLOBALS From 69ff49996b168f58a22eddb1308ce69d31177ac6 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Tue, 3 Oct 2023 10:04:05 +1300 Subject: [PATCH 23/46] storage: migration to populate event_tag_index --- gossip-lib/src/storage/migrations/mod.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/gossip-lib/src/storage/migrations/mod.rs b/gossip-lib/src/storage/migrations/mod.rs index c640548e..ff3fa02a 100644 --- a/gossip-lib/src/storage/migrations/mod.rs +++ b/gossip-lib/src/storage/migrations/mod.rs @@ -7,7 +7,7 @@ use nostr_types::{Event, Id, RelayUrl, Signature}; use speedy::{Readable, Writable}; impl Storage { - const MAX_MIGRATION_LEVEL: u32 = 10; + const MAX_MIGRATION_LEVEL: u32 = 11; pub(super) fn migrate(&self, mut level: u32) -> Result<(), Error> { if level > Self::MAX_MIGRATION_LEVEL { @@ -60,6 +60,10 @@ impl Storage { let _ = self.db_event_references_person1()?; let _ = self.db_hashtags1()?; } + 10 => { + let _ = self.db_events1()?; + let _ = self.db_event_tag_index1()?; + } _ => {} }; Ok(()) @@ -111,6 +115,10 @@ impl Storage { tracing::info!("{prefix}: rewriting theme settings..."); self.rewrite_theme_settings(txn)?; } + 10 => { + tracing::info!("{prefix}: populating event tag index..."); + self.populate_event_tag_index(txn)?; + } _ => panic!("Unreachable migration level"), }; @@ -516,4 +524,15 @@ impl Storage { Ok(()) } + + pub fn populate_event_tag_index<'a>(&'a self, txn: &mut RwTxn<'a>) -> Result<(), Error> { + let loop_txn = self.env.read_txn()?; + for result in self.db_events1()?.iter(&loop_txn)? { + let (_key, val) = result?; + let event = Event::read_from_buffer(val)?; + self.write_event_tag_index(&event, Some(txn))?; + } + + Ok(()) + } } From 33c4c2c9d53efe279fe3ec28759797a24f36533f Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Tue, 3 Oct 2023 13:02:50 +1300 Subject: [PATCH 24/46] Rebuild event tags index whenever the user's key changes --- gossip-lib/src/signer.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/gossip-lib/src/signer.rs b/gossip-lib/src/signer.rs index f866fec3..2dcc11b2 100644 --- a/gossip-lib/src/signer.rs +++ b/gossip-lib/src/signer.rs @@ -48,6 +48,13 @@ impl Signer { .write("Ignored setting of public key (private key supercedes)".to_string()); } else { *self.public.write() = Some(pk); + + // Reubild the event tag index, since the 'p' tags it need to index just changed. + task::spawn(async move { + if let Err(e) = GLOBALS.storage.rebuild_event_tags_index(None) { + tracing::error!("{}", e); + } + }); } } @@ -71,6 +78,13 @@ impl Signer { } else { *self.encrypted.write() = Some(epk); } + + // Reubild the event tag index, since the 'p' tags it need to index just changed. + task::spawn(async move { + if let Err(e) = GLOBALS.storage.rebuild_event_tags_index(None) { + tracing::error!("{}", e); + } + }); } pub(crate) fn set_private_key(&self, pk: PrivateKey, pass: &str) -> Result<(), Error> { @@ -78,6 +92,14 @@ impl Signer { Some(pk.export_encrypted(pass, GLOBALS.storage.read_setting_log_n())?); *self.public.write() = Some(pk.public_key()); *self.private.write() = Some(pk); + + // Reubild the event tag index, since the 'p' tags it need to index just changed. + task::spawn(async move { + if let Err(e) = GLOBALS.storage.rebuild_event_tags_index(None) { + tracing::error!("{}", e); + } + }); + Ok(()) } @@ -168,6 +190,11 @@ impl Signer { if let Err(e) = GLOBALS.signer.save().await { tracing::error!("{}", e); } + + // Reubild the event tag index, since the 'p' tags it need to index just changed. + if let Err(e) = GLOBALS.storage.rebuild_event_tags_index(None) { + tracing::error!("{}", e); + } }); Ok(()) From b9cd5646d73ea84276617b62c0772f34886e959e Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Fri, 6 Oct 2023 11:49:21 +1300 Subject: [PATCH 25/46] Switch inbox logic to use event_tag_index --- gossip-lib/src/feed.rs | 71 ++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/gossip-lib/src/feed.rs b/gossip-lib/src/feed.rs index af7ca825..fb3dad12 100644 --- a/gossip-lib/src/feed.rs +++ b/gossip-lib/src/feed.rs @@ -2,7 +2,7 @@ use crate::comms::{ToMinionMessage, ToMinionPayload, ToMinionPayloadDetail, ToOv use crate::dm_channel::DmChannel; use crate::error::Error; use crate::globals::GLOBALS; -use nostr_types::{EventDelegation, EventKind, Id, PublicKey, RelayUrl, Unixtime}; +use nostr_types::{EventDelegation, EventKind, Id, PublicKey, PublicKeyHex, RelayUrl, Unixtime}; use parking_lot::RwLock; use std::collections::HashSet; use std::sync::atomic::{AtomicBool, Ordering}; @@ -353,43 +353,48 @@ impl Feed { let since = now - Duration::from_secs(GLOBALS.storage.read_setting_replies_chunk()); + let my_pubkeyhex: PublicKeyHex = my_pubkey.into(); + let inbox_events: Vec = GLOBALS .storage - .read_events_referencing_person(&my_pubkey, since, |e| { - if e.created_at > now { - return false; - } // no future events - if dismissed.contains(&e.id) { - return false; - } // not dismissed - //if e.pubkey == my_pubkey { - // return false; - //} // not self-authored - - // Always include gift wrap and DMs - if e.kind == EventKind::GiftWrap - || e.kind == EventKind::EncryptedDirectMessage - { - return true; - } - - // Include if it directly replies to one of my events - if let Some((id, _)) = e.replies_to() { - if my_event_ids.contains(&id) { + .find_tagged_events( + "p", + Some(my_pubkeyhex.as_str()), + |e| { + if e.created_at < since || e.created_at > now { + return false; + } + if ! kinds_with_dms.contains(&e.kind) { + return false; + } + if dismissed.contains(&e.id) { + return false; + } + if e.kind == EventKind::GiftWrap + || e.kind == EventKind::EncryptedDirectMessage + { return true; } - } - if indirect { - // Include if it tags me - e.people().iter().any(|(p, _, _)| *p == my_pubkey.into()) - } else { - // Include if it directly references me in the content - e.people_referenced_in_content() - .iter() - .any(|p| *p == my_pubkey) - } - })? + // Include if it directly replies to one of my events + if let Some((id, _)) = e.replies_to() { + if my_event_ids.contains(&id) { + return true; + } + } + + if indirect { + // Include if it tags me + e.people().iter().any(|(p, _, _)| *p == my_pubkey.into()) + } else { + // Include if it directly references me in the content + e.people_referenced_in_content() + .iter() + .any(|p| *p == my_pubkey) + } + }, + true, + )? .iter() .map(|e| e.id) .collect(); From c70b5cfce2302c30f762e1bae11aba1d6a620304 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Fri, 6 Oct 2023 11:55:47 +1300 Subject: [PATCH 26/46] storage: stable sorting --- gossip-lib/src/storage/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gossip-lib/src/storage/mod.rs b/gossip-lib/src/storage/mod.rs index 98920abd..2214a278 100644 --- a/gossip-lib/src/storage/mod.rs +++ b/gossip-lib/src/storage/mod.rs @@ -1477,7 +1477,7 @@ impl Storage { } if sort { - events.sort_by(|a, b| b.created_at.cmp(&a.created_at)); + events.sort_by(|a, b| b.created_at.cmp(&a.created_at).then(b.id.cmp(&a.id))); } Ok(events) @@ -1563,7 +1563,7 @@ impl Storage { events.sort_by(|a, b| { // ORDER created_at desc - b.created_at.cmp(&a.created_at) + b.created_at.cmp(&a.created_at).then(b.id.cmp(&a.id)) }); Ok(events) @@ -1725,7 +1725,7 @@ impl Storage { } if sort { - events.sort_by(|a, b| b.created_at.cmp(&a.created_at)); + events.sort_by(|a, b| b.created_at.cmp(&a.created_at).then(b.id.cmp(&a.id))); } Ok(events) @@ -2195,7 +2195,7 @@ impl Storage { )?; // sort - output.sort_by(|a, b| b.created_at.cmp(&a.created_at)); + output.sort_by(|a, b| b.created_at.cmp(&a.created_at).then(b.id.cmp(&a.id))); Ok(output.iter().map(|e| e.id).collect()) } From 8812d48a264b70b695d9862ed144c194357f44b9 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Fri, 6 Oct 2023 12:22:16 +1300 Subject: [PATCH 27/46] Use event_tag_index to find delegated events in Person feed --- gossip-lib/src/feed.rs | 54 +++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/gossip-lib/src/feed.rs b/gossip-lib/src/feed.rs index fb3dad12..3e7803ad 100644 --- a/gossip-lib/src/feed.rs +++ b/gossip-lib/src/feed.rs @@ -2,7 +2,7 @@ use crate::comms::{ToMinionMessage, ToMinionPayload, ToMinionPayloadDetail, ToOv use crate::dm_channel::DmChannel; use crate::error::Error; use crate::globals::GLOBALS; -use nostr_types::{EventDelegation, EventKind, Id, PublicKey, PublicKeyHex, RelayUrl, Unixtime}; +use nostr_types::{Event, EventKind, Id, PublicKey, PublicKeyHex, RelayUrl, Unixtime}; use parking_lot::RwLock; use std::collections::HashSet; use std::sync::atomic::{AtomicBool, Ordering}; @@ -417,32 +417,48 @@ impl Feed { let since = now - Duration::from_secs(GLOBALS.storage.read_setting_person_feed_chunk()); - let events: Vec = GLOBALS + let pphex: PublicKeyHex = person_pubkey.into(); + + let filter = |e: &Event| { + if dismissed.contains(&e.id) { + return false; + } + if ! kinds_without_dms.contains(&e.kind) { + return false; + } + true + }; + + let mut events: Vec = GLOBALS .storage .find_events( &kinds_without_dms, - &[], // any person (due to delegation condition) // FIXME + &[person_pubkey], Some(since), - |e| { - if dismissed.contains(&e.id) { - return false; - } // not dismissed - if e.pubkey == person_pubkey { - true - } else { - if let EventDelegation::DelegatedBy(pk) = e.delegation() { - pk == person_pubkey - } else { - false - } - } - }, - true, + filter, + false )? .iter() - .map(|e| e.id) + .chain( + GLOBALS + .storage + .find_tagged_events( + "delegation", + Some(pphex.as_str()), + filter, + false + )? + .iter() + ) + .map(|e| e.to_owned()) .collect(); + events.sort_by(|a,b| b.created_at.cmp(&a.created_at).then( + b.id.cmp(&a.id) + )); + + let events: Vec = events.iter().map(|e| e.id).collect(); + *self.person_feed.write() = events; } FeedKind::DmChat(channel) => { From 3edbb73f81f4430c29101e8a4c3a3fe75db7392f Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Fri, 6 Oct 2023 12:31:33 +1300 Subject: [PATCH 28/46] FIXME about delegation --- gossip-lib/src/feed.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gossip-lib/src/feed.rs b/gossip-lib/src/feed.rs index 3e7803ad..6e0921b7 100644 --- a/gossip-lib/src/feed.rs +++ b/gossip-lib/src/feed.rs @@ -310,6 +310,9 @@ impl Feed { let since = now - Duration::from_secs(GLOBALS.storage.read_setting_feed_chunk()); + // FIXME we don't include delegated events. We should look for all events + // delegated to people we follow and include those in the feed too. + let followed_events: Vec = GLOBALS .storage .find_events( From 82b6ca53a6f717fddd6b90a72c404a1a3286f6be Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Sat, 7 Oct 2023 08:38:11 +1300 Subject: [PATCH 29/46] storage: migration 11: Remove event_references_person --- gossip-bin/src/ui/help/stats.rs | 9 - gossip-lib/src/feed.rs | 19 +- .../src/storage/event_references_person1.rs | 163 ------------------ gossip-lib/src/storage/events1.rs | 1 - gossip-lib/src/storage/migrations/mod.rs | 28 ++- gossip-lib/src/storage/mod.rs | 39 ----- .../src/storage/unindexed_giftwraps1.rs | 1 - 7 files changed, 31 insertions(+), 229 deletions(-) delete mode 100644 gossip-lib/src/storage/event_references_person1.rs diff --git a/gossip-bin/src/ui/help/stats.rs b/gossip-bin/src/ui/help/stats.rs index 4fa5b5ef..a312f739 100644 --- a/gossip-bin/src/ui/help/stats.rs +++ b/gossip-bin/src/ui/help/stats.rs @@ -82,15 +82,6 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr )); ui.add_space(6.0); - ui.label(format!( - "Event Index (References Person): {} records", - GLOBALS - .storage - .get_event_references_person_len() - .unwrap_or(0) - )); - ui.add_space(6.0); - ui.label(format!( "Event Relationships: {} records", GLOBALS.storage.get_relationships_len().unwrap_or(0) diff --git a/gossip-lib/src/feed.rs b/gossip-lib/src/feed.rs index 6e0921b7..4a14d9a9 100644 --- a/gossip-lib/src/feed.rs +++ b/gossip-lib/src/feed.rs @@ -367,7 +367,7 @@ impl Feed { if e.created_at < since || e.created_at > now { return false; } - if ! kinds_with_dms.contains(&e.kind) { + if !kinds_with_dms.contains(&e.kind) { return false; } if dismissed.contains(&e.id) { @@ -426,7 +426,7 @@ impl Feed { if dismissed.contains(&e.id) { return false; } - if ! kinds_without_dms.contains(&e.kind) { + if !kinds_without_dms.contains(&e.kind) { return false; } true @@ -439,26 +439,19 @@ impl Feed { &[person_pubkey], Some(since), filter, - false + false, )? .iter() .chain( GLOBALS .storage - .find_tagged_events( - "delegation", - Some(pphex.as_str()), - filter, - false - )? - .iter() + .find_tagged_events("delegation", Some(pphex.as_str()), filter, false)? + .iter(), ) .map(|e| e.to_owned()) .collect(); - events.sort_by(|a,b| b.created_at.cmp(&a.created_at).then( - b.id.cmp(&a.id) - )); + events.sort_by(|a, b| b.created_at.cmp(&a.created_at).then(b.id.cmp(&a.id))); let events: Vec = events.iter().map(|e| e.id).collect(); diff --git a/gossip-lib/src/storage/event_references_person1.rs b/gossip-lib/src/storage/event_references_person1.rs deleted file mode 100644 index f700b838..00000000 --- a/gossip-lib/src/storage/event_references_person1.rs +++ /dev/null @@ -1,163 +0,0 @@ -use crate::error::{Error, ErrorKind}; -use crate::globals::GLOBALS; -use crate::storage::{RawDatabase, Storage}; -use heed::{types::UnalignedSlice, DatabaseFlags, RwTxn}; -use nostr_types::{Event, EventKind, Id, PublicKey, Unixtime}; -use speedy::Readable; -use std::cmp::Ordering; -use std::collections::HashSet; -use std::ops::Bound; -use std::sync::Mutex; - -// PublicKey:ReverseUnixtime -> Id -// (pubkey is referenced by the event somehow) -// (only feed-displayable events are included) -// (dup keys, so multiple Ids per key) -// NOTE: this may be far too much data. Maybe we should only build this for the -// user's pubkey as their inbox. - -static EVENT_REFERENCES_PERSON1_DB_CREATE_LOCK: Mutex<()> = Mutex::new(()); -static mut EVENT_REFERENCES_PERSON1_DB: Option = None; - -impl Storage { - pub(super) fn db_event_references_person1(&self) -> Result { - unsafe { - if let Some(db) = EVENT_REFERENCES_PERSON1_DB { - Ok(db) - } else { - // Lock. This drops when anything returns. - let _lock = EVENT_REFERENCES_PERSON1_DB_CREATE_LOCK.lock(); - - // In case of a race, check again - if let Some(db) = EVENT_REFERENCES_PERSON1_DB { - return Ok(db); - } - - // Create it. We know that nobody else is doing this and that - // it cannot happen twice. - let mut txn = self.env.write_txn()?; - let db = self - .env - .database_options() - .types::, UnalignedSlice>() - .flags(DatabaseFlags::DUP_SORT | DatabaseFlags::DUP_FIXED) - .name("event_references_person") - .create(&mut txn)?; - txn.commit()?; - EVENT_REFERENCES_PERSON1_DB = Some(db); - Ok(db) - } - } - } - - pub(crate) fn write_event_references_person1<'a>( - &'a self, - event: &Event, - rw_txn: Option<&mut RwTxn<'a>>, - ) -> Result<(), Error> { - let f = |txn: &mut RwTxn<'a>| -> Result<(), Error> { - let mut event = event; - - // If giftwrap, index the inner rumor instead - let mut rumor_event: Event; - if event.kind == EventKind::GiftWrap { - match GLOBALS.signer.unwrap_giftwrap(event) { - Ok(rumor) => { - rumor_event = rumor.into_event_with_bad_signature(); - rumor_event.id = event.id; // lie, so it indexes it under the giftwrap - event = &rumor_event; - } - Err(e) => { - if matches!(e.kind, ErrorKind::NoPrivateKey) { - // Store as unindexed for later indexing - let bytes = vec![]; - self.db_unindexed_giftwraps()? - .put(txn, event.id.as_slice(), &bytes)?; - } - } - } - } - - if !event.kind.is_feed_displayable() { - return Ok(()); - } - - let bytes = event.id.as_slice(); - - let mut pubkeys: HashSet = HashSet::new(); - for (pubkeyhex, _, _) in event.people() { - let pubkey = match PublicKey::try_from_hex_string(pubkeyhex.as_str(), false) { - Ok(pk) => pk, - Err(_) => continue, - }; - pubkeys.insert(pubkey); - } - for pubkey in event.people_referenced_in_content() { - pubkeys.insert(pubkey); - } - if !pubkeys.is_empty() { - for pubkey in pubkeys.drain() { - let mut key: Vec = pubkey.to_bytes(); - key.extend((i64::MAX - event.created_at.0).to_be_bytes().as_slice()); // reverse created_at - self.db_event_references_person1()?.put(txn, &key, bytes)?; - } - } - - Ok(()) - }; - - match rw_txn { - Some(txn) => f(txn)?, - None => { - let mut txn = self.env.write_txn()?; - f(&mut txn)?; - txn.commit()?; - } - }; - - Ok(()) - } - - // Read all events referencing a given person in reverse time order - pub(crate) fn read_events_referencing_person1( - &self, - pubkey: &PublicKey, - since: Unixtime, - f: F, - ) -> Result, Error> - where - F: Fn(&Event) -> bool, - { - let txn = self.env.read_txn()?; - let now = Unixtime::now().unwrap(); - let mut start_key: Vec = pubkey.to_bytes(); - let mut end_key: Vec = start_key.clone(); - start_key.extend((i64::MAX - now.0).to_be_bytes().as_slice()); // work back from now - end_key.extend((i64::MAX - since.0).to_be_bytes().as_slice()); // until since - let range = (Bound::Included(&*start_key), Bound::Excluded(&*end_key)); - let iter = self.db_event_references_person1()?.range(&txn, &range)?; - let mut events: Vec = Vec::new(); - for result in iter { - let (_key, val) = result?; - - // Take the event - let id = Id(val[0..32].try_into()?); - // (like read_event, but we supply our on transaction) - if let Some(bytes) = self.db_events1()?.get(&txn, id.as_slice())? { - let event = Event::read_from_buffer(bytes)?; - if f(&event) { - events.push(event); - } - } - } - - // We have to sort these because (pubkey/unixtime) isn't unique. - // The sort should be pretty fast given they are already nearly sorted. - events.sort_by(|a, b| match b.created_at.cmp(&a.created_at) { - Ordering::Equal => b.id.cmp(&a.id), - ordered => ordered, - }); - - Ok(events) - } -} diff --git a/gossip-lib/src/storage/events1.rs b/gossip-lib/src/storage/events1.rs index a6b7d0f5..1c35f7ac 100644 --- a/gossip-lib/src/storage/events1.rs +++ b/gossip-lib/src/storage/events1.rs @@ -59,7 +59,6 @@ impl Storage { self.write_event_ek_pk_index(event, Some(txn))?; self.write_event_ek_c_index(event, Some(txn))?; self.write_event_tag_index(event, Some(txn))?; - self.write_event_references_person(event, Some(txn))?; for hashtag in event.hashtags() { if hashtag.is_empty() { continue; diff --git a/gossip-lib/src/storage/migrations/mod.rs b/gossip-lib/src/storage/migrations/mod.rs index ff3fa02a..08de5bf0 100644 --- a/gossip-lib/src/storage/migrations/mod.rs +++ b/gossip-lib/src/storage/migrations/mod.rs @@ -2,12 +2,13 @@ use super::types::{Person2, PersonRelay1, Settings1, Settings2, Theme1, ThemeVar use super::Storage; use crate::error::{Error, ErrorKind}; use crate::people::PersonList; -use heed::RwTxn; +use heed::types::UnalignedSlice; +use heed::{DatabaseFlags, RwTxn}; use nostr_types::{Event, Id, RelayUrl, Signature}; use speedy::{Readable, Writable}; impl Storage { - const MAX_MIGRATION_LEVEL: u32 = 11; + const MAX_MIGRATION_LEVEL: u32 = 12; pub(super) fn migrate(&self, mut level: u32) -> Result<(), Error> { if level > Self::MAX_MIGRATION_LEVEL { @@ -57,7 +58,6 @@ impl Storage { let _ = self.db_events1()?; let _ = self.db_event_ek_pk_index1()?; let _ = self.db_event_ek_c_index1()?; - let _ = self.db_event_references_person1()?; let _ = self.db_hashtags1()?; } 10 => { @@ -119,6 +119,10 @@ impl Storage { tracing::info!("{prefix}: populating event tag index..."); self.populate_event_tag_index(txn)?; } + 11 => { + tracing::info!("{prefix}: removing now unused event_references_person index..."); + self.remove_event_references_person(txn)?; + } _ => panic!("Unreachable migration level"), }; @@ -535,4 +539,22 @@ impl Storage { Ok(()) } + + pub fn remove_event_references_person<'a>(&'a self, txn: &mut RwTxn<'a>) -> Result<(), Error> { + { + let db = self + .env + .database_options() + .types::, UnalignedSlice>() + .flags(DatabaseFlags::DUP_SORT | DatabaseFlags::DUP_FIXED) + .name("event_references_person") + .create(txn)?; + + db.clear(txn)?; + } + + // heed doesn't expose mdb_drop(1) yet, so we can't actually remove this database. + + Ok(()) + } } diff --git a/gossip-lib/src/storage/mod.rs b/gossip-lib/src/storage/mod.rs index 2214a278..b908e0f1 100644 --- a/gossip-lib/src/storage/mod.rs +++ b/gossip-lib/src/storage/mod.rs @@ -19,7 +19,6 @@ pub mod types; // database implementations mod event_ek_c_index1; mod event_ek_pk_index1; -mod event_references_person1; mod event_seen_on_relay1; mod event_tag_index1; mod event_viewed1; @@ -181,7 +180,6 @@ impl Storage { // triggered into existence if their migration is necessary. let _ = self.db_event_ek_c_index()?; let _ = self.db_event_ek_pk_index()?; - let _ = self.db_event_references_person()?; let _ = self.db_event_tag_index()?; let _ = self.db_events()?; let _ = self.db_event_seen_on_relay()?; @@ -234,11 +232,6 @@ impl Storage { self.db_event_ek_pk_index1() } - #[inline] - pub(crate) fn db_event_references_person(&self) -> Result { - self.db_event_references_person1() - } - #[inline] pub(crate) fn db_event_tag_index(&self) -> Result { self.db_event_tag_index1() @@ -344,12 +337,6 @@ impl Storage { Ok(self.db_event_ek_c_index()?.len(&txn)?) } - /// The number of records in the event_references_person index table - pub fn get_event_references_person_len(&self) -> Result { - let txn = self.env.read_txn()?; - Ok(self.db_event_references_person()?.len(&txn)?) - } - /// The number of records in the event_tag index table pub fn get_event_tag_index_len(&self) -> Result { let txn = self.env.read_txn()?; @@ -1731,30 +1718,6 @@ impl Storage { Ok(events) } - // We don't call this externally. Whenever we write an event, we do this. - #[inline] - fn write_event_references_person<'a>( - &'a self, - event: &Event, - rw_txn: Option<&mut RwTxn<'a>>, - ) -> Result<(), Error> { - self.write_event_references_person1(event, rw_txn) - } - - /// Read all events referencing a given person in reverse time order - #[inline] - pub fn read_events_referencing_person( - &self, - pubkey: &PublicKey, - since: Unixtime, - f: F, - ) -> Result, Error> - where - F: Fn(&Event) -> bool, - { - self.read_events_referencing_person1(pubkey, since, f) - } - #[inline] pub(crate) fn index_unindexed_giftwraps(&self) -> Result<(), Error> { self.index_unindexed_giftwraps1() @@ -2211,7 +2174,6 @@ impl Storage { self.db_event_ek_pk_index()?.clear(txn)?; self.db_event_ek_c_index()?.clear(txn)?; self.db_event_tag_index()?.clear(txn)?; - self.db_event_references_person()?.clear(txn)?; self.db_hashtags()?.clear(txn)?; let loop_txn = self.env.read_txn()?; @@ -2221,7 +2183,6 @@ impl Storage { self.write_event_ek_pk_index(&event, Some(txn))?; self.write_event_ek_c_index(&event, Some(txn))?; self.write_event_tag_index(&event, Some(txn))?; - self.write_event_references_person(&event, Some(txn))?; for hashtag in event.hashtags() { if hashtag.is_empty() { continue; diff --git a/gossip-lib/src/storage/unindexed_giftwraps1.rs b/gossip-lib/src/storage/unindexed_giftwraps1.rs index bc667e53..3fe96d71 100644 --- a/gossip-lib/src/storage/unindexed_giftwraps1.rs +++ b/gossip-lib/src/storage/unindexed_giftwraps1.rs @@ -64,7 +64,6 @@ impl Storage { self.write_event_ek_pk_index(&event, Some(&mut txn))?; self.write_event_ek_c_index(&event, Some(&mut txn))?; self.write_event_tag_index(&event, Some(&mut txn))?; - self.write_event_references_person(&event, Some(&mut txn))?; } self.db_unindexed_giftwraps1()? .delete(&mut txn, id.as_slice())?; From 912a91467577801ad5a47051d645f977d2b08438 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Sat, 7 Oct 2023 10:51:17 +1300 Subject: [PATCH 30/46] Add latest message content to DmChannelData --- gossip-bin/src/ui/dm_chat_list.rs | 14 ++++--- gossip-lib/src/dm_channel.rs | 3 +- gossip-lib/src/storage/mod.rs | 68 +++++++++++++++++++------------ 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/gossip-bin/src/ui/dm_chat_list.rs b/gossip-bin/src/ui/dm_chat_list.rs index 10a16644..d18cfce1 100644 --- a/gossip-bin/src/ui/dm_chat_list.rs +++ b/gossip-bin/src/ui/dm_chat_list.rs @@ -32,14 +32,16 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr )); ui.label( - RichText::new(crate::date_ago::date_ago(channeldata.latest_message)) - .italics() - .weak(), + RichText::new(crate::date_ago::date_ago( + channeldata.latest_message_created_at, + )) + .italics() + .weak(), ) .on_hover_ui(|ui| { - if let Ok(stamp) = - time::OffsetDateTime::from_unix_timestamp(channeldata.latest_message.0) - { + if let Ok(stamp) = time::OffsetDateTime::from_unix_timestamp( + channeldata.latest_message_created_at.0, + ) { if let Ok(formatted) = stamp.format(&time::format_description::well_known::Rfc2822) { diff --git a/gossip-lib/src/dm_channel.rs b/gossip-lib/src/dm_channel.rs index 5d75b092..7d89ba4a 100644 --- a/gossip-lib/src/dm_channel.rs +++ b/gossip-lib/src/dm_channel.rs @@ -112,7 +112,8 @@ impl DmChannel { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct DmChannelData { pub dm_channel: DmChannel, - pub latest_message: Unixtime, + pub latest_message_created_at: Unixtime, + pub latest_message_content: String, pub message_count: usize, pub unread_message_count: usize, } diff --git a/gossip-lib/src/storage/mod.rs b/gossip-lib/src/storage/mod.rs index b908e0f1..b5462d14 100644 --- a/gossip-lib/src/storage/mod.rs +++ b/gossip-lib/src/storage/mod.rs @@ -2094,18 +2094,25 @@ impl Storage { Some(dmc) => dmc, None => continue, }; - map.entry(dmchannel.clone()) - .and_modify(|d| { - d.latest_message = d.latest_message.max(time); - d.message_count += 1; - d.unread_message_count += unread; - }) - .or_insert(DmChannelData { - dm_channel: dmchannel, - latest_message: time, - message_count: 1, - unread_message_count: unread, - }); + if let Some(dmcdata) = map.get_mut(&dmchannel) { + if time > dmcdata.latest_message_created_at { + dmcdata.latest_message_created_at = time; + dmcdata.latest_message_content = GLOBALS.signer.decrypt_message(event)?; + } + dmcdata.message_count += 1; + dmcdata.unread_message_count += unread; + } else { + map.insert( + dmchannel.clone(), + DmChannelData { + dm_channel: dmchannel, + latest_message_created_at: time, + latest_message_content: GLOBALS.signer.decrypt_message(event)?, + message_count: 1, + unread_message_count: unread, + }, + ); + } } else if event.kind == EventKind::GiftWrap { if let Ok(rumor) = GLOBALS.signer.unwrap_giftwrap(event) { let rumor_event = rumor.into_event_with_bad_signature(); @@ -2114,24 +2121,35 @@ impl Storage { Some(dmc) => dmc, None => continue, }; - map.entry(dmchannel.clone()) - .and_modify(|d| { - d.latest_message = d.latest_message.max(time); - d.message_count += 1; - d.unread_message_count += unread; - }) - .or_insert(DmChannelData { - dm_channel: dmchannel, - latest_message: time, - message_count: 1, - unread_message_count: unread, - }); + if let Some(dmcdata) = map.get_mut(&dmchannel) { + if time > dmcdata.latest_message_created_at { + dmcdata.latest_message_created_at = time; + dmcdata.latest_message_content = rumor_event.content.clone(); + } + dmcdata.message_count += 1; + dmcdata.unread_message_count += unread; + } else { + map.insert( + dmchannel.clone(), + DmChannelData { + dm_channel: dmchannel, + latest_message_created_at: time, + latest_message_content: rumor_event.content.clone(), + message_count: 1, + unread_message_count: unread, + }, + ); + } } } } let mut output: Vec = map.drain().map(|e| e.1).collect(); - output.sort_by(|a, b| b.latest_message.cmp(&a.latest_message)); + output.sort_by(|a, b| { + b.latest_message_created_at + .cmp(&a.latest_message_created_at) + .then(b.unread_message_count.cmp(&a.unread_message_count)) + }); Ok(output) } From dbead00d0786790d12d3eff4af51d1c1c94b7515 Mon Sep 17 00:00:00 2001 From: Daniele Tonon Date: Sat, 7 Oct 2023 15:18:24 +0200 Subject: [PATCH 31/46] Uniform view's titles --- gossip-bin/src/ui/feed/mod.rs | 29 ++++++++++++++++------------- gossip-bin/src/ui/help/mod.rs | 2 +- gossip-bin/src/ui/help/stats.rs | 2 +- gossip-bin/src/ui/help/theme.rs | 2 +- gossip-bin/src/ui/people/follow.rs | 7 +++++-- gossip-bin/src/ui/relays/active.rs | 2 ++ gossip-bin/src/ui/relays/known.rs | 1 + gossip-bin/src/ui/relays/mine.rs | 1 + gossip-bin/src/ui/search.rs | 1 + gossip-bin/src/ui/settings/mod.rs | 1 + gossip-bin/src/ui/you/delegation.rs | 7 ++++++- gossip-bin/src/ui/you/metadata.rs | 8 ++++++-- gossip-bin/src/ui/you/mod.rs | 2 +- 13 files changed, 43 insertions(+), 22 deletions(-) diff --git a/gossip-bin/src/ui/feed/mod.rs b/gossip-bin/src/ui/feed/mod.rs index 9eaf92d3..191465e9 100644 --- a/gossip-bin/src/ui/feed/mod.rs +++ b/gossip-bin/src/ui/feed/mod.rs @@ -55,17 +55,17 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram FeedKind::Followed(with_replies) => { let feed = GLOBALS.feed.get_followed(); let id = if with_replies { "main" } else { "general" }; - + ui.add_space(10.0); ui.allocate_ui_with_layout( Vec2::new(ui.available_width(), ui.spacing().interact_size.y), egui::Layout::left_to_right(egui::Align::Center), |ui| { add_left_space(ui); - ui.label("Main Feed"); + ui.heading("Main feed"); recompute_btn(app, ui); ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { - ui.add_space(16.0); + ui.add_space(10.0); ui.label(RichText::new("Include replies").size(11.0)); let size = ui.spacing().interact_size.y * egui::vec2(1.6, 0.8); if crate::ui::components::switch_with_size( @@ -89,7 +89,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram }); }, ); - ui.add_space(4.0); + ui.add_space(6.0); render_a_feed(app, ctx, frame, ui, feed, false, id); } FeedKind::Inbox(indirect) => { @@ -104,17 +104,17 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram } let feed = GLOBALS.feed.get_inbox(); let id = if indirect { "activity" } else { "inbox" }; - + ui.add_space(10.0); ui.allocate_ui_with_layout( Vec2::new(ui.available_width(), ui.spacing().interact_size.y), egui::Layout::left_to_right(egui::Align::Center), |ui| { add_left_space(ui); - ui.label("Inbox"); + ui.heading("Inbox"); recompute_btn(app, ui); ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { - ui.add_space(16.0); + ui.add_space(10.0); ui.label(RichText::new("Everything").size(11.0)); let size = ui.spacing().interact_size.y * egui::vec2(1.6, 0.8); if crate::ui::components::switch_with_size( @@ -136,23 +136,26 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram }); }, ); - ui.add_space(4.0); + ui.add_space(6.0); render_a_feed(app, ctx, frame, ui, feed, false, id); } FeedKind::Thread { id, .. } => { - ui.horizontal(|ui| { - ui.label("Thread"); - recompute_btn(app, ui); - }); if let Some(parent) = GLOBALS.feed.get_thread_parent() { render_a_feed(app, ctx, frame, ui, vec![parent], true, &id.as_hex_string()); } } FeedKind::Person(pubkey) => { + ui.add_space(10.0); ui.horizontal(|ui| { - ui.label(gossip_lib::names::tag_name_from_pubkey_lookup(&pubkey)); + add_left_space(ui); + if Some(pubkey) == GLOBALS.signer.public_key() { + ui.heading("My notes"); + } else { + ui.heading(gossip_lib::names::tag_name_from_pubkey_lookup(&pubkey)); + } recompute_btn(app, ui); }); + ui.add_space(6.0); let feed = GLOBALS.feed.get_person_feed(); render_a_feed(app, ctx, frame, ui, feed, false, &pubkey.as_hex_string()); diff --git a/gossip-bin/src/ui/help/mod.rs b/gossip-bin/src/ui/help/mod.rs index 52254ac8..fcd6f520 100644 --- a/gossip-bin/src/ui/help/mod.rs +++ b/gossip-bin/src/ui/help/mod.rs @@ -9,7 +9,7 @@ mod theme; pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { if app.page == Page::HelpHelp { - ui.add_space(24.0); + ui.add_space(10.0); ui.heading("Help - Getting Started"); ui.add_space(12.0); ui.separator(); diff --git a/gossip-bin/src/ui/help/stats.rs b/gossip-bin/src/ui/help/stats.rs index a312f739..de011dec 100644 --- a/gossip-bin/src/ui/help/stats.rs +++ b/gossip-bin/src/ui/help/stats.rs @@ -6,7 +6,7 @@ use humansize::{format_size, DECIMAL}; use std::sync::atomic::Ordering; pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { - ui.add_space(24.0); + ui.add_space(10.0); ui.heading("Statistics".to_string()); ui.add_space(12.0); ui.separator(); diff --git a/gossip-bin/src/ui/help/theme.rs b/gossip-bin/src/ui/help/theme.rs index f50759ee..a8639228 100644 --- a/gossip-bin/src/ui/help/theme.rs +++ b/gossip-bin/src/ui/help/theme.rs @@ -15,7 +15,7 @@ enum Background { } pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { - ui.add_space(24.0); + ui.add_space(10.0); ui.heading("Theme Test".to_string()); ui.add_space(12.0); ui.separator(); diff --git a/gossip-bin/src/ui/people/follow.rs b/gossip-bin/src/ui/people/follow.rs index 1845dd71..5dbeab7c 100644 --- a/gossip-bin/src/ui/people/follow.rs +++ b/gossip-bin/src/ui/people/follow.rs @@ -6,9 +6,12 @@ use gossip_lib::GLOBALS; use nostr_types::{Profile, PublicKey}; pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { - ui.add_space(30.0); + ui.add_space(10.0); + ui.horizontal_wrapped(|ui| { + ui.add_space(2.0); + ui.heading("Follow Someone"); + }); - ui.heading("Follow Someone"); ui.add_space(10.0); ui.label( diff --git a/gossip-bin/src/ui/relays/active.rs b/gossip-bin/src/ui/relays/active.rs index a93af9a9..9bf38514 100644 --- a/gossip-bin/src/ui/relays/active.rs +++ b/gossip-bin/src/ui/relays/active.rs @@ -15,6 +15,7 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr ui.add_space(10.0); ui.horizontal_wrapped(|ui| { ui.with_layout(egui::Layout::left_to_right(egui::Align::Center), |ui| { + ui.add_space(2.0); ui.heading(Page::RelaysActivityMonitor.name()); ui.set_enabled(!is_editing); }); @@ -83,3 +84,4 @@ fn get_relays(app: &mut GossipUi) -> Vec { relays.sort_by(|a, b| super::sort_relay(&app.relays, a, b)); relays } + diff --git a/gossip-bin/src/ui/relays/known.rs b/gossip-bin/src/ui/relays/known.rs index ce29b8a6..9a9177ca 100644 --- a/gossip-bin/src/ui/relays/known.rs +++ b/gossip-bin/src/ui/relays/known.rs @@ -10,6 +10,7 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr let is_editing = app.relays.edit.is_some(); ui.add_space(10.0); ui.horizontal_wrapped(|ui| { + ui.add_space(2.0); ui.heading(Page::RelaysKnownNetwork.name()); ui.set_enabled(!is_editing); ui.with_layout(egui::Layout::right_to_left(egui::Align::Min), |ui| { diff --git a/gossip-bin/src/ui/relays/mine.rs b/gossip-bin/src/ui/relays/mine.rs index 77a0579d..3096105d 100644 --- a/gossip-bin/src/ui/relays/mine.rs +++ b/gossip-bin/src/ui/relays/mine.rs @@ -11,6 +11,7 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr let is_editing = app.relays.edit.is_some(); ui.add_space(10.0); ui.horizontal_wrapped(|ui| { + ui.add_space(2.0); ui.heading(Page::RelaysMine.name()); ui.set_enabled(!is_editing); ui.with_layout(egui::Layout::right_to_left(egui::Align::Min), |ui| { diff --git a/gossip-bin/src/ui/search.rs b/gossip-bin/src/ui/search.rs index 69e742a4..53b69523 100644 --- a/gossip-bin/src/ui/search.rs +++ b/gossip-bin/src/ui/search.rs @@ -9,6 +9,7 @@ use gossip_lib::GLOBALS; use std::sync::atomic::Ordering; pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut Frame, ui: &mut Ui) { + ui.add_space(10.0); ui.heading("Search notes and users"); ui.add_space(12.0); diff --git a/gossip-bin/src/ui/settings/mod.rs b/gossip-bin/src/ui/settings/mod.rs index c28fbcc3..7f13f7ff 100644 --- a/gossip-bin/src/ui/settings/mod.rs +++ b/gossip-bin/src/ui/settings/mod.rs @@ -11,6 +11,7 @@ mod posting; mod ui; pub(super) fn update(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Frame, ui: &mut Ui) { + ui.add_space(10.0); ui.heading("Settings"); ui.with_layout(Layout::right_to_left(Align::Min), |ui| { diff --git a/gossip-bin/src/ui/you/delegation.rs b/gossip-bin/src/ui/you/delegation.rs index cc61f498..2bfcd0ab 100644 --- a/gossip-bin/src/ui/you/delegation.rs +++ b/gossip-bin/src/ui/you/delegation.rs @@ -6,7 +6,12 @@ use gossip_lib::GLOBALS; use tokio::task; pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { - ui.heading("Delegatee"); + ui.add_space(10.0); + ui.horizontal_wrapped(|ui| { + // ui.add_space(2.0); + ui.heading("Delegatee"); + }); + ui.add_space(10.0); ui.label("If NIP-26 Delegation is set, I will post on behalf of the delegator"); ui.add_space(24.0); diff --git a/gossip-bin/src/ui/you/metadata.rs b/gossip-bin/src/ui/you/metadata.rs index 6ce00093..6b18a887 100644 --- a/gossip-bin/src/ui/you/metadata.rs +++ b/gossip-bin/src/ui/you/metadata.rs @@ -14,8 +14,12 @@ lazy_static! { } pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { - ui.add_space(24.0); - + ui.add_space(10.0); + ui.horizontal_wrapped(|ui| { + // ui.add_space(2.0); + ui.heading("My profile"); + }); + ui.add_space(10.0); let public_key = match GLOBALS.signer.public_key() { Some(pk) => pk, None => { diff --git a/gossip-bin/src/ui/you/mod.rs b/gossip-bin/src/ui/you/mod.rs index f0847822..b3894313 100644 --- a/gossip-bin/src/ui/you/mod.rs +++ b/gossip-bin/src/ui/you/mod.rs @@ -14,7 +14,7 @@ mod metadata; pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { if app.page == Page::YourKeys { ui.add_space(10.0); - ui.heading("Your Keys"); + ui.heading("My Keys"); ui.add_space(10.0); ui.separator(); From b5cae086ee4713139ea90d2510840bafebd20574 Mon Sep 17 00:00:00 2001 From: Daniele Tonon Date: Sat, 7 Oct 2023 18:12:27 +0200 Subject: [PATCH 32/46] Restyle a little the profile page --- gossip-bin/src/ui/feed/note/mod.rs | 2 +- gossip-bin/src/ui/mod.rs | 52 ++++---- gossip-bin/src/ui/people/followed.rs | 2 +- gossip-bin/src/ui/people/muted.rs | 2 +- gossip-bin/src/ui/people/person.rs | 182 +++++++++++++++------------ gossip-bin/src/ui/search.rs | 4 +- 6 files changed, 138 insertions(+), 106 deletions(-) diff --git a/gossip-bin/src/ui/feed/note/mod.rs b/gossip-bin/src/ui/feed/note/mod.rs index 4e514e54..9123beb5 100644 --- a/gossip-bin/src/ui/feed/note/mod.rs +++ b/gossip-bin/src/ui/feed/note/mod.rs @@ -284,7 +284,7 @@ fn render_note_inner( ui.add_space(3.0); - GossipUi::render_person_name_line(app, ui, ¬e.author); + GossipUi::render_person_name_line(app, ui, ¬e.author, false); ui.horizontal_wrapped(|ui| { if let Some((irt, _)) = note.event.replies_to() { diff --git a/gossip-bin/src/ui/mod.rs b/gossip-bin/src/ui/mod.rs index 6c29a161..70af7d23 100644 --- a/gossip-bin/src/ui/mod.rs +++ b/gossip-bin/src/ui/mod.rs @@ -1100,7 +1100,7 @@ impl GossipUi { ui.set_enabled(!relays::is_entry_dialog_active(self)); } - pub fn render_person_name_line(app: &mut GossipUi, ui: &mut Ui, person: &Person) { + pub fn render_person_name_line(app: &mut GossipUi, ui: &mut Ui, person: &Person, profile_page: bool) { // Let the 'People' manager know that we are interested in displaying this person. // It will take all actions necessary to make the data eventually available. GLOBALS.people.person_of_interest(person.pubkey); @@ -1115,16 +1115,22 @@ impl GossipUi { }; let tag_name_menu = { - let text = match &person.petname { - Some(pn) => pn.to_owned(), - None => gossip_lib::names::tag_name_from_person(person), + let text = if !profile_page { + match &person.petname { + Some(pn) => pn.to_owned(), + None => gossip_lib::names::tag_name_from_person(person), + } + } else { + "ACTIONS".to_string() }; RichText::new(format!("☰ {}", text)) }; ui.menu_button(tag_name_menu, |ui| { - if ui.button("View Person").clicked() { - app.set_page(Page::Person(person.pubkey)); + if !profile_page { + if ui.button("View Person").clicked() { + app.set_page(Page::Person(person.pubkey)); + } } if app.page != Page::Feed(FeedKind::Person(person.pubkey)) { if ui.button("View Their Posts").clicked() { @@ -1183,23 +1189,25 @@ impl GossipUi { .on_hover_text("followed"); } - if let Some(mut nip05) = person.nip05().map(|s| s.to_owned()) { - if nip05.starts_with("_@") { - nip05 = nip05.get(2..).unwrap().to_string(); - } + if !profile_page { + if let Some(mut nip05) = person.nip05().map(|s| s.to_owned()) { + if nip05.starts_with("_@") { + nip05 = nip05.get(2..).unwrap().to_string(); + } - ui.with_layout( - Layout::left_to_right(Align::Min) - .with_cross_align(Align::Center) - .with_cross_justify(true), - |ui| { - if person.nip05_valid { - ui.label(RichText::new(nip05).monospace().small()); - } else { - ui.label(RichText::new(nip05).monospace().small().strikethrough()); - } - }, - ); + ui.with_layout( + Layout::left_to_right(Align::Min) + .with_cross_align(Align::Center) + .with_cross_justify(true), + |ui| { + if person.nip05_valid { + ui.label(RichText::new(nip05).monospace().small()); + } else { + ui.label(RichText::new(nip05).monospace().small().strikethrough()); + } + }, + ); + } } }); } diff --git a/gossip-bin/src/ui/people/followed.rs b/gossip-bin/src/ui/people/followed.rs index 4983dcbf..64ff3fad 100644 --- a/gossip-bin/src/ui/people/followed.rs +++ b/gossip-bin/src/ui/people/followed.rs @@ -181,7 +181,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra ui.vertical(|ui| { ui.label(RichText::new(gossip_lib::names::pubkey_short(&person.pubkey)).weak()); - GossipUi::render_person_name_line(app, ui, person); + GossipUi::render_person_name_line(app, ui, person, false); if !GLOBALS .storage .have_persons_relays(person.pubkey) diff --git a/gossip-bin/src/ui/people/muted.rs b/gossip-bin/src/ui/people/muted.rs index ab5e203f..e9013f1f 100644 --- a/gossip-bin/src/ui/people/muted.rs +++ b/gossip-bin/src/ui/people/muted.rs @@ -149,7 +149,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra ui.vertical(|ui| { ui.label(RichText::new(gossip_lib::names::pubkey_short(&person.pubkey)).weak()); - GossipUi::render_person_name_line(app, ui, person); + GossipUi::render_person_name_line(app, ui, person, false); if ui.button("UNMUTE").clicked() { let _ = GLOBALS.people.mute(&person.pubkey, false); diff --git a/gossip-bin/src/ui/people/person.rs b/gossip-bin/src/ui/people/person.rs index b1fbc6f4..28d58969 100644 --- a/gossip-bin/src/ui/people/person.rs +++ b/gossip-bin/src/ui/people/person.rs @@ -34,63 +34,51 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra } fn content(app: &mut GossipUi, ctx: &Context, ui: &mut Ui, pubkey: PublicKey, person: Person) { - ui.add_space(24.0); - - ui.horizontal(|ui| { - // Avatar first - let avatar = if let Some(avatar) = app.try_get_avatar(ctx, &pubkey) { - avatar - } else { - app.placeholder_avatar.clone() - }; - ui.add( - Image::new(&avatar) - .max_size(Vec2 { - x: AVATAR_SIZE_F32 * 3.0, - y: AVATAR_SIZE_F32 * 3.0, - }) - .maintain_aspect_ratio(true), - ); - ui.vertical(|ui| { - let display_name = gossip_lib::names::display_name_from_person(&person); - ui.heading(display_name); - ui.label(RichText::new(gossip_lib::names::pubkey_short(&pubkey)).weak()); - GossipUi::render_person_name_line(app, ui, &person); - - ui.horizontal(|ui| { - ui.add_space(12.0); - ui.label("Pet name:"); - if app.editing_petname { - let edit_color = app.theme.input_text_color(); - ui.add(TextEdit::singleline(&mut app.petname).text_color(edit_color)); - if ui.button("save").clicked() { - let mut person = person.clone(); - person.petname = Some(app.petname.clone()); - if let Err(e) = GLOBALS.storage.write_person(&person, None) { - GLOBALS.status_queue.write().write(format!("{}", e)); - } - app.editing_petname = false; - app.notes.cache_invalidate_person(&person.pubkey); - } - if ui.button("cancel").clicked() { - app.editing_petname = false; - } - if ui.button("remove").clicked() { - let mut person = person.clone(); - person.petname = None; - if let Err(e) = GLOBALS.storage.write_person(&person, None) { - GLOBALS.status_queue.write().write(format!("{}", e)); - } - app.editing_petname = false; - app.notes.cache_invalidate_person(&person.pubkey); - } - } else { - match &person.petname { - Some(pn) => { - ui.label(pn); - if ui.button("edit").clicked() { - app.editing_petname = true; - app.petname = pn.to_owned(); + ui.vertical(|ui| { + ui.add_space(10.0); + ui.allocate_ui_with_layout( + Vec2::new(ui.available_width(), ui.spacing().interact_size.y), + egui::Layout::right_to_left(egui::Align::Center), + |ui| { + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + let avatar = if let Some(avatar) = app.try_get_avatar(ctx, &pubkey) { + avatar + } else { + app.placeholder_avatar.clone() + }; + ui.horizontal(|ui| { + ui.add_space(20.0); + ui.add( + Image::new(&avatar) + .max_size(Vec2 { + x: AVATAR_SIZE_F32 * 3.0, + y: AVATAR_SIZE_F32 * 3.0, + }) + .maintain_aspect_ratio(true), + ); + }); + }); + ui.vertical(|ui| { + let display_name = gossip_lib::names::display_name_from_person(&person); + ui.heading(display_name); + ui.label(RichText::new(gossip_lib::names::pubkey_short(&pubkey))); + ui.add_space(10.0); + ui.horizontal(|ui| { + ui.label("Pet name:"); + if app.editing_petname { + let edit_color = app.theme.input_text_color(); + ui.add(TextEdit::singleline(&mut app.petname).text_color(edit_color)); + if ui.button("save").clicked() { + let mut person = person.clone(); + person.petname = Some(app.petname.clone()); + if let Err(e) = GLOBALS.storage.write_person(&person, None) { + GLOBALS.status_queue.write().write(format!("{}", e)); + } + app.editing_petname = false; + app.notes.cache_invalidate_person(&person.pubkey); + } + if ui.button("cancel").clicked() { + app.editing_petname = false; } if ui.button("remove").clicked() { let mut person = person.clone(); @@ -98,23 +86,71 @@ fn content(app: &mut GossipUi, ctx: &Context, ui: &mut Ui, pubkey: PublicKey, pe if let Err(e) = GLOBALS.storage.write_person(&person, None) { GLOBALS.status_queue.write().write(format!("{}", e)); } + app.editing_petname = false; app.notes.cache_invalidate_person(&person.pubkey); } - } - None => { - ui.label(RichText::new("none").italics()); - if ui.button("add").clicked() { - app.editing_petname = true; - app.petname = "".to_owned(); + } else { + match &person.petname { + Some(pn) => { + ui.label(pn); + if ui.button("edit").clicked() { + app.editing_petname = true; + app.petname = pn.to_owned(); + } + if ui.button("remove").clicked() { + let mut person = person.clone(); + person.petname = None; + if let Err(e) = GLOBALS.storage.write_person(&person, None) { + GLOBALS.status_queue.write().write(format!("{}", e)); + } + app.notes.cache_invalidate_person(&person.pubkey); + } + } + None => { + ui.label(RichText::new("none").italics()); + if ui.button("add").clicked() { + app.editing_petname = true; + app.petname = "".to_owned(); + } + } } } + }); + + ui.add_space(10.0); + { + let visuals = ui.visuals_mut(); + visuals.widgets.inactive.weak_bg_fill = app.theme.accent_color(); + visuals.widgets.inactive.fg_stroke.width = 1.0; + visuals.widgets.inactive.fg_stroke.color = + app.theme.get_style().visuals.extreme_bg_color; + visuals.widgets.hovered.weak_bg_fill = app.theme.navigation_text_color(); + visuals.widgets.hovered.fg_stroke.color = app.theme.accent_color(); + visuals.widgets.inactive.fg_stroke.color = + app.theme.get_style().visuals.extreme_bg_color; + GossipUi::render_person_name_line(app, ui, &person, true); } - } - }); - }); + + if let Some(about) = person.about() { + ui.add_space(10.0); + ui.separator(); + ui.add_space(10.0); + ui.horizontal_wrapped(|ui| { + ui.label(about); + if ui.add(CopyButton {}).on_hover_text("Copy About").clicked() { + ui.output_mut(|o| o.copied_text = about.to_owned()); + } + }); + } + }); + }, + ); + }); - ui.add_space(12.0); + ui.add_space(10.0); + ui.separator(); + ui.add_space(10.0); let npub = pubkey.as_bech32_string(); ui.horizontal_wrapped(|ui| { @@ -143,18 +179,6 @@ fn content(app: &mut GossipUi, ctx: &Context, ui: &mut Ui, pubkey: PublicKey, pe }); } - if let Some(about) = person.about() { - ui.label(RichText::new("About: ").strong()); - Frame::group(ui.style()).show(ui, |ui| { - ui.horizontal_wrapped(|ui| { - ui.label(about); - if ui.add(CopyButton {}).on_hover_text("Copy About").clicked() { - ui.output_mut(|o| o.copied_text = about.to_owned()); - } - }); - }); - } - if let Some(picture) = person.picture() { ui.horizontal_wrapped(|ui| { ui.label(RichText::new("Picture: ").strong()); diff --git a/gossip-bin/src/ui/search.rs b/gossip-bin/src/ui/search.rs index 69e742a4..1e90ab5b 100644 --- a/gossip-bin/src/ui/search.rs +++ b/gossip-bin/src/ui/search.rs @@ -81,7 +81,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut Frame, ui: ui.label( RichText::new(gossip_lib::names::pubkey_short(&person.pubkey)).weak(), ); - GossipUi::render_person_name_line(app, ui, person); + GossipUi::render_person_name_line(app, ui, person, false); }); }); } @@ -101,7 +101,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut Frame, ui: ); if let Ok(Some(person)) = GLOBALS.storage.read_person(&event.pubkey) { - GossipUi::render_person_name_line(app, ui, &person); + GossipUi::render_person_name_line(app, ui, &person, false); } else { ui.label(event.pubkey.as_bech32_string()); } From 5fbd800356af162088d005c4ca711530063f453b Mon Sep 17 00:00:00 2001 From: Daniele Tonon Date: Sat, 7 Oct 2023 22:32:14 +0200 Subject: [PATCH 33/46] Update popover styles --- gossip-bin/src/ui/relays/mod.rs | 3 ++- gossip-bin/src/ui/theme/default.rs | 26 +++++++++++++++++--------- gossip-bin/src/ui/theme/mod.rs | 8 +++++++- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/gossip-bin/src/ui/relays/mod.rs b/gossip-bin/src/ui/relays/mod.rs index 3788b341..9ec2d51b 100644 --- a/gossip-bin/src/ui/relays/mod.rs +++ b/gossip-bin/src/ui/relays/mod.rs @@ -487,7 +487,7 @@ pub(super) fn configure_list_btn(app: &mut GossipUi, ui: &mut Ui) { frame.stroke = egui::Stroke::NONE; // frame.shadow = egui::epaint::Shadow::NONE; frame.rounding = egui::Rounding::same(5.0); - frame.inner_margin = egui::Margin::symmetric(20.0, 10.0); + frame.inner_margin = egui::Margin::symmetric(20.0, 16.0); frame.show(ui, |ui| { let path = PathShape::convex_polygon( [ button_center_bottom, @@ -506,6 +506,7 @@ pub(super) fn configure_list_btn(app: &mut GossipUi, ui: &mut Ui) { crate::ui::components::switch_with_size(ui, &mut app.relays.show_details, size); ui.label("Show details"); }); + ui.add_space(8.0); ui.horizontal(|ui|{ crate::ui::components::switch_with_size(ui, &mut app.relays.show_hidden, size); ui.label("Show hidden relays"); diff --git a/gossip-bin/src/ui/theme/default.rs b/gossip-bin/src/ui/theme/default.rs index e24dca50..43391467 100644 --- a/gossip-bin/src/ui/theme/default.rs +++ b/gossip-bin/src/ui/theme/default.rs @@ -278,19 +278,27 @@ impl ThemeDef for DefaultTheme { /// the style to use when displaying on-top of an accent-colored background fn get_on_accent_style(dark_mode: bool) -> Style { - let mut style = Self::get_style(!dark_mode); + let mut style = Self::get_style(dark_mode); if dark_mode { - // TODO style dark mode - } else { - style.visuals.widgets.noninteractive.fg_stroke.color = Color32::WHITE; + style.visuals.widgets.noninteractive.fg_stroke.color = style.visuals.window_fill; style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.inactive.fg_stroke.color = Self::navigation_text_color(dark_mode); + style.visuals.widgets.inactive.fg_stroke = Stroke::new(0.0, style.visuals.panel_fill.gamma_multiply(0.6)); style.visuals.widgets.active.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.active.fg_stroke.color = Self::navigation_text_active_color(dark_mode); - style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(8); - style.visuals.widgets.hovered.fg_stroke.color = Self::navigation_text_hover_color(dark_mode); + style.visuals.widgets.active.fg_stroke.color = style.visuals.window_fill; + style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(2); + style.visuals.widgets.hovered.fg_stroke.color = style.visuals.panel_fill.gamma_multiply(0.6); style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); - style.visuals.selection.stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); + style.visuals.selection.stroke = Stroke::new(0.0, style.visuals.window_fill); + } else { + style.visuals.widgets.noninteractive.fg_stroke.color = style.visuals.panel_fill; + style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); + style.visuals.widgets.inactive.fg_stroke = Stroke::new(0.0, style.visuals.panel_fill.gamma_multiply(0.6)); + style.visuals.widgets.active.bg_fill = style.visuals.panel_fill.gamma_multiply(0.6); + style.visuals.widgets.active.fg_stroke.color = style.visuals.window_fill; + style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(2); + style.visuals.widgets.hovered.fg_stroke.color = style.visuals.panel_fill.gamma_multiply(0.6); + style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); + style.visuals.selection.stroke = Stroke::new(0.0, style.visuals.panel_fill); } style } diff --git a/gossip-bin/src/ui/theme/mod.rs b/gossip-bin/src/ui/theme/mod.rs index 1fa35b10..87ac22c8 100644 --- a/gossip-bin/src/ui/theme/mod.rs +++ b/gossip-bin/src/ui/theme/mod.rs @@ -4,7 +4,7 @@ use eframe::egui::{ Color32, Context, FontData, FontDefinitions, FontTweak, Margin, Rounding, Stroke, Style, TextFormat, TextStyle, Ui, }; -use eframe::epaint::{FontFamily, FontId, Shadow}; +use eframe::epaint::{ecolor, FontFamily, FontId, Shadow}; use gossip_lib::Settings; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -412,6 +412,12 @@ pub trait ThemeDef: Send + Sync { // image rounding fn round_image() -> bool; + + fn darken_color(color: Color32, factor: f32) -> Color32 { + let mut hsva: ecolor::HsvaGamma = color.into(); + hsva.v = (hsva.v * factor).max(0.0).min(1.0); + hsva.into() + } } pub(super) fn font_definitions() -> FontDefinitions { From 31ac81f496801ca71599e3462f945313eff3d75b Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Sun, 8 Oct 2023 12:23:21 +1300 Subject: [PATCH 34/46] minor spacing --- gossip-bin/src/ui/people/person.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gossip-bin/src/ui/people/person.rs b/gossip-bin/src/ui/people/person.rs index 28d58969..2bf50f65 100644 --- a/gossip-bin/src/ui/people/person.rs +++ b/gossip-bin/src/ui/people/person.rs @@ -299,6 +299,8 @@ fn content(app: &mut GossipUi, ctx: &Context, ui: &mut Ui, pubkey: PublicKey, pe } } }); + + ui.add_space(10.0); } } if need_to_set_active_person && !app.setting_active_person { From 22808aa1c01645accf87022c7deb264070dc6154 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Sun, 8 Oct 2023 18:57:58 +1300 Subject: [PATCH 35/46] Fix error on DM Chat page when key is not unlocked --- gossip-bin/src/ui/dm_chat_list.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gossip-bin/src/ui/dm_chat_list.rs b/gossip-bin/src/ui/dm_chat_list.rs index d18cfce1..2c8135ab 100644 --- a/gossip-bin/src/ui/dm_chat_list.rs +++ b/gossip-bin/src/ui/dm_chat_list.rs @@ -2,12 +2,17 @@ use super::{GossipUi, Page}; use eframe::egui; use egui::{Context, Label, RichText, Sense, Ui}; use gossip_lib::DmChannelData; +use gossip_lib::{Error, ErrorKind}; use gossip_lib::FeedKind; use gossip_lib::GLOBALS; pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { let mut channels: Vec = match GLOBALS.storage.dm_channels() { Ok(channels) => channels, + Err(Error { kind: ErrorKind::NoPrivateKey, .. }) => { + ui.label("Private Key Not Available"); + return; + }, Err(_) => { ui.label("ERROR"); return; From 84836eee97206fb930b03a7b6638cc6de4133eab Mon Sep 17 00:00:00 2001 From: Daniele Tonon Date: Sun, 8 Oct 2023 16:16:16 +0200 Subject: [PATCH 36/46] Remove accent color from the sidebar --- gossip-bin/src/ui/mod.rs | 4 +-- gossip-bin/src/ui/theme/classic.rs | 8 +++++ gossip-bin/src/ui/theme/default.rs | 49 ++++++++++++++++++------------ gossip-bin/src/ui/theme/mod.rs | 7 +++++ gossip-bin/src/ui/theme/roundy.rs | 8 +++++ 5 files changed, 54 insertions(+), 22 deletions(-) diff --git a/gossip-bin/src/ui/mod.rs b/gossip-bin/src/ui/mod.rs index 70af7d23..a7a8e6f8 100644 --- a/gossip-bin/src/ui/mod.rs +++ b/gossip-bin/src/ui/mod.rs @@ -734,7 +734,7 @@ impl GossipUi { ui.add_space(4.0); let back_label_text = RichText::new("‹ Back"); - let label = if self.history.is_empty() { Label::new(back_label_text.color(Color32::from_white_alpha(8))) } else { Label::new(back_label_text.color(self.theme.navigation_text_color())).sense(Sense::click()) }; + let label = if self.history.is_empty() { Label::new(back_label_text.color(self.theme.navigation_text_deactivated_color())) } else { Label::new(back_label_text.color(self.theme.navigation_text_color())).sense(Sense::click()) }; let response = ui.add(label); let response = if let Some(page) = self.history.last() { response.on_hover_text(format!("back to {}", page.to_short_string())) @@ -889,7 +889,7 @@ impl GossipUi { .shadow(egui::epaint::Shadow::NONE) .show(ui, |ui| { let text = if GLOBALS.signer.is_ready() { RichText::new("+").size(22.5) } else { RichText::new("\u{1f513}").size(20.0) }; - let response = ui.add_sized([crate::AVATAR_SIZE_F32, crate::AVATAR_SIZE_F32], egui::Button::new(text.color(self.theme.navigation_text_color())).stroke(egui::Stroke::NONE).rounding(egui::Rounding::same(crate::AVATAR_SIZE_F32)).fill(self.theme.navigation_bg_fill())); + let response = ui.add_sized([crate::AVATAR_SIZE_F32, crate::AVATAR_SIZE_F32], egui::Button::new(text.color(self.theme.get_style().visuals.panel_fill)).stroke(egui::Stroke::NONE).rounding(egui::Rounding::same(crate::AVATAR_SIZE_F32)).fill(self.theme.accent_color())); if response.clicked() { self.show_post_area = true; if GLOBALS.signer.is_ready() { diff --git a/gossip-bin/src/ui/theme/classic.rs b/gossip-bin/src/ui/theme/classic.rs index 7d1bd8e6..d9fc8dc5 100644 --- a/gossip-bin/src/ui/theme/classic.rs +++ b/gossip-bin/src/ui/theme/classic.rs @@ -425,6 +425,14 @@ impl ThemeDef for ClassicTheme { } } + fn navigation_text_deactivated_color(dark_mode: bool) -> eframe::egui::Color32 { + if dark_mode { + Color32::from_white_alpha(10) + } else { + Color32::from_black_alpha(100) + } + } + fn navigation_text_color(_dark_mode: bool) -> eframe::egui::Color32 { //if dark_mode { Color32::from_gray(220) diff --git a/gossip-bin/src/ui/theme/default.rs b/gossip-bin/src/ui/theme/default.rs index cb033301..cb79be28 100644 --- a/gossip-bin/src/ui/theme/default.rs +++ b/gossip-bin/src/ui/theme/default.rs @@ -194,7 +194,7 @@ impl ThemeDef for DefaultTheme { noninteractive: WidgetVisuals { weak_bg_fill: Color32::from_gray(248), bg_fill: Color32::from_black_alpha(20), - bg_stroke: Stroke::new(2.0, Color32::from_white_alpha(5)), + bg_stroke: Stroke::new(2.0, Color32::from_white_alpha(1)), fg_stroke: Stroke::new(1.0, Color32::from_gray(80)), // normal text color rounding: Rounding::same(2.0), expansion: 0.0, @@ -423,41 +423,50 @@ impl ThemeDef for DefaultTheme { } fn navigation_bg_fill(dark_mode: bool) -> eframe::egui::Color32 { - let mut hsva: ecolor::HsvaGamma = Self::accent_color(dark_mode).into(); - hsva.s *= 0.7; - hsva.v = if dark_mode { 0.23 } else { 0.56 }; + let mut hsva: ecolor::HsvaGamma = Self::get_style(dark_mode).visuals.panel_fill.into(); + let delta = if dark_mode { + 1.3 + } else { + 0.90 + }; + hsva.v = hsva.v * delta; hsva.into() } + fn navigation_text_deactivated_color(dark_mode: bool) -> eframe::egui::Color32 { + if dark_mode { + Color32::from_white_alpha(10) + } else { + Color32::from_black_alpha(100) + } + } + fn navigation_text_color(dark_mode: bool) -> eframe::egui::Color32 { - let mut hsva: ecolor::HsvaGamma = Self::accent_color(dark_mode).into(); - hsva.s = 0.05; - hsva.v = if dark_mode { 0.56 } else { 0.86 }; - hsva.into() + if dark_mode { + Color32::from_white_alpha(40) + } else { + Color32::from_black_alpha(140) + } } fn navigation_text_active_color(dark_mode: bool) -> eframe::egui::Color32 { - let mut hsva: ecolor::HsvaGamma = Self::accent_color(dark_mode).into(); - hsva.s = 0.05; - hsva.v = if dark_mode { 0.86 } else { 0.97 }; - hsva.into() + if dark_mode { + Color32::from_white_alpha(140) + } else { + Color32::from_black_alpha(200) + } } fn navigation_text_hover_color(dark_mode: bool) -> eframe::egui::Color32 { - let mut hsva: ecolor::HsvaGamma = Self::accent_color(dark_mode).into(); - hsva.s = 0.05; - hsva.v = 1.00; - hsva.into() + Self::accent_color(dark_mode) } fn navigation_header_active_color(dark_mode: bool) -> eframe::egui::Color32 { - let mut hsva: ecolor::HsvaGamma = Self::accent_color(false).into(); if dark_mode { - hsva.v = (hsva.v + 0.1).min(1.0); // lighten + Color32::from_white_alpha(80) } else { - hsva.v = (hsva.v - 0.2).max(0.0); // darken + Color32::from_black_alpha(80) } - hsva.into() } fn input_text_color(dark_mode: bool) -> eframe::egui::Color32 { diff --git a/gossip-bin/src/ui/theme/mod.rs b/gossip-bin/src/ui/theme/mod.rs index a23b4f1d..3edac631 100644 --- a/gossip-bin/src/ui/theme/mod.rs +++ b/gossip-bin/src/ui/theme/mod.rs @@ -148,6 +148,12 @@ macro_rules! theme_dispatch { } } + pub fn navigation_text_deactivated_color(&self) -> Color32 { + match self.variant { + $( $variant => $class::navigation_text_deactivated_color(self.dark_mode), )+ + } + } + pub fn navigation_text_color(&self) -> Color32 { match self.variant { $( $variant => $class::navigation_text_color(self.dark_mode), )+ @@ -366,6 +372,7 @@ pub trait ThemeDef: Send + Sync { fn notice_marker_text_color(dark_mode: bool) -> eframe::egui::Color32; fn navigation_bg_fill(dark_mode: bool) -> eframe::egui::Color32; + fn navigation_text_deactivated_color(dark_mode: bool) -> eframe::egui::Color32; fn navigation_text_color(dark_mode: bool) -> eframe::egui::Color32; fn navigation_text_active_color(dark_mode: bool) -> eframe::egui::Color32; fn navigation_text_hover_color(dark_mode: bool) -> eframe::egui::Color32; diff --git a/gossip-bin/src/ui/theme/roundy.rs b/gossip-bin/src/ui/theme/roundy.rs index eba681af..1baa22be 100644 --- a/gossip-bin/src/ui/theme/roundy.rs +++ b/gossip-bin/src/ui/theme/roundy.rs @@ -431,6 +431,14 @@ impl ThemeDef for RoundyTheme { } } + fn navigation_text_deactivated_color(dark_mode: bool) -> eframe::egui::Color32 { + if dark_mode { + Color32::from_white_alpha(10) + } else { + Color32::from_black_alpha(100) + } + } + fn navigation_text_color(_dark_mode: bool) -> eframe::egui::Color32 { //if dark_mode { Color32::from_gray(220) From 7d451c01afec81a02b6cff151326efaa16d2cb96 Mon Sep 17 00:00:00 2001 From: Daniele Tonon Date: Sun, 8 Oct 2023 17:35:21 +0200 Subject: [PATCH 37/46] Review the color/size of note labels --- gossip-bin/src/ui/feed/note/mod.rs | 15 ++++++++------- gossip-bin/src/ui/theme/default.rs | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/gossip-bin/src/ui/feed/note/mod.rs b/gossip-bin/src/ui/feed/note/mod.rs index 9123beb5..8631e9b4 100644 --- a/gossip-bin/src/ui/feed/note/mod.rs +++ b/gossip-bin/src/ui/feed/note/mod.rs @@ -306,30 +306,31 @@ fn render_note_inner( ui.add_space(8.0); if note.event.pow() > 0 { - ui.label(format!("POW={}", note.event.pow())); + let color = app.theme.notice_marker_text_color(); + ui.label(RichText::new(format!("POW={}", note.event.pow())).color(color).text_style(TextStyle::Small)); } match ¬e.delegation { EventDelegation::InvalidDelegation(why) => { let color = app.theme.warning_marker_text_color(); - ui.add(Label::new(RichText::new("INVALID DELEGATION").color(color))) + ui.add(Label::new(RichText::new("INVALID DELEGATION").color(color).text_style(TextStyle::Small))) .on_hover_text(why); } EventDelegation::DelegatedBy(_) => { let color = app.theme.notice_marker_text_color(); - ui.label(RichText::new("DELEGATED").color(color)); + ui.label(RichText::new("DELEGATED").color(color).text_style(TextStyle::Small)); } _ => {} } if note.deletion.is_some() { let color = app.theme.warning_marker_text_color(); - ui.label(RichText::new("DELETED").color(color)); + ui.label(RichText::new("DELETED").color(color).text_style(TextStyle::Small)); } if note.event.kind == EventKind::Repost { let color = app.theme.notice_marker_text_color(); - ui.label(RichText::new("REPOSTED").color(color)); + ui.label(RichText::new("REPOSTED").color(color).text_style(TextStyle::Small)); } if let Page::Feed(FeedKind::DmChat(_)) = app.page { @@ -338,9 +339,9 @@ fn render_note_inner( if note.event.kind.is_direct_message_related() { let color = app.theme.notice_marker_text_color(); if note.secure { - ui.label(RichText::new("Private Chat (Gift Wrapped)").color(color)); + ui.label(RichText::new("PRIVATE CHAT (GIFT WRAPPED)").color(color).text_style(TextStyle::Small)); } else { - ui.label(RichText::new("Private Chat").color(color)); + ui.label(RichText::new("PRIVATE CHAT").color(color).text_style(TextStyle::Small)); } } } diff --git a/gossip-bin/src/ui/theme/default.rs b/gossip-bin/src/ui/theme/default.rs index cb033301..402cabca 100644 --- a/gossip-bin/src/ui/theme/default.rs +++ b/gossip-bin/src/ui/theme/default.rs @@ -415,9 +415,9 @@ impl ThemeDef for DefaultTheme { fn notice_marker_text_color(dark_mode: bool) -> eframe::egui::Color32 { let mut hsva: ecolor::HsvaGamma = Self::accent_color(dark_mode).into(); if dark_mode { - hsva.v = (hsva.v + 0.2).min(1.0); // lighten + hsva.v = (hsva.v - 0.2).min(1.0); // darken++ } else { - hsva.v = (hsva.v - 0.2).max(0.0); // darken + hsva.v = (hsva.v - 0.1).max(0.0); // darken } hsva.into() } From b309a197402528f544918af50d9dc0b63953af5d Mon Sep 17 00:00:00 2001 From: Daniele Tonon Date: Sun, 8 Oct 2023 18:17:23 +0200 Subject: [PATCH 38/46] Improve sidebar resize UX --- gossip-bin/src/ui/theme/default.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gossip-bin/src/ui/theme/default.rs b/gossip-bin/src/ui/theme/default.rs index cb79be28..eb085481 100644 --- a/gossip-bin/src/ui/theme/default.rs +++ b/gossip-bin/src/ui/theme/default.rs @@ -129,7 +129,7 @@ impl ThemeDef for DefaultTheme { weak_bg_fill: Color32::from_white_alpha(4), bg_fill: Color32::from_white_alpha(20), bg_stroke: Stroke::new(0.0, Self::accent_color(dark_mode)), // e.g. hover over window edge or button - fg_stroke: Stroke::new(1.5, Self::accent_color(dark_mode)), + fg_stroke: Stroke::new(1.5, Color32::from_white_alpha(1)), rounding: Rounding::same(3.0), expansion: 2.0, }, @@ -137,7 +137,7 @@ impl ThemeDef for DefaultTheme { weak_bg_fill: Color32::from_gray(55), bg_fill: Color32::from_gray(55), bg_stroke: Stroke::new(0.0, Self::accent_color(dark_mode)), - fg_stroke: Stroke::new(2.0, Color32::from_gray(220)), + fg_stroke: Stroke::new(2.0, Color32::from_white_alpha(10)), rounding: Rounding::same(2.0), expansion: 2.0, }, @@ -214,7 +214,7 @@ impl ThemeDef for DefaultTheme { weak_bg_fill: Color32::from_black_alpha(10), bg_fill: Color32::from_black_alpha(10), bg_stroke: Stroke::new(0.0, Self::accent_color(dark_mode)), // e.g. hover over window edge or button - fg_stroke: Stroke::new(1.5, Self::accent_color(dark_mode)), + fg_stroke: Stroke::new(1.5, Color32::from_black_alpha(20)), rounding: Rounding::same(3.0), expansion: 2.0, }, @@ -222,7 +222,7 @@ impl ThemeDef for DefaultTheme { weak_bg_fill: Color32::from_gray(165), bg_fill: Color32::from_black_alpha(50), bg_stroke: Stroke::new(0.0, Self::accent_color(dark_mode)), - fg_stroke: Stroke::new(2.0, Color32::from_gray(30)), + fg_stroke: Stroke::new(2.0, Color32::from_black_alpha(40)), rounding: Rounding::same(2.0), expansion: 2.0, }, From 79e81a2710dd85f4be78a132e5c805b43e2c2212 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Mon, 9 Oct 2023 06:54:03 +1300 Subject: [PATCH 39/46] Fix saving of theme settings --- gossip-bin/src/ui/mod.rs | 18 ++++++++++++++---- gossip-bin/src/ui/settings/ui.rs | 19 ++++++++----------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/gossip-bin/src/ui/mod.rs b/gossip-bin/src/ui/mod.rs index 70af7d23..7d00c065 100644 --- a/gossip-bin/src/ui/mod.rs +++ b/gossip-bin/src/ui/mod.rs @@ -973,15 +973,25 @@ impl eframe::App for GossipUi { self.current_scroll_offset = requested_scroll; } - if self.theme.follow_os_dark_mode { + let mut reapply = false; + let mut theme = Theme::from_settings(&self.settings); + if theme.follow_os_dark_mode { // detect if the OS has changed dark/light mode let os_dark_mode = ctx.style().visuals.dark_mode; - if os_dark_mode != self.theme.dark_mode { + if os_dark_mode != theme.dark_mode { // switch to the OS setting - self.theme.dark_mode = os_dark_mode; - theme::apply_theme(&self.theme, ctx); + self.settings.dark_mode = os_dark_mode; + theme.dark_mode = os_dark_mode; + reapply = true; } } + if self.theme != theme { + self.theme = theme; + reapply = true; + } + if reapply { + theme::apply_theme(&self.theme, ctx); + } // dialogues first if relays::is_entry_dialog_active(self) { diff --git a/gossip-bin/src/ui/settings/ui.rs b/gossip-bin/src/ui/settings/ui.rs index 5fb012fa..ecfdc901 100644 --- a/gossip-bin/src/ui/settings/ui.rs +++ b/gossip-bin/src/ui/settings/ui.rs @@ -19,29 +19,26 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra ui.add_space(20.0); ui.horizontal(|ui| { ui.label("Theme:"); - if !app.theme.follow_os_dark_mode { - if app.theme.dark_mode { + if !app.settings.follow_os_dark_mode { + if app.settings.dark_mode { if ui.add(Button::new("🌙 Dark")).on_hover_text("Switch to light mode").clicked() { - app.theme.dark_mode = false; - crate::ui::theme::apply_theme(&app.theme, ctx); + app.settings.dark_mode = false; } } else { if ui.add(Button::new("☀ Light")).on_hover_text("Switch to dark mode").clicked() { - app.theme.dark_mode = true; - crate::ui::theme::apply_theme(&app.theme, ctx); + app.settings.dark_mode = true; } } } let theme_combo = egui::ComboBox::from_id_source("Theme"); - theme_combo.selected_text(app.theme.name()).show_ui(ui, |ui| { + theme_combo.selected_text(&app.settings.theme_variant).show_ui(ui, |ui| { for theme_variant in ThemeVariant::all() { - if ui.add(egui::widgets::SelectableLabel::new(*theme_variant == app.theme.variant, theme_variant.name())).clicked() { - app.theme.variant = *theme_variant; - crate::ui::theme::apply_theme(&app.theme, ctx); + if ui.add(egui::widgets::SelectableLabel::new(theme_variant.name() == app.settings.theme_variant, theme_variant.name())).clicked() { + app.settings.theme_variant = theme_variant.name().to_string(); }; } }); - ui.checkbox(&mut app.theme.follow_os_dark_mode, "Follow OS dark-mode").on_hover_text("Follow the operating system setting for dark-mode (requires app-restart to take effect)"); + ui.checkbox(&mut app.settings.follow_os_dark_mode, "Follow OS dark-mode").on_hover_text("Follow the operating system setting for dark-mode (requires app-restart to take effect)"); }); ui.add_space(20.0); From f08d6a04b00ee3c94794cd8dfc48d46c8c6feca4 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Mon, 9 Oct 2023 06:55:20 +1300 Subject: [PATCH 40/46] cargo fmt --- gossip-bin/src/ui/dm_chat_list.rs | 9 ++++++--- gossip-bin/src/ui/mod.rs | 7 ++++++- gossip-bin/src/ui/people/person.rs | 12 ++++++------ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/gossip-bin/src/ui/dm_chat_list.rs b/gossip-bin/src/ui/dm_chat_list.rs index 2c8135ab..19feb824 100644 --- a/gossip-bin/src/ui/dm_chat_list.rs +++ b/gossip-bin/src/ui/dm_chat_list.rs @@ -2,17 +2,20 @@ use super::{GossipUi, Page}; use eframe::egui; use egui::{Context, Label, RichText, Sense, Ui}; use gossip_lib::DmChannelData; -use gossip_lib::{Error, ErrorKind}; use gossip_lib::FeedKind; use gossip_lib::GLOBALS; +use gossip_lib::{Error, ErrorKind}; pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { let mut channels: Vec = match GLOBALS.storage.dm_channels() { Ok(channels) => channels, - Err(Error { kind: ErrorKind::NoPrivateKey, .. }) => { + Err(Error { + kind: ErrorKind::NoPrivateKey, + .. + }) => { ui.label("Private Key Not Available"); return; - }, + } Err(_) => { ui.label("ERROR"); return; diff --git a/gossip-bin/src/ui/mod.rs b/gossip-bin/src/ui/mod.rs index 7d00c065..f978983c 100644 --- a/gossip-bin/src/ui/mod.rs +++ b/gossip-bin/src/ui/mod.rs @@ -1110,7 +1110,12 @@ impl GossipUi { ui.set_enabled(!relays::is_entry_dialog_active(self)); } - pub fn render_person_name_line(app: &mut GossipUi, ui: &mut Ui, person: &Person, profile_page: bool) { + pub fn render_person_name_line( + app: &mut GossipUi, + ui: &mut Ui, + person: &Person, + profile_page: bool, + ) { // Let the 'People' manager know that we are interested in displaying this person. // It will take all actions necessary to make the data eventually available. GLOBALS.people.person_of_interest(person.pubkey); diff --git a/gossip-bin/src/ui/people/person.rs b/gossip-bin/src/ui/people/person.rs index 2bf50f65..c3bca63c 100644 --- a/gossip-bin/src/ui/people/person.rs +++ b/gossip-bin/src/ui/people/person.rs @@ -100,7 +100,8 @@ fn content(app: &mut GossipUi, ctx: &Context, ui: &mut Ui, pubkey: PublicKey, pe if ui.button("remove").clicked() { let mut person = person.clone(); person.petname = None; - if let Err(e) = GLOBALS.storage.write_person(&person, None) { + if let Err(e) = GLOBALS.storage.write_person(&person, None) + { GLOBALS.status_queue.write().write(format!("{}", e)); } app.notes.cache_invalidate_person(&person.pubkey); @@ -116,21 +117,21 @@ fn content(app: &mut GossipUi, ctx: &Context, ui: &mut Ui, pubkey: PublicKey, pe } } }); - + ui.add_space(10.0); { let visuals = ui.visuals_mut(); visuals.widgets.inactive.weak_bg_fill = app.theme.accent_color(); visuals.widgets.inactive.fg_stroke.width = 1.0; visuals.widgets.inactive.fg_stroke.color = - app.theme.get_style().visuals.extreme_bg_color; + app.theme.get_style().visuals.extreme_bg_color; visuals.widgets.hovered.weak_bg_fill = app.theme.navigation_text_color(); visuals.widgets.hovered.fg_stroke.color = app.theme.accent_color(); visuals.widgets.inactive.fg_stroke.color = - app.theme.get_style().visuals.extreme_bg_color; + app.theme.get_style().visuals.extreme_bg_color; GossipUi::render_person_name_line(app, ui, &person, true); } - + if let Some(about) = person.about() { ui.add_space(10.0); ui.separator(); @@ -145,7 +146,6 @@ fn content(app: &mut GossipUi, ctx: &Context, ui: &mut Ui, pubkey: PublicKey, pe }); }, ); - }); ui.add_space(10.0); From af11976989693d2a89fca26e99963ec875b5e699 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Mon, 9 Oct 2023 06:56:36 +1300 Subject: [PATCH 41/46] cargo clippy --- gossip-bin/src/ui/people/person.rs | 2 +- gossip-bin/src/ui/theme/mod.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gossip-bin/src/ui/people/person.rs b/gossip-bin/src/ui/people/person.rs index c3bca63c..c345245a 100644 --- a/gossip-bin/src/ui/people/person.rs +++ b/gossip-bin/src/ui/people/person.rs @@ -2,7 +2,7 @@ use super::{GossipUi, Page}; use crate::ui::widgets::CopyButton; use crate::AVATAR_SIZE_F32; use eframe::egui; -use egui::{Context, Frame, Image, RichText, TextEdit, Ui, Vec2}; +use egui::{Context, Image, RichText, TextEdit, Ui, Vec2}; use gossip_lib::comms::ToOverlordMessage; use gossip_lib::Person; use gossip_lib::GLOBALS; diff --git a/gossip-bin/src/ui/theme/mod.rs b/gossip-bin/src/ui/theme/mod.rs index a23b4f1d..08853f68 100644 --- a/gossip-bin/src/ui/theme/mod.rs +++ b/gossip-bin/src/ui/theme/mod.rs @@ -79,6 +79,7 @@ macro_rules! theme_dispatch { } impl Theme { + #[allow(dead_code)] pub fn name(&self) -> &'static str { self.variant.name() } From cd9c6d794f2efe9fcf74de36eed599df352ab8e7 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Mon, 9 Oct 2023 07:41:46 +1300 Subject: [PATCH 42/46] Drop unsupported themes --- gossip-bin/src/ui/theme/classic.rs | 622 ---------------------------- gossip-bin/src/ui/theme/default.rs | 18 +- gossip-bin/src/ui/theme/mod.rs | 22 +- gossip-bin/src/ui/theme/roundy.rs | 645 ----------------------------- 4 files changed, 10 insertions(+), 1297 deletions(-) delete mode 100644 gossip-bin/src/ui/theme/classic.rs delete mode 100644 gossip-bin/src/ui/theme/roundy.rs diff --git a/gossip-bin/src/ui/theme/classic.rs b/gossip-bin/src/ui/theme/classic.rs deleted file mode 100644 index 2353daa5..00000000 --- a/gossip-bin/src/ui/theme/classic.rs +++ /dev/null @@ -1,622 +0,0 @@ -use super::{FeedProperties, NoteRenderData, ThemeDef}; -use crate::ui::HighlightType; -use eframe::egui::style::{Selection, WidgetVisuals, Widgets}; -use eframe::egui::{FontDefinitions, Margin, RichText, Style, TextFormat, TextStyle, Visuals}; -use eframe::epaint::{ecolor, Color32, FontFamily, FontId, Rounding, Shadow, Stroke}; -use std::collections::BTreeMap; - -#[derive(Default)] -pub struct ClassicTheme {} - -impl ThemeDef for ClassicTheme { - fn name() -> &'static str { - "Classic" - } - - fn accent_color(dark_mode: bool) -> Color32 { - // not used within - if dark_mode { - Color32::from_rgb(116, 167, 204) - } else { - Color32::from_rgb(85, 122, 149) - } - } - - fn accent_complementary_color(dark_mode: bool) -> Color32 { - // not used within - let mut hsva: ecolor::HsvaGamma = Self::accent_color(dark_mode).into(); - hsva.h = (hsva.h + 0.5) % 1.0; - hsva.into() - } - - fn highlighted_note_bgcolor(dark_mode: bool) -> Color32 { - // not used within - if dark_mode { - Color32::from_rgb(41, 34, 46) - } else { - Color32::from_rgb(255, 255, 237) - } - } - - fn get_style(dark_mode: bool) -> Style { - let mut style = Style::default(); - - // /// `item_spacing` is inserted _after_ adding a widget, so to increase the spacing between - // /// widgets `A` and `B` you need to change `item_spacing` before adding `A`. - // pub item_spacing: Vec2, - - // /// Horizontal and vertical margins within a window frame. - // pub window_margin: Margin, - - // /// Button size is text size plus this on each side - // pub button_padding: Vec2, - - // /// Horizontal and vertical margins within a menu frame. - // pub menu_margin: Margin, - - // /// Indent collapsing regions etc by this much. - // pub indent: f32, - - // /// Minimum size of a [`DragValue`], color picker button, and other small widgets. - // /// `interact_size.y` is the default height of button, slider, etc. - // /// Anything clickable should be (at least) this size. - // pub interact_size: Vec2, // TODO(emilk): rename min_interact_size ? - - // /// Default width of a [`Slider`]. - // pub slider_width: f32, - - // /// Default (minimum) width of a [`ComboBox`](gossip_lib::ComboBox). - // pub combo_width: f32, - - // /// Default width of a [`TextEdit`]. - // pub text_edit_width: f32, - - // /// Checkboxes, radio button and collapsing headers have an icon at the start. - // /// This is the width/height of the outer part of this icon (e.g. the BOX of the checkbox). - // pub icon_width: f32, - - // /// Checkboxes, radio button and collapsing headers have an icon at the start. - // /// This is the width/height of the inner part of this icon (e.g. the check of the checkbox). - // pub icon_width_inner: f32, - - // /// Checkboxes, radio button and collapsing headers have an icon at the start. - // /// This is the spacing between the icon and the text - // pub icon_spacing: f32, - // /// Width of a tooltip (`on_hover_ui`, `on_hover_text` etc). - // pub tooltip_width: f32, - - // /// End indented regions with a horizontal line - // pub indent_ends_with_horizontal_line: bool, - - // /// Height of a combo-box before showing scroll bars. - // pub combo_height: f32, - - // pub scroll_bar_width: f32, - - // /// Make sure the scroll handle is at least this big - // pub scroll_handle_min_length: f32, - - // /// Margin between contents and scroll bar. - // pub scroll_bar_inner_margin: f32, - - // /// Margin between scroll bar and the outer container (e.g. right of a vertical scroll bar). - // pub scroll_bar_outer_margin: f32, - - if dark_mode { - style.visuals = Visuals { - dark_mode: true, - widgets: Widgets { - noninteractive: WidgetVisuals { - weak_bg_fill: Color32::from_gray(27), - bg_fill: Color32::from_white_alpha(8), - bg_stroke: Stroke::new(1.0, Color32::from_gray(72)), // separators, borders - fg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // normal text color - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - inactive: WidgetVisuals { - weak_bg_fill: Color32::from_gray(60), // button background - bg_fill: Color32::from_white_alpha(8), - bg_stroke: Stroke::new(1.0, Color32::from_gray(72)), // separators, borders - // The following is used for All buttons, any clickable text, - // AND text inputs, whether they are inactive OR active. It's really - // overloaded. - fg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // button text - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - hovered: WidgetVisuals { - weak_bg_fill: Color32::from_gray(70), - bg_fill: Color32::from_gray(70), - bg_stroke: Stroke::new(1.0, Color32::from_gray(150)), // e.g. hover over window edge or button - fg_stroke: Stroke::new(1.5, Color32::from_gray(240)), - rounding: Rounding::same(3.0), - expansion: 1.0, - }, - active: WidgetVisuals { - weak_bg_fill: Color32::from_gray(55), - bg_fill: Color32::from_gray(55), - bg_stroke: Stroke::new(1.0, Color32::WHITE), - fg_stroke: Stroke::new(2.0, Color32::WHITE), - rounding: Rounding::same(2.0), - expansion: 1.0, - }, - open: WidgetVisuals { - weak_bg_fill: Color32::from_gray(27), - bg_fill: Color32::from_gray(27), - bg_stroke: Stroke::new(1.0, Color32::from_gray(60)), - fg_stroke: Stroke::new(1.0, Color32::from_gray(210)), - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - }, - - // Background colors - window_fill: Color32::from_gray(0x24), // pulldown menus and tooltips - panel_fill: Color32::from_gray(0x24), // panel backgrounds, even-table-rows - faint_bg_color: Color32::from_gray(0x14), // odd-table-rows - extreme_bg_color: Color32::from_gray(0), // text input background; scrollbar background - code_bg_color: Color32::from_gray(64), // ??? - - // Foreground colors - window_stroke: Stroke::new(1.0, Color32::from_gray(230)), - override_text_color: None, - warn_fg_color: Color32::from_rgb(255, 143, 0), // orange - error_fg_color: Color32::from_rgb(255, 0, 0), // red - hyperlink_color: Color32::from_rgb(0x73, 0x95, 0xae), // light blue? - - selection: Selection { - bg_fill: Color32::from_rgb(0x57, 0x4a, 0x40), - stroke: Stroke::new(1.0, Color32::from_gray(230)), - }, - - window_shadow: Shadow::big_dark(), - popup_shadow: Shadow::small_dark(), - - indent_has_left_vline: false, - menu_rounding: Rounding::same(2.0), - slider_trailing_fill: true, - striped: true, - window_rounding: Rounding::same(6.0), - resize_corner_size: 12.0, - text_cursor: Stroke::new(2.0, Color32::from_rgb(192, 222, 255)), - text_cursor_preview: false, - clip_rect_margin: 3.0, // should be at least half the size of the widest frame stroke + max WidgetVisuals::expansion - button_frame: true, - collapsing_header_frame: false, - interact_cursor: None, - image_loading_spinners: true, - }; - } else { - style.visuals = Visuals { - dark_mode: false, - widgets: Widgets { - noninteractive: WidgetVisuals { - weak_bg_fill: Color32::from_gray(248), - bg_fill: Color32::from_black_alpha(20), - bg_stroke: Stroke::new(1.0, Color32::from_gray(192)), - fg_stroke: Stroke::new(1.0, Color32::from_gray(80)), // normal text color - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - inactive: WidgetVisuals { - weak_bg_fill: Color32::from_gray(230), // button background - bg_fill: Color32::from_black_alpha(20), - bg_stroke: Stroke::new(1.0, Color32::from_gray(192)), - // The following is used for All buttons, any clickable text, - // AND text inputs, whether they are inactive OR active. It's really - // overloaded. - fg_stroke: Stroke::new(1.0, Color32::from_gray(60)), // button text - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - hovered: WidgetVisuals { - weak_bg_fill: Color32::from_gray(220), - bg_fill: Color32::from_gray(220), - bg_stroke: Stroke::new(1.0, Color32::from_gray(105)), // e.g. hover over window edge or button - fg_stroke: Stroke::new(1.5, Color32::BLACK), - rounding: Rounding::same(3.0), - expansion: 1.0, - }, - active: WidgetVisuals { - weak_bg_fill: Color32::from_gray(165), - bg_fill: Color32::from_gray(165), - bg_stroke: Stroke::new(1.0, Color32::BLACK), - fg_stroke: Stroke::new(2.0, Color32::BLACK), - rounding: Rounding::same(2.0), - expansion: 1.0, - }, - open: WidgetVisuals { - weak_bg_fill: Color32::from_gray(220), - bg_fill: Color32::from_gray(220), - bg_stroke: Stroke::new(1.0, Color32::from_gray(160)), - fg_stroke: Stroke::new(1.0, Color32::BLACK), - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - }, - - // Background colors - window_fill: Color32::from_gray(0xed), // pulldown menus and tooltips - panel_fill: Color32::from_gray(0xed), // panel backgrounds, even-table-rows - faint_bg_color: Color32::from_gray(0xf9), // odd-table-rows - extreme_bg_color: Color32::from_gray(0xff), // text input background; scrollbar background - code_bg_color: Color32::from_gray(230), // ??? - - // Foreground colors - window_stroke: Stroke::new(1.0, Color32::from_rgb(0x5d, 0x5c, 0x61)), // DONE - override_text_color: None, - warn_fg_color: Color32::from_rgb(255, 100, 0), // slightly orange red. it's difficult to find a warning color that pops on bright background. - error_fg_color: Color32::from_rgb(255, 0, 0), // red - hyperlink_color: Color32::from_rgb(0x55, 0x7a, 0x95), // DONE - - selection: Selection { - bg_fill: Color32::from_rgb(0xb1, 0xa2, 0x96), // DONE - stroke: Stroke::new(1.0, Color32::from_rgb(0x5d, 0x5c, 0x61)), // DONE - }, - - window_shadow: Shadow::big_light(), - popup_shadow: Shadow::small_light(), - - indent_has_left_vline: false, - menu_rounding: Rounding::same(2.0), - slider_trailing_fill: true, - striped: true, - window_rounding: Rounding::same(6.0), - resize_corner_size: 12.0, - text_cursor: Stroke::new(2.0, Color32::from_rgb(0, 83, 125)), - text_cursor_preview: false, - clip_rect_margin: 3.0, // should be at least half the size of the widest frame stroke + max WidgetVisuals::expansion - button_frame: true, - collapsing_header_frame: false, - interact_cursor: None, - image_loading_spinners: true, - }; - } - style - } - - /// the style to use when displaying on-top of an accent-colored background - fn get_on_accent_style(dark_mode: bool) -> Style { - let mut style = Self::get_style(!dark_mode); - if dark_mode { - todo!() - } else { - style.visuals.widgets.noninteractive.fg_stroke.color = Color32::WHITE; - style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.inactive.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); - style.visuals.widgets.active.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.active.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); - style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(8); - style.visuals.widgets.hovered.fg_stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); - style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); - style.visuals.selection.stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); - } - style - } - - fn font_definitions() -> FontDefinitions { - super::font_definitions() // use default gossip font definitions - } - - fn text_styles() -> BTreeMap { - let mut text_styles: BTreeMap = BTreeMap::new(); - - text_styles.insert( - TextStyle::Small, - FontId { - size: 10.75, - family: FontFamily::Proportional, - }, - ); - - text_styles.insert( - TextStyle::Body, - FontId { - size: 12.5, - family: FontFamily::Proportional, - }, - ); - - text_styles.insert( - TextStyle::Monospace, - FontId { - size: 12.5, - family: FontFamily::Monospace, - }, - ); - - text_styles.insert( - TextStyle::Button, - FontId { - size: 12.5, - family: FontFamily::Proportional, - }, - ); - - text_styles.insert( - TextStyle::Heading, - FontId { - size: 16.25, - family: FontFamily::Proportional, - }, - ); - - // for subject lines in notes - text_styles.insert( - TextStyle::Name("subject".into()), - FontId { - size: 15.0, - family: FontFamily::Proportional, - }, - ); - - text_styles - } - - fn highlight_text_format(highlight_type: HighlightType, dark_mode: bool) -> TextFormat { - let main = if dark_mode { - Color32::WHITE - } else { - Color32::BLACK - }; - let grey = if dark_mode { - Color32::from_gray(36) - } else { - Color32::LIGHT_GRAY - }; - let green = if dark_mode { - Color32::LIGHT_GREEN - } else { - Color32::DARK_GREEN - }; - let red = if dark_mode { - Color32::LIGHT_RED - } else { - Color32::DARK_RED - }; - let purple = if dark_mode { - Color32::from_rgb(0xA0, 0x40, 0xA0) - } else { - Color32::from_rgb(0x80, 0, 0x80) - }; - - match highlight_type { - HighlightType::Nothing => TextFormat { - font_id: FontId::new(12.5, FontFamily::Proportional), - color: main, - ..Default::default() - }, - HighlightType::PublicKey => TextFormat { - font_id: FontId::new(12.5, FontFamily::Monospace), - background: grey, - color: green, - ..Default::default() - }, - HighlightType::Event => TextFormat { - font_id: FontId::new(12.5, FontFamily::Monospace), - background: grey, - color: red, - ..Default::default() - }, - HighlightType::Relay => TextFormat { - font_id: FontId::new(12.5, FontFamily::Monospace), - background: grey, - color: purple, - ..Default::default() - }, - HighlightType::Hyperlink => TextFormat { - font_id: FontId::new(12.5, FontFamily::Proportional), - color: { - // This should match get_style() above for hyperlink color. - if dark_mode { - Color32::from_rgb(0x73, 0x95, 0xae) - } else { - Color32::from_rgb(0x55, 0x7a, 0x95) - } - }, - ..Default::default() - }, - } - } - - fn warning_marker_text_color(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::LIGHT_RED - } else { - Color32::DARK_RED - } - } - - fn notice_marker_text_color(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::LIGHT_BLUE - } else { - Color32::DARK_BLUE - } - } - - fn navigation_bg_fill(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::from_rgb(0x30, 0x6f, 0xc1) - } else { - Color32::from_rgb(0x55, 0x7a, 0x95) - } - } - - fn navigation_text_deactivated_color(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::from_white_alpha(10) - } else { - Color32::from_black_alpha(100) - } - } - - fn navigation_text_color(_dark_mode: bool) -> eframe::egui::Color32 { - //if dark_mode { - Color32::from_gray(220) - //} else { - // Color32::from_gray(220) - //} - } - - fn navigation_text_active_color(_dark_mode: bool) -> eframe::egui::Color32 { - //if dark_mode { - Color32::from_gray(0xf9) - //} else { - // Color32::from_gray(0xf9) - //} - } - - fn navigation_text_hover_color(_dark_mode: bool) -> eframe::egui::Color32 { - Color32::WHITE - } - - fn navigation_header_active_color(_dark_mode: bool) -> eframe::egui::Color32 { - Color32::from_gray(0xaa) - } - - fn input_text_color(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::from_gray(190) - } else { - Color32::from_gray(60) - } - } - - // feed styling - fn feed_scroll_rounding(_feed: &FeedProperties) -> Rounding { - Rounding::ZERO - } - fn feed_scroll_fill(dark_mode: bool, _feed: &FeedProperties) -> Color32 { - if dark_mode { - Color32::BLACK - } else { - Color32::WHITE - } - } - fn feed_scroll_stroke(_dark_mode: bool, _feed: &FeedProperties) -> Stroke { - Stroke::NONE - } - fn feed_post_separator_stroke(dark_mode: bool, _post: &NoteRenderData) -> Stroke { - if dark_mode { - Stroke::new(1.0, Color32::from_gray(72)) - } else { - Stroke::new(1.0, Color32::from_gray(192)) - } - } - fn feed_post_outer_indent(_ui: &mut eframe::egui::Ui, _post: &NoteRenderData) {} - fn feed_post_inner_indent(ui: &mut eframe::egui::Ui, post: &NoteRenderData) { - if post.is_thread { - let space = 100.0 * (10.0 - (1000.0 / (post.thread_position as f32 + 100.0))); - ui.add_space(space); - if post.thread_position > 0 { - ui.label( - RichText::new(format!("{}>", post.thread_position)) - .italics() - .weak(), - ); - } - } - } - fn feed_frame_inner_margin(_post: &NoteRenderData) -> Margin { - Margin { - left: 10.0, - top: 4.0, - right: 10.0, - bottom: 4.0, - } - } - fn feed_frame_outer_margin(_post: &NoteRenderData) -> Margin { - Margin { - left: 0.0, - top: 5.0, - right: 0.0, - bottom: 0.0, - } - } - fn feed_frame_rounding(_post: &NoteRenderData) -> Rounding { - Rounding::default() - } - fn feed_frame_shadow(_dark_mode: bool, _post: &NoteRenderData) -> Shadow { - Shadow::default() - } - fn feed_frame_fill(dark_mode: bool, post: &NoteRenderData) -> Color32 { - if post.is_new { - if dark_mode { - Color32::from_rgb(60, 0, 0) - } else { - Color32::LIGHT_YELLOW - } - } else { - if dark_mode { - Color32::BLACK - } else { - Color32::WHITE - } - } - } - fn feed_frame_stroke(_dark_mode: bool, _post: &NoteRenderData) -> Stroke { - Stroke::NONE - } - - fn repost_separator_before_stroke(dark_mode: bool, _post: &NoteRenderData) -> Stroke { - if dark_mode { - Stroke::new(1.0, Color32::from_gray(72)) - } else { - Stroke::new(1.0, Color32::from_gray(192)) - } - } - - fn repost_space_above_separator_before(_post: &NoteRenderData) -> f32 { - 4.0 - } - fn repost_space_below_separator_before(_post: &NoteRenderData) -> f32 { - 8.0 - } - - fn repost_separator_after_stroke(dark_mode: bool, post: &NoteRenderData) -> Stroke { - Self::repost_separator_before_stroke(dark_mode, post) - } - fn repost_space_above_separator_after(_post: &NoteRenderData) -> f32 { - 4.0 - } - fn repost_space_below_separator_after(_post: &NoteRenderData) -> f32 { - 0.0 - } - - fn repost_inner_margin(_post: &NoteRenderData) -> Margin { - // Margin { - // left: 10.0, - // top: 4.0, - // right: 10.0, - // bottom: 4.0, - // } - Margin::same(0.0) - } - fn repost_outer_margin(_post: &NoteRenderData) -> Margin { - // Margin { - // left: -10.0, - // top: -4.0, - // right: -10.0, - // bottom: -4.0, - // } - Margin::same(0.0) - } - fn repost_rounding(post: &NoteRenderData) -> Rounding { - Self::feed_frame_rounding(post) - } - fn repost_shadow(_dark_mode: bool, _post: &NoteRenderData) -> Shadow { - Shadow::NONE - } - fn repost_fill(_dark_mode: bool, _post: &NoteRenderData) -> Color32 { - Color32::TRANSPARENT - } - fn repost_stroke(_dark_mode: bool, _post: &NoteRenderData) -> Stroke { - Stroke::NONE - } - - fn round_image() -> bool { - false - } -} diff --git a/gossip-bin/src/ui/theme/default.rs b/gossip-bin/src/ui/theme/default.rs index 0396d940..a29b50ad 100644 --- a/gossip-bin/src/ui/theme/default.rs +++ b/gossip-bin/src/ui/theme/default.rs @@ -282,21 +282,25 @@ impl ThemeDef for DefaultTheme { if dark_mode { style.visuals.widgets.noninteractive.fg_stroke.color = style.visuals.window_fill; style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.inactive.fg_stroke = Stroke::new(0.0, style.visuals.panel_fill.gamma_multiply(0.6)); + style.visuals.widgets.inactive.fg_stroke = + Stroke::new(0.0, style.visuals.panel_fill.gamma_multiply(0.6)); style.visuals.widgets.active.bg_fill = Color32::from_black_alpha(20); style.visuals.widgets.active.fg_stroke.color = style.visuals.window_fill; style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(2); - style.visuals.widgets.hovered.fg_stroke.color = style.visuals.panel_fill.gamma_multiply(0.6); + style.visuals.widgets.hovered.fg_stroke.color = + style.visuals.panel_fill.gamma_multiply(0.6); style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); style.visuals.selection.stroke = Stroke::new(0.0, style.visuals.window_fill); } else { style.visuals.widgets.noninteractive.fg_stroke.color = style.visuals.panel_fill; style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.inactive.fg_stroke = Stroke::new(0.0, style.visuals.panel_fill.gamma_multiply(0.6)); + style.visuals.widgets.inactive.fg_stroke = + Stroke::new(0.0, style.visuals.panel_fill.gamma_multiply(0.6)); style.visuals.widgets.active.bg_fill = style.visuals.panel_fill.gamma_multiply(0.6); style.visuals.widgets.active.fg_stroke.color = style.visuals.window_fill; style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(2); - style.visuals.widgets.hovered.fg_stroke.color = style.visuals.panel_fill.gamma_multiply(0.6); + style.visuals.widgets.hovered.fg_stroke.color = + style.visuals.panel_fill.gamma_multiply(0.6); style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); style.visuals.selection.stroke = Stroke::new(0.0, style.visuals.panel_fill); } @@ -451,11 +455,7 @@ impl ThemeDef for DefaultTheme { fn navigation_bg_fill(dark_mode: bool) -> eframe::egui::Color32 { let mut hsva: ecolor::HsvaGamma = Self::get_style(dark_mode).visuals.panel_fill.into(); - let delta = if dark_mode { - 1.3 - } else { - 0.90 - }; + let delta = if dark_mode { 1.3 } else { 0.90 }; hsva.v = hsva.v * delta; hsva.into() } diff --git a/gossip-bin/src/ui/theme/mod.rs b/gossip-bin/src/ui/theme/mod.rs index bb1ef5dc..7d995b43 100644 --- a/gossip-bin/src/ui/theme/mod.rs +++ b/gossip-bin/src/ui/theme/mod.rs @@ -9,15 +9,9 @@ use gossip_lib::Settings; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; -mod classic; -pub use classic::ClassicTheme; - mod default; pub use default::DefaultTheme; -mod roundy; -pub use roundy::RoundyTheme; - pub fn apply_theme(theme: &Theme, ctx: &Context) { ctx.set_style(theme.get_style()); ctx.set_fonts(theme.font_definitions()); @@ -29,9 +23,7 @@ pub fn apply_theme(theme: &Theme, ctx: &Context) { // note: if we store anything inside the variants, we can't use macro_rules. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub enum ThemeVariant { - Classic, Default, - Roundy, } #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] @@ -45,9 +37,7 @@ impl Theme { pub fn from_settings(settings: &Settings) -> Theme { Theme { variant: match &*settings.theme_variant { - "Classic" => ThemeVariant::Classic, "Default" => ThemeVariant::Default, - "Roundy" => ThemeVariant::Roundy, _ => ThemeVariant::Default, }, dark_mode: settings.dark_mode, @@ -344,17 +334,7 @@ macro_rules! theme_dispatch { } } -theme_dispatch!( - ThemeVariant::Classic, - ClassicTheme, - "Classic", - ThemeVariant::Default, - DefaultTheme, - "Default", - ThemeVariant::Roundy, - RoundyTheme, - "Roundy" -); +theme_dispatch!(ThemeVariant::Default, DefaultTheme, "Default"); pub trait ThemeDef: Send + Sync { // User facing name diff --git a/gossip-bin/src/ui/theme/roundy.rs b/gossip-bin/src/ui/theme/roundy.rs deleted file mode 100644 index 213cdab0..00000000 --- a/gossip-bin/src/ui/theme/roundy.rs +++ /dev/null @@ -1,645 +0,0 @@ -use super::{FeedProperties, NoteRenderData, ThemeDef}; -use crate::ui::HighlightType; -use eframe::egui::style::{Selection, WidgetVisuals, Widgets}; -use eframe::egui::{FontDefinitions, Margin, Style, TextFormat, TextStyle, Visuals}; -use eframe::epaint::{ecolor, Color32, FontFamily, FontId, Rounding, Shadow, Stroke}; -use std::collections::BTreeMap; - -#[derive(Default)] -pub struct RoundyTheme {} - -impl ThemeDef for RoundyTheme { - fn name() -> &'static str { - "Roundy" - } - - fn accent_color(dark_mode: bool) -> Color32 { - // not used within - if dark_mode { - Color32::from_rgb(116, 167, 204) - } else { - Color32::from_rgb(85, 122, 149) - } - } - - fn accent_complementary_color(dark_mode: bool) -> Color32 { - // not used within - let mut hsva: ecolor::HsvaGamma = Self::accent_color(dark_mode).into(); - hsva.h = (hsva.h + 0.5) % 1.0; - hsva.into() - } - - fn highlighted_note_bgcolor(dark_mode: bool) -> Color32 { - // not used within - if dark_mode { - Color32::from_rgb(41, 34, 46) - } else { - Color32::from_rgb(255, 255, 237) - } - } - - fn get_style(dark_mode: bool) -> Style { - let mut style = Style::default(); - - // /// `item_spacing` is inserted _after_ adding a widget, so to increase the spacing between - // /// widgets `A` and `B` you need to change `item_spacing` before adding `A`. - // pub item_spacing: Vec2, - - // /// Horizontal and vertical margins within a window frame. - // pub window_margin: Margin, - style.spacing.window_margin = Margin::symmetric(20.0, 20.0); - - // /// Button size is text size plus this on each side - // pub button_padding: Vec2, - - // /// Horizontal and vertical margins within a menu frame. - // pub menu_margin: Margin, - style.spacing.menu_margin = Margin::symmetric(10.0, 5.0); - - // /// Indent collapsing regions etc by this much. - // pub indent: f32, - - // /// Minimum size of a [`DragValue`], color picker button, and other small widgets. - // /// `interact_size.y` is the default height of button, slider, etc. - // /// Anything clickable should be (at least) this size. - // pub interact_size: Vec2, // TODO(emilk): rename min_interact_size ? - - // /// Default width of a [`Slider`]. - // pub slider_width: f32, - - // /// Default (minimum) width of a [`ComboBox`](gossip_lib::ComboBox). - // pub combo_width: f32, - - // /// Default width of a [`TextEdit`]. - // pub text_edit_width: f32, - - // /// Checkboxes, radio button and collapsing headers have an icon at the start. - // /// This is the width/height of the outer part of this icon (e.g. the BOX of the checkbox). - // pub icon_width: f32, - - // /// Checkboxes, radio button and collapsing headers have an icon at the start. - // /// This is the width/height of the inner part of this icon (e.g. the check of the checkbox). - // pub icon_width_inner: f32, - - // /// Checkboxes, radio button and collapsing headers have an icon at the start. - // /// This is the spacing between the icon and the text - // pub icon_spacing: f32, - - // /// Width of a tooltip (`on_hover_ui`, `on_hover_text` etc). - // pub tooltip_width: f32, - - // /// End indented regions with a horizontal line - // pub indent_ends_with_horizontal_line: bool, - - // /// Height of a combo-box before showing scroll bars. - // pub combo_height: f32, - - // pub scroll_bar_width: f32, - //style.spacing.scroll_bar_width = 15.0; - - // /// Make sure the scroll handle is at least this big - //style.spacing.scroll_handle_min_length = 40.0; - - // /// Margin between contents and scroll bar. - // pub scroll_bar_inner_margin: f32, - - // /// Margin between scroll bar and the outer container (e.g. right of a vertical scroll bar). - // pub scroll_bar_outer_margin: f32, - - if dark_mode { - // ---- dark mode ------------------------------------------------------------------------------------------ - style.visuals = Visuals { - dark_mode: true, - widgets: Widgets { - noninteractive: WidgetVisuals { - weak_bg_fill: Color32::from_gray(27), - bg_fill: Color32::from_white_alpha(8), - bg_stroke: Stroke::new(1.0, Color32::from_gray(72)), // separators, borders - fg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // normal text color - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - inactive: WidgetVisuals { - weak_bg_fill: Color32::from_gray(60), // button background - bg_fill: Color32::from_white_alpha(8), - bg_stroke: Stroke::new(1.0, Color32::from_gray(72)), // separators, borders - // The following is used for All buttons, any clickable text, - // AND text inputs, whether they are inactive OR active. It's really - // overloaded. - fg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // button text - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - hovered: WidgetVisuals { - weak_bg_fill: Color32::from_gray(70), - bg_fill: Color32::from_gray(70), - bg_stroke: Stroke::new(1.0, Color32::from_gray(150)), // e.g. hover over window edge or button - fg_stroke: Stroke::new(1.5, Color32::from_gray(240)), - rounding: Rounding::same(3.0), - expansion: 1.0, - }, - active: WidgetVisuals { - weak_bg_fill: Color32::from_gray(55), - bg_fill: Color32::from_gray(55), - bg_stroke: Stroke::new(1.0, Color32::WHITE), - fg_stroke: Stroke::new(2.0, Color32::WHITE), - rounding: Rounding::same(2.0), - expansion: 1.0, - }, - open: WidgetVisuals { - weak_bg_fill: Color32::from_gray(27), - bg_fill: Color32::from_gray(27), - bg_stroke: Stroke::new(1.0, Color32::from_gray(60)), - fg_stroke: Stroke::new(1.0, Color32::from_gray(210)), - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - }, - - // Background colors - window_fill: Color32::from_gray(30), // pulldown menus and tooltips - panel_fill: Color32::from_gray(30), // panel backgrounds, even-table-rows - faint_bg_color: Color32::from_gray(0x14), // odd-table-rows - extreme_bg_color: Color32::from_gray(0), // text input background; scrollbar background - code_bg_color: Color32::from_gray(64), // ??? - - // Foreground colors - window_stroke: Stroke::new(1.0, Color32::from_gray(230)), - override_text_color: None, - warn_fg_color: Color32::from_rgb(255, 143, 0), // orange - error_fg_color: Color32::from_rgb(255, 0, 0), // red - hyperlink_color: Color32::from_rgb(0x73, 0x95, 0xae), // light blue? - - selection: Selection { - bg_fill: Color32::from_rgb(0x57, 0x4a, 0x40), - stroke: Stroke::new(1.0, Color32::from_gray(230)), - }, - - window_shadow: Shadow::big_dark(), - popup_shadow: Shadow::small_dark(), - - indent_has_left_vline: false, - menu_rounding: Rounding::same(2.0), - slider_trailing_fill: true, - striped: true, - window_rounding: Rounding::same(6.0), - resize_corner_size: 12.0, - text_cursor: Stroke::new(2.0, Color32::from_rgb(192, 222, 255)), - text_cursor_preview: false, - clip_rect_margin: 3.0, // should be at least half the size of the widest frame stroke + max WidgetVisuals::expansion - button_frame: true, - collapsing_header_frame: false, - interact_cursor: None, - image_loading_spinners: true, - }; - } else { - // ---- light mode ----------------------------------------------------------------------------------------- - style.visuals = Visuals { - dark_mode: false, - widgets: Widgets { - noninteractive: WidgetVisuals { - weak_bg_fill: Color32::from_gray(248), - bg_fill: Color32::from_black_alpha(20), - bg_stroke: Stroke::new(1.0, Color32::from_gray(192)), - fg_stroke: Stroke::new(1.0, Color32::from_gray(80)), // normal text color - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - inactive: WidgetVisuals { - weak_bg_fill: Color32::from_gray(230), // button background - bg_fill: Color32::from_black_alpha(20), - bg_stroke: Stroke::new(1.0, Color32::from_gray(192)), - // The following is used for All buttons, any clickable text, - // AND text inputs, whether they are inactive OR active. It's really - // overloaded. - fg_stroke: Stroke::new(1.0, Color32::from_gray(60)), // button text - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - hovered: WidgetVisuals { - weak_bg_fill: Color32::from_gray(220), - bg_fill: Color32::from_gray(220), - bg_stroke: Stroke::new(1.0, Color32::from_gray(105)), // e.g. hover over window edge or button - fg_stroke: Stroke::new(1.5, Color32::BLACK), - rounding: Rounding::same(3.0), - expansion: 1.0, - }, - active: WidgetVisuals { - weak_bg_fill: Color32::from_gray(165), - bg_fill: Color32::from_gray(165), - bg_stroke: Stroke::new(1.0, Color32::BLACK), - fg_stroke: Stroke::new(2.0, Color32::BLACK), - rounding: Rounding::same(2.0), - expansion: 1.0, - }, - open: WidgetVisuals { - weak_bg_fill: Color32::from_gray(220), - bg_fill: Color32::from_gray(220), - bg_stroke: Stroke::new(1.0, Color32::from_gray(160)), - fg_stroke: Stroke::new(1.0, Color32::BLACK), - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - }, - - // Background colors - window_fill: Color32::from_gray(0xec), // pulldown menus and tooltips - panel_fill: Color32::from_gray(0xec), // panel backgrounds, even-table-rows - faint_bg_color: Color32::from_gray(0xf9), // odd-table-rows - extreme_bg_color: Color32::from_gray(0xff), // text input background; scrollbar background - code_bg_color: Color32::from_gray(230), // ??? - - // Foreground colors - window_stroke: Stroke::new(1.0, Color32::from_rgb(0x5d, 0x5c, 0x61)), // DONE - override_text_color: None, - warn_fg_color: Color32::from_rgb(255, 100, 0), // slightly orange red. it's difficult to find a warning color that pops on bright background. - error_fg_color: Color32::from_rgb(255, 0, 0), // red - hyperlink_color: Color32::from_rgb(0x55, 0x7a, 0x95), // DONE - - selection: Selection { - bg_fill: Color32::WHITE, // DONE - stroke: Stroke::new(1.0, Color32::from_rgb(0x5d, 0x5c, 0x61)), // DONE - }, - - window_shadow: Shadow::big_light(), - popup_shadow: Shadow::small_light(), - - indent_has_left_vline: false, - menu_rounding: Rounding::same(2.0), - slider_trailing_fill: true, - striped: true, - window_rounding: Rounding::same(6.0), - resize_corner_size: 12.0, - text_cursor: Stroke::new(2.0, Color32::from_rgb(0, 83, 125)), - text_cursor_preview: false, - clip_rect_margin: 3.0, // should be at least half the size of the widest frame stroke + max WidgetVisuals::expansion - button_frame: true, - collapsing_header_frame: false, - interact_cursor: None, - image_loading_spinners: true, - }; - } - style - } - - /// the style to use when displaying on-top of an accent-colored background - fn get_on_accent_style(dark_mode: bool) -> Style { - let mut style = Self::get_style(!dark_mode); - if dark_mode { - todo!() - } else { - style.visuals.widgets.noninteractive.fg_stroke.color = Color32::WHITE; - style.visuals.widgets.inactive.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.inactive.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); - style.visuals.widgets.active.bg_fill = Color32::from_black_alpha(20); - style.visuals.widgets.active.fg_stroke = Stroke::new(1.0, Color32::from_black_alpha(50)); - style.visuals.widgets.hovered.bg_fill = Color32::from_white_alpha(8); - style.visuals.widgets.hovered.fg_stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); - style.visuals.selection.bg_fill = Self::accent_color(dark_mode).gamma_multiply(1.2); - style.visuals.selection.stroke = Stroke::new(1.0, Color32::from_white_alpha(230)); - } - style - } - - fn font_definitions() -> FontDefinitions { - super::font_definitions() // use default gossip font definitions - } - - fn text_styles() -> BTreeMap { - let mut text_styles: BTreeMap = BTreeMap::new(); - - text_styles.insert( - TextStyle::Small, - FontId { - size: 10.75, - family: FontFamily::Proportional, - }, - ); - - text_styles.insert( - TextStyle::Body, - FontId { - size: 12.5, - family: FontFamily::Proportional, - }, - ); - - text_styles.insert( - TextStyle::Monospace, - FontId { - size: 12.5, - family: FontFamily::Monospace, - }, - ); - - text_styles.insert( - TextStyle::Button, - FontId { - size: 12.5, - family: FontFamily::Proportional, - }, - ); - - text_styles.insert( - TextStyle::Heading, - FontId { - size: 16.25, - family: FontFamily::Proportional, - }, - ); - - // for subject lines in notes - text_styles.insert( - TextStyle::Name("subject".into()), - FontId { - size: 15.0, - family: FontFamily::Proportional, - }, - ); - - text_styles - } - - fn highlight_text_format(highlight_type: HighlightType, dark_mode: bool) -> TextFormat { - let main = if dark_mode { - Color32::WHITE - } else { - Color32::BLACK - }; - let grey = if dark_mode { - Color32::from_gray(36) - } else { - Color32::LIGHT_GRAY - }; - let green = if dark_mode { - Color32::LIGHT_GREEN - } else { - Color32::DARK_GREEN - }; - let red = if dark_mode { - Color32::LIGHT_RED - } else { - Color32::DARK_RED - }; - let purple = if dark_mode { - Color32::from_rgb(0xA0, 0x40, 0xA0) - } else { - Color32::from_rgb(0x80, 0, 0x80) - }; - - match highlight_type { - HighlightType::Nothing => TextFormat { - font_id: FontId::new(12.5, FontFamily::Proportional), - color: main, - ..Default::default() - }, - HighlightType::PublicKey => TextFormat { - font_id: FontId::new(12.5, FontFamily::Monospace), - background: grey, - color: green, - ..Default::default() - }, - HighlightType::Event => TextFormat { - font_id: FontId::new(12.5, FontFamily::Monospace), - background: grey, - color: red, - ..Default::default() - }, - HighlightType::Relay => TextFormat { - font_id: FontId::new(12.5, FontFamily::Monospace), - background: grey, - color: purple, - ..Default::default() - }, - HighlightType::Hyperlink => TextFormat { - font_id: FontId::new(12.5, FontFamily::Proportional), - color: { - // This should match get_style() above for hyperlink color. - if dark_mode { - Color32::from_rgb(0x73, 0x95, 0xae) - } else { - Color32::from_rgb(0x55, 0x7a, 0x95) - } - }, - ..Default::default() - }, - } - } - - fn warning_marker_text_color(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::LIGHT_RED - } else { - Color32::DARK_RED - } - } - - fn notice_marker_text_color(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::LIGHT_BLUE - } else { - Color32::DARK_BLUE - } - } - - fn navigation_bg_fill(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::from_rgb(0x30, 0x6f, 0xc1) - } else { - Color32::from_rgb(0x55, 0x7a, 0x95) - } - } - - fn navigation_text_deactivated_color(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::from_white_alpha(10) - } else { - Color32::from_black_alpha(100) - } - } - - fn navigation_text_color(_dark_mode: bool) -> eframe::egui::Color32 { - //if dark_mode { - Color32::from_gray(220) - //} else { - // Color32::from_gray(220) - //} - } - - fn navigation_text_active_color(_dark_mode: bool) -> eframe::egui::Color32 { - //if dark_mode { - Color32::from_gray(0xf9) - //} else { - // Color32::from_gray(0xf9) - //} - } - - fn navigation_text_hover_color(_dark_mode: bool) -> eframe::egui::Color32 { - Color32::WHITE - } - - fn navigation_header_active_color(_dark_mode: bool) -> eframe::egui::Color32 { - Color32::from_gray(0xaa) - } - - fn input_text_color(dark_mode: bool) -> eframe::egui::Color32 { - if dark_mode { - Color32::from_gray(190) - } else { - Color32::from_gray(60) - } - } - - // feed styling - fn feed_scroll_rounding(_feed: &FeedProperties) -> Rounding { - Rounding::same(7.0) - } - fn feed_scroll_fill(_dark_mode: bool, _feed: &FeedProperties) -> Color32 { - Color32::TRANSPARENT - } - fn feed_scroll_stroke(_dark_mode: bool, _feed: &FeedProperties) -> Stroke { - Stroke::NONE - } - fn feed_post_separator_stroke(_dark_mode: bool, _post: &NoteRenderData) -> Stroke { - Stroke::new(1.0, Color32::TRANSPARENT) - } - fn feed_post_outer_indent(ui: &mut eframe::egui::Ui, post: &NoteRenderData) { - if post.is_thread { - let space = 100.0 * (10.0 - (1000.0 / (post.thread_position as f32 + 100.0))); - ui.add_space(space); - } - } - fn feed_post_inner_indent(_ui: &mut eframe::egui::Ui, _post: &NoteRenderData) {} - fn feed_frame_inner_margin(_post: &NoteRenderData) -> Margin { - Margin { - left: 10.0, - right: 10.0, - top: 10.0, - bottom: 5.0, - } - } - fn feed_frame_outer_margin(_post: &NoteRenderData) -> Margin { - Margin::default() - } - fn feed_frame_rounding(post: &NoteRenderData) -> Rounding { - if post.is_thread { - let mut rounding = Rounding::ZERO; - if post.is_first && post.thread_position == 0 { - rounding.nw = 7.0; - rounding.ne = 7.0; - } - rounding - } else { - Rounding::same(7.0) - } - } - fn feed_frame_shadow(_dark_mode: bool, _post: &NoteRenderData) -> Shadow { - Shadow::NONE - } - fn feed_frame_fill(dark_mode: bool, post: &NoteRenderData) -> Color32 { - if post.is_new { - if dark_mode { - Color32::from_rgb(45, 45, 46) - } else { - Color32::from_rgb(0xFF, 0xFF, 0xFA) - } - } else { - if dark_mode { - Color32::from_rgb(36, 36, 37) - } else { - Color32::WHITE - } - } - } - fn feed_frame_stroke(dark_mode: bool, post: &NoteRenderData) -> Stroke { - if post.is_main_event { - if dark_mode { - Stroke::new(1.0, Color32::from_rgb(64, 96, 64)) - } else { - Stroke::new(1.0, Color32::from_rgb(96, 128, 96)) - } - } else { - if dark_mode { - Stroke::new(1.0, Color32::from_gray(50)) - } else { - Stroke::new(1.0, Color32::from_gray(0xCC)) - } - } - } - - fn repost_separator_before_stroke(dark_mode: bool, post: &NoteRenderData) -> Stroke { - if post.is_comment_mention { - return Stroke::NONE; - } - - if dark_mode { - Stroke::new(1.0, Color32::from_gray(72)) - } else { - Stroke::new(1.0, Color32::from_gray(192)) - } - } - fn repost_space_above_separator_before(_post: &NoteRenderData) -> f32 { - 0.0 - } - fn repost_space_below_separator_before(post: &NoteRenderData) -> f32 { - if !post.is_comment_mention { - 8.0 - } else { - 0.0 - } - } - - fn repost_separator_after_stroke(_dark_mode: bool, _post: &NoteRenderData) -> Stroke { - Stroke::NONE - } - fn repost_space_above_separator_after(_post: &NoteRenderData) -> f32 { - 0.0 - } - fn repost_space_below_separator_after(_post: &NoteRenderData) -> f32 { - 0.0 - } - - fn repost_inner_margin(post: &NoteRenderData) -> Margin { - Margin { - left: 0.0, - top: if post.is_comment_mention { 6.0 } else { 0.0 }, - right: 10.0, - bottom: if post.is_comment_mention { 7.0 } else { 0.0 }, - } - } - fn repost_outer_margin(post: &NoteRenderData) -> Margin { - Margin { - left: 0.0, - top: if post.is_comment_mention { 10.0 } else { 4.0 }, - right: -10.0, - bottom: if post.is_comment_mention { 6.0 } else { 0.0 }, - } - } - fn repost_rounding(post: &NoteRenderData) -> Rounding { - Self::feed_frame_rounding(post) - } - fn repost_shadow(_dark_mode: bool, _post: &NoteRenderData) -> Shadow { - Shadow::NONE - } - fn repost_fill(dark_mode: bool, post: &NoteRenderData) -> Color32 { - if !post.is_comment_mention { - return Color32::TRANSPARENT; - } - - let mut hsva: ecolor::HsvaGamma = Self::feed_frame_fill(dark_mode, post).into(); - if dark_mode { - hsva.v = (hsva.v + 0.05).min(1.0); // lighten - } else { - hsva.v = (hsva.v - 0.05).max(0.0); // darken - } - let color: Color32 = hsva.into(); - color - } - fn repost_stroke(_dark_mode: bool, _post: &NoteRenderData) -> Stroke { - Stroke::NONE - } - - fn round_image() -> bool { - true - } -} From 5f44a290afa0c827052f1b915e8d4e53732b7071 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Mon, 9 Oct 2023 07:42:53 +1300 Subject: [PATCH 43/46] cargo fmt and clippy --- gossip-bin/src/ui/feed/note/mod.rs | 44 ++++++++++++++++++++++++------ gossip-bin/src/ui/relays/active.rs | 1 - gossip-bin/src/ui/relays/mod.rs | 23 ++++++++++------ gossip-bin/src/ui/theme/default.rs | 2 +- 4 files changed, 51 insertions(+), 19 deletions(-) diff --git a/gossip-bin/src/ui/feed/note/mod.rs b/gossip-bin/src/ui/feed/note/mod.rs index 8631e9b4..e7cce694 100644 --- a/gossip-bin/src/ui/feed/note/mod.rs +++ b/gossip-bin/src/ui/feed/note/mod.rs @@ -307,30 +307,50 @@ fn render_note_inner( if note.event.pow() > 0 { let color = app.theme.notice_marker_text_color(); - ui.label(RichText::new(format!("POW={}", note.event.pow())).color(color).text_style(TextStyle::Small)); + ui.label( + RichText::new(format!("POW={}", note.event.pow())) + .color(color) + .text_style(TextStyle::Small), + ); } match ¬e.delegation { EventDelegation::InvalidDelegation(why) => { let color = app.theme.warning_marker_text_color(); - ui.add(Label::new(RichText::new("INVALID DELEGATION").color(color).text_style(TextStyle::Small))) - .on_hover_text(why); + ui.add(Label::new( + RichText::new("INVALID DELEGATION") + .color(color) + .text_style(TextStyle::Small), + )) + .on_hover_text(why); } EventDelegation::DelegatedBy(_) => { let color = app.theme.notice_marker_text_color(); - ui.label(RichText::new("DELEGATED").color(color).text_style(TextStyle::Small)); + ui.label( + RichText::new("DELEGATED") + .color(color) + .text_style(TextStyle::Small), + ); } _ => {} } if note.deletion.is_some() { let color = app.theme.warning_marker_text_color(); - ui.label(RichText::new("DELETED").color(color).text_style(TextStyle::Small)); + ui.label( + RichText::new("DELETED") + .color(color) + .text_style(TextStyle::Small), + ); } if note.event.kind == EventKind::Repost { let color = app.theme.notice_marker_text_color(); - ui.label(RichText::new("REPOSTED").color(color).text_style(TextStyle::Small)); + ui.label( + RichText::new("REPOSTED") + .color(color) + .text_style(TextStyle::Small), + ); } if let Page::Feed(FeedKind::DmChat(_)) = app.page { @@ -339,9 +359,17 @@ fn render_note_inner( if note.event.kind.is_direct_message_related() { let color = app.theme.notice_marker_text_color(); if note.secure { - ui.label(RichText::new("PRIVATE CHAT (GIFT WRAPPED)").color(color).text_style(TextStyle::Small)); + ui.label( + RichText::new("PRIVATE CHAT (GIFT WRAPPED)") + .color(color) + .text_style(TextStyle::Small), + ); } else { - ui.label(RichText::new("PRIVATE CHAT").color(color).text_style(TextStyle::Small)); + ui.label( + RichText::new("PRIVATE CHAT") + .color(color) + .text_style(TextStyle::Small), + ); } } } diff --git a/gossip-bin/src/ui/relays/active.rs b/gossip-bin/src/ui/relays/active.rs index 9bf38514..592ac7c2 100644 --- a/gossip-bin/src/ui/relays/active.rs +++ b/gossip-bin/src/ui/relays/active.rs @@ -84,4 +84,3 @@ fn get_relays(app: &mut GossipUi) -> Vec { relays.sort_by(|a, b| super::sort_relay(&app.relays, a, b)); relays } - diff --git a/gossip-bin/src/ui/relays/mod.rs b/gossip-bin/src/ui/relays/mod.rs index 9ec2d51b..c2a1231f 100644 --- a/gossip-bin/src/ui/relays/mod.rs +++ b/gossip-bin/src/ui/relays/mod.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use super::{GossipUi, Page, widgets}; +use super::{widgets, GossipUi, Page}; use eframe::{egui, epaint::PathShape}; use egui::{Context, Ui}; use egui_winit::egui::{vec2, Id, Rect, RichText}; @@ -471,7 +471,7 @@ pub(super) fn configure_list_btn(app: &mut GossipUi, ui: &mut Ui) { } let button_center_bottom = response.rect.center_bottom(); - let seen_on_popup_position = button_center_bottom + vec2( -180.0, widgets::DROPDOWN_DISTANCE ); + let seen_on_popup_position = button_center_bottom + vec2(-180.0, widgets::DROPDOWN_DISTANCE); let id: Id = "configure-list-menu".into(); let mut frame = egui::Frame::popup(ui.style()); @@ -490,24 +490,29 @@ pub(super) fn configure_list_btn(app: &mut GossipUi, ui: &mut Ui) { frame.inner_margin = egui::Margin::symmetric(20.0, 16.0); frame.show(ui, |ui| { let path = PathShape::convex_polygon( - [ button_center_bottom, - button_center_bottom + vec2(widgets::DROPDOWN_DISTANCE, widgets::DROPDOWN_DISTANCE), - button_center_bottom + vec2(-widgets::DROPDOWN_DISTANCE, widgets::DROPDOWN_DISTANCE)] - .to_vec(), + [ + button_center_bottom, + button_center_bottom + + vec2(widgets::DROPDOWN_DISTANCE, widgets::DROPDOWN_DISTANCE), + button_center_bottom + + vec2(-widgets::DROPDOWN_DISTANCE, widgets::DROPDOWN_DISTANCE), + ] + .to_vec(), app.theme.accent_color(), - egui::Stroke::NONE); + egui::Stroke::NONE, + ); ui.painter().add(path); let size = ui.spacing().interact_size.y * egui::vec2(1.6, 0.8); // since we are displaying over an accent color background, load that style *ui.style_mut() = app.theme.get_on_accent_style(); - ui.horizontal(|ui|{ + ui.horizontal(|ui| { crate::ui::components::switch_with_size(ui, &mut app.relays.show_details, size); ui.label("Show details"); }); ui.add_space(8.0); - ui.horizontal(|ui|{ + ui.horizontal(|ui| { crate::ui::components::switch_with_size(ui, &mut app.relays.show_hidden, size); ui.label("Show hidden relays"); }); diff --git a/gossip-bin/src/ui/theme/default.rs b/gossip-bin/src/ui/theme/default.rs index a29b50ad..02cd8f0c 100644 --- a/gossip-bin/src/ui/theme/default.rs +++ b/gossip-bin/src/ui/theme/default.rs @@ -456,7 +456,7 @@ impl ThemeDef for DefaultTheme { fn navigation_bg_fill(dark_mode: bool) -> eframe::egui::Color32 { let mut hsva: ecolor::HsvaGamma = Self::get_style(dark_mode).visuals.panel_fill.into(); let delta = if dark_mode { 1.3 } else { 0.90 }; - hsva.v = hsva.v * delta; + hsva.v *= delta; hsva.into() } From 421355d7b1191eeede4aac7d0e96ea7a0ad2f7e6 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Mon, 9 Oct 2023 08:12:19 +1300 Subject: [PATCH 44/46] Wizard fixes --- gossip-bin/src/ui/wizard/follow_people.rs | 45 +++++++++------- gossip-bin/src/ui/wizard/setup_relays.rs | 65 +++++++++-------------- 2 files changed, 53 insertions(+), 57 deletions(-) diff --git a/gossip-bin/src/ui/wizard/follow_people.rs b/gossip-bin/src/ui/wizard/follow_people.rs index e6e80a40..3fe20165 100644 --- a/gossip-bin/src/ui/wizard/follow_people.rs +++ b/gossip-bin/src/ui/wizard/follow_people.rs @@ -52,7 +52,6 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr .to_overlord .send(ToOverlordMessage::UpdateMetadata(*pk)); // then remember we did so we don't keep doing it over and over again - tracing::error!("DEBUGGING: fetching metadata for {}", pk.as_hex_string()); app.wizard_state .followed_getting_metadata .insert(pk.to_owned()); @@ -134,25 +133,35 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr ui.label(" • Profile (nprofile1..)"); ui.label(" • DNS ID (user@domain)"); - ui.add_space(20.0); - let mut label = RichText::new(" > Publish and Finish"); - if app.wizard_state.new_user { - label = label.color(app.theme.accent_color()); - } - if ui.button(label).clicked() { - let _ = GLOBALS.to_overlord.send(ToOverlordMessage::PushFollow); + if app.wizard_state.has_private_key { + ui.add_space(20.0); + let mut label = RichText::new(" > Publish and Finish"); + if app.wizard_state.new_user { + label = label.color(app.theme.accent_color()); + } + if ui.button(label).clicked() { + let _ = GLOBALS.to_overlord.send(ToOverlordMessage::PushFollow); - let _ = GLOBALS.storage.write_wizard_complete(true, None); - app.page = Page::Feed(FeedKind::Followed(false)); - } + let _ = GLOBALS.storage.write_wizard_complete(true, None); + app.page = Page::Feed(FeedKind::Followed(false)); + } - ui.add_space(20.0); - let mut label = RichText::new(" > Finish without publishing"); - if !app.wizard_state.new_user { + ui.add_space(20.0); + let mut label = RichText::new(" > Finish without publishing"); + if !app.wizard_state.new_user { + label = label.color(app.theme.accent_color()); + } + if ui.button(label).clicked() { + let _ = GLOBALS.storage.write_wizard_complete(true, None); + app.page = Page::Feed(FeedKind::Followed(false)); + } + } else { + ui.add_space(20.0); + let mut label = RichText::new(" > Finish"); label = label.color(app.theme.accent_color()); - } - if ui.button(label).clicked() { - let _ = GLOBALS.storage.write_wizard_complete(true, None); - app.page = Page::Feed(FeedKind::Followed(false)); + if ui.button(label).clicked() { + let _ = GLOBALS.storage.write_wizard_complete(true, None); + app.page = Page::Feed(FeedKind::Followed(false)); + } } } diff --git a/gossip-bin/src/ui/wizard/setup_relays.rs b/gossip-bin/src/ui/wizard/setup_relays.rs index eea5d9bd..140d77cc 100644 --- a/gossip-bin/src/ui/wizard/setup_relays.rs +++ b/gossip-bin/src/ui/wizard/setup_relays.rs @@ -226,47 +226,34 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr } if !need_more { - ui.add_space(20.0); - let mut label = RichText::new(" > Publish and Continue"); - if app.wizard_state.new_user { - label = label.color(app.theme.accent_color()); - } - if ui.button(label).clicked() { - let _ = GLOBALS - .to_overlord - .send(ToOverlordMessage::AdvertiseRelayList); - app.page = Page::Wizard(WizardPage::SetupMetadata); - } + if app.wizard_state.has_private_key { + ui.add_space(20.0); + let mut label = RichText::new(" > Publish and Continue"); + if app.wizard_state.new_user { + label = label.color(app.theme.accent_color()); + } + if ui.button(label).clicked() { + let _ = GLOBALS + .to_overlord + .send(ToOverlordMessage::AdvertiseRelayList); + app.page = Page::Wizard(WizardPage::SetupMetadata); + } - ui.add_space(20.0); - let mut label = RichText::new(" > Continue without publishing"); - if !app.wizard_state.new_user { + ui.add_space(20.0); + let mut label = RichText::new(" > Continue without publishing"); + if !app.wizard_state.new_user { + label = label.color(app.theme.accent_color()); + } + if ui.button(label).clicked() { + app.page = Page::Wizard(WizardPage::SetupMetadata); + }; + } else { + ui.add_space(20.0); + let mut label = RichText::new(" > Continue"); label = label.color(app.theme.accent_color()); + if ui.button(label).clicked() { + app.page = Page::Wizard(WizardPage::SetupMetadata); + }; } - if ui.button(label).clicked() { - app.page = Page::Wizard(WizardPage::SetupMetadata); - }; } - - /* - [only if privatekey] - - Please select several relays that you will publish your notes to. We recommend at - least 2, but no more than 10. - - Enter a Relay URL: _____________________ [ADD] - - You may also pick from this list of popular relays, however be aware that this - list may go out of date rapidly. - --- - --- - --- - - ( Continue ) ( 40 ) - ( Go Back) ( 1 or 20, dep if they are new or not, which we have to save in a UI var ) - ( Exit this Wizard) - - (You can change your relays by visiting the RELAYS page) - - */ } From e13e6aeae11385ea63a7ec84eb2f745ca4698218 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Mon, 9 Oct 2023 08:23:42 +1300 Subject: [PATCH 45/46] Fix mute list issue --- gossip-bin/src/ui/people/muted.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gossip-bin/src/ui/people/muted.rs b/gossip-bin/src/ui/people/muted.rs index e9013f1f..cf9fd7e9 100644 --- a/gossip-bin/src/ui/people/muted.rs +++ b/gossip-bin/src/ui/people/muted.rs @@ -9,10 +9,15 @@ use std::sync::atomic::Ordering; pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { let muted_pubkeys = GLOBALS.people.get_muted_pubkeys(); + let mut people: Vec = Vec::new(); for pk in &muted_pubkeys { if let Ok(Some(person)) = GLOBALS.storage.read_person(pk) { people.push(person); + } else { + let person = Person::new(pk.to_owned()); + let _ = GLOBALS.storage.write_person(&person, None); + people.push(person); } } people.sort_unstable(); From 74d29374cddf9fb9cc4c26912814fb1ce822dee0 Mon Sep 17 00:00:00 2001 From: Daniele Tonon Date: Mon, 9 Oct 2023 09:46:47 +0200 Subject: [PATCH 46/46] Fix hover contrast on buttons/dropdown Bug from b309a197 styling of the sidebar's drag handle --- gossip-bin/src/ui/theme/default.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gossip-bin/src/ui/theme/default.rs b/gossip-bin/src/ui/theme/default.rs index 02cd8f0c..16d67259 100644 --- a/gossip-bin/src/ui/theme/default.rs +++ b/gossip-bin/src/ui/theme/default.rs @@ -129,7 +129,7 @@ impl ThemeDef for DefaultTheme { weak_bg_fill: Color32::from_white_alpha(4), bg_fill: Color32::from_white_alpha(20), bg_stroke: Stroke::new(0.0, Self::accent_color(dark_mode)), // e.g. hover over window edge or button - fg_stroke: Stroke::new(1.5, Color32::from_white_alpha(1)), + fg_stroke: Stroke::new(1.5, Color32::from_white_alpha(240)), rounding: Rounding::same(3.0), expansion: 2.0, }, @@ -214,7 +214,7 @@ impl ThemeDef for DefaultTheme { weak_bg_fill: Color32::from_black_alpha(10), bg_fill: Color32::from_black_alpha(10), bg_stroke: Stroke::new(0.0, Self::accent_color(dark_mode)), // e.g. hover over window edge or button - fg_stroke: Stroke::new(1.5, Color32::from_black_alpha(20)), + fg_stroke: Stroke::new(1.5, Color32::from_black_alpha(240)), rounding: Rounding::same(3.0), expansion: 2.0, },