From 0200cbe3d21aafa84008559089e1e8494d7b8aee Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Wed, 21 Dec 2022 11:45:15 +1300 Subject: [PATCH] More UI work --- Cargo.lock | 45 ++++++++++++++++ Cargo.toml | 2 +- src/ui/about.rs | 7 +++ src/ui/feed.rs | 7 +++ src/ui/mod.rs | 75 ++++++++++++++++++++------ src/ui/people.rs | 7 +++ src/ui/relays.rs | 7 +++ src/ui/settings.rs | 35 ++++++++++++ src/ui/stats.rs | 7 +++ src/ui/style.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++ src/ui/you.rs | 7 +++ 11 files changed, 310 insertions(+), 18 deletions(-) create mode 100644 src/ui/about.rs create mode 100644 src/ui/feed.rs create mode 100644 src/ui/people.rs create mode 100644 src/ui/relays.rs create mode 100644 src/ui/settings.rs create mode 100644 src/ui/stats.rs create mode 100644 src/ui/style.rs create mode 100644 src/ui/you.rs diff --git a/Cargo.lock b/Cargo.lock index dabe14be..436728af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,7 @@ checksum = "3083ac5a97521e35388ca80cf365b6be5210962cc59f11ee238cd92ac2fa9524" dependencies = [ "enumset", "kurbo", + "serde", ] [[package]] @@ -115,6 +116,7 @@ checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" dependencies = [ "cfg-if", "once_cell", + "serde", "version_check", ] @@ -937,6 +939,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs" version = "4.0.0" @@ -957,6 +969,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -1017,6 +1040,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b601108bca3af7650440ace4ca55b2daf52c36f2635be3587d77b16efd8d0691" dependencies = [ "bytemuck", + "serde", ] [[package]] @@ -1027,6 +1051,7 @@ checksum = "5ea929ec5819fef373728bb0e55003ce921975039cfec3ca8305bb024e5b7b32" dependencies = [ "bytemuck", "dark-light", + "directories-next", "egui", "egui-winit", "egui_glow", @@ -1035,6 +1060,8 @@ dependencies = [ "js-sys", "percent-encoding", "raw-window-handle 0.5.0", + "ron", + "serde", "tracing", "wasm-bindgen", "wasm-bindgen-futures", @@ -1052,6 +1079,8 @@ dependencies = [ "ahash 0.8.2", "epaint", "nohash-hasher", + "ron", + "serde", "tracing", ] @@ -1065,6 +1094,7 @@ dependencies = [ "arboard", "egui", "instant", + "serde", "smithay-clipboard", "tracing", "webbrowser", @@ -1133,6 +1163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5277249c8c3430e7127e4f2c40a77485e7baf11ae132ce9b3253a8ed710df0a0" dependencies = [ "bytemuck", + "serde", ] [[package]] @@ -1172,6 +1203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19be8061a06ab6f3a6cf21106c873578bf01bd42ad15e0311a9c76161cb1c753" dependencies = [ "enumset_derive", + "serde", ] [[package]] @@ -1200,6 +1232,7 @@ dependencies = [ "emath", "nohash-hasher", "parking_lot", + "serde", ] [[package]] @@ -1988,6 +2021,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a53776d271cfb873b17c618af0298445c88afc52837f3e948fa3fafd131f449" dependencies = [ "arrayvec 0.7.2", + "serde", ] [[package]] @@ -2929,6 +2963,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "ron" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" +dependencies = [ + "base64 0.13.1", + "bitflags", + "serde", +] + [[package]] name = "roxmltree" version = "0.14.1" diff --git a/Cargo.toml b/Cargo.toml index 13a7cd6c..c47319d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ edition = "2021" [dependencies] base64 = "0.13" dirs = "4.0" -eframe = { version = "0.20", features = [ "dark-light" ] } +eframe = { version = "0.20", features = [ "dark-light", "persistence" ] } egui_extras = { version = "0.20", features = [ "svg", "tracing" ] } futures = "0.3" http = "0.2" diff --git a/src/ui/about.rs b/src/ui/about.rs new file mode 100644 index 00000000..380bbc28 --- /dev/null +++ b/src/ui/about.rs @@ -0,0 +1,7 @@ +use super::GossipUi; +use eframe::egui; +use egui::{Context, Ui}; + +pub(super) fn update(_app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { + ui.label("ABOUT PAGE - Coming Soon".to_string()); +} diff --git a/src/ui/feed.rs b/src/ui/feed.rs new file mode 100644 index 00000000..31c73093 --- /dev/null +++ b/src/ui/feed.rs @@ -0,0 +1,7 @@ +use super::GossipUi; +use eframe::egui; +use egui::{Context, Ui}; + +pub(super) fn update(_app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { + ui.label("FEED PAGE - Coming Soon".to_string()); +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 6154ade9..421f1457 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,6 +1,15 @@ +mod about; +mod feed; +mod people; +mod relays; +mod settings; +mod stats; +mod style; +mod you; + use crate::error::Error; use eframe::{egui, IconData, Theme}; -use egui::style::Style; +use egui::Context; pub fn run() -> Result<(), Error> { let icon_bytes = include_bytes!("../../gossip.png"); @@ -9,6 +18,7 @@ pub fn run() -> Result<(), Error> { let options = eframe::NativeOptions { decorated: true, + drag_and_drop_support: true, default_theme: Theme::Light, icon_data: Some(IconData { rgba: icon.into_raw(), @@ -16,14 +26,15 @@ pub fn run() -> Result<(), Error> { height: icon_height, }), initial_window_size: Some(egui::vec2(700.0, 900.0)), + resizable: true, centered: true, ..Default::default() }; eframe::run_native( - "Gossip", + "gossip", options, - Box::new(|_cc| Box::new(GossipUi::default())), + Box::new(|cc| Box::new(GossipUi::new(cc))), ); Ok(()) @@ -42,37 +53,67 @@ enum Page { struct GossipUi { page: Page, + initial_dark_mode_set: bool, + fonts_installed: bool, + } -impl Default for GossipUi { - fn default() -> Self { - Self { page: Page::Feed } +impl GossipUi { + fn new(_cc: &eframe::CreationContext<'_>) -> Self { + GossipUi { + page: Page::Feed, + initial_dark_mode_set: false, + fonts_installed: false, + } } } impl eframe::App for GossipUi { - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - egui::CentralPanel::default().show(ctx, |ui| { - //ui.heading("Gossip"); + fn update(&mut self, ctx: &Context, frame: &mut eframe::Frame) { + let darkmode: bool = ctx.style().visuals.dark_mode; + if ! self.initial_dark_mode_set { + if darkmode { + ctx.set_visuals(style::dark_mode_visuals()); + } else { + ctx.set_visuals(style::light_mode_visuals()); + }; + self.initial_dark_mode_set = true; + } + + if ! self.fonts_installed { + ctx.set_fonts(style::font_definitions()); + self.fonts_installed = true; + } + + egui::TopBottomPanel::top("menu").show(ctx, |ui| { ui.horizontal(|ui| { - // light-dark switcher - let style: Style = (*ui.ctx().style()).clone(); - let new_visuals = style.visuals.light_dark_small_toggle_button(ui); - if let Some(visuals) = new_visuals { - ui.ctx().set_visuals(visuals); - } - ui.selectable_value(&mut self.page, Page::Feed, "Feed"); + ui.separator(); ui.selectable_value(&mut self.page, Page::People, "People"); + ui.separator(); ui.selectable_value(&mut self.page, Page::You, "You"); + ui.separator(); ui.selectable_value(&mut self.page, Page::Relays, "Relays"); + ui.separator(); ui.selectable_value(&mut self.page, Page::Settings, "Settings"); + ui.separator(); ui.selectable_value(&mut self.page, Page::Stats, "Stats"); + ui.separator(); ui.selectable_value(&mut self.page, Page::About, "About"); + ui.separator(); }); + }); - ui.label("Hello World".to_string()); + egui::CentralPanel::default().show(ctx, |ui| match self.page { + Page::Feed => feed::update(self, ctx, frame, ui), + Page::People => people::update(self, ctx, frame, ui), + Page::You => you::update(self, ctx, frame, ui), + Page::Relays => relays::update(self, ctx, frame, ui), + Page::Settings => settings::update(self, ctx, frame, ui, darkmode), + Page::Stats => stats::update(self, ctx, frame, ui), + Page::About => about::update(self, ctx, frame, ui), }); } } + diff --git a/src/ui/people.rs b/src/ui/people.rs new file mode 100644 index 00000000..abe77eb6 --- /dev/null +++ b/src/ui/people.rs @@ -0,0 +1,7 @@ +use super::GossipUi; +use eframe::egui; +use egui::{Context, Ui}; + +pub(super) fn update(_app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { + ui.label("PEOPLE PAGE - Coming Soon".to_string()); +} diff --git a/src/ui/relays.rs b/src/ui/relays.rs new file mode 100644 index 00000000..5cca5e0c --- /dev/null +++ b/src/ui/relays.rs @@ -0,0 +1,7 @@ +use super::GossipUi; +use eframe::egui; +use egui::{Context, Ui}; + +pub(super) fn update(_app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { + ui.label("RELAYS PAGE - Coming Soon".to_string()); +} diff --git a/src/ui/settings.rs b/src/ui/settings.rs new file mode 100644 index 00000000..29797ea7 --- /dev/null +++ b/src/ui/settings.rs @@ -0,0 +1,35 @@ +use super::GossipUi; +use eframe::egui; +use egui::widgets::Button; +use egui::{Context, Ui}; + +pub(super) fn update( + _app: &mut GossipUi, + _ctx: &Context, + _frame: &mut eframe::Frame, + ui: &mut Ui, + darkmode: bool, +) { + ui.heading("Settings"); + + #[allow(clippy::collapsible_else_if)] + if darkmode { + if ui + .add(Button::new("☀ Light")) + .on_hover_text("Switch to light mode") + .clicked() + { + ui.ctx().set_visuals(super::style::light_mode_visuals()); + } + } else { + if ui + .add(Button::new("🌙 Dark")) + .on_hover_text("Switch to dark mode") + .clicked() + { + ui.ctx().set_visuals(super::style::dark_mode_visuals()); + } + } + + ui.label("SETTINGS PAGE - Coming Soon".to_string()); +} diff --git a/src/ui/stats.rs b/src/ui/stats.rs new file mode 100644 index 00000000..4aebab89 --- /dev/null +++ b/src/ui/stats.rs @@ -0,0 +1,7 @@ +use super::GossipUi; +use eframe::egui; +use egui::{Context, Ui}; + +pub(super) fn update(_app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { + ui.label("STATS PAGE - Coming Soon".to_string()); +} diff --git a/src/ui/style.rs b/src/ui/style.rs new file mode 100644 index 00000000..9f5ee01e --- /dev/null +++ b/src/ui/style.rs @@ -0,0 +1,129 @@ +use eframe::{egui, epaint}; +use egui::style::{Selection, Visuals, Widgets}; +use egui::{Color32, FontData, FontDefinitions, FontFamily, FontTweak, Rounding, Stroke}; +use epaint::Shadow; +use std::collections::BTreeMap; + +pub(super) fn dark_mode_visuals() -> Visuals { + Visuals { + dark_mode: true, + override_text_color: None, + widgets: Widgets::default(), + selection: Selection { + bg_fill: Color32::from_rgb(0xb1, 0xa2, 0x96), // DONE + stroke: Stroke::new(1.0, Color32::from_rgb(0x37, 0x96, 0x83)), // DONE + }, + hyperlink_color: Color32::from_rgb(0x73, 0x95, 0xae), // DONE + faint_bg_color: Color32::from_gray(0x30), // DONE + extreme_bg_color: Color32::from_gray(0), // e.g. TextEdit background + code_bg_color: Color32::from_gray(64), + warn_fg_color: Color32::from_rgb(255, 143, 0), // orange + error_fg_color: Color32::from_rgb(255, 0, 0), // red + window_rounding: Rounding::same(6.0), + window_shadow: Shadow::big_dark(), + window_fill: Color32::from_gray(0x24), // DONE + window_stroke: Stroke::new(1.0, Color32::from_rgb(0x37, 0x96, 0x83)), // DONE + panel_fill: Color32::from_gray(0x24), // DONE + popup_shadow: Shadow::small_dark(), + resize_corner_size: 12.0, + text_cursor_width: 2.0, + 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, + } +} + +pub(super) fn light_mode_visuals() -> Visuals { + Visuals { + dark_mode: false, + override_text_color: None, + widgets: Widgets::light(), + selection: Selection { + bg_fill: Color32::from_rgb(0xb1, 0xa2, 0x96), // DONE + stroke: Stroke::new(1.0, Color32::from_rgb(0x5d, 0x5c, 0x61)), // DONE + }, + hyperlink_color: Color32::from_rgb(0x55, 0x7a, 0x95), // DONE + faint_bg_color: Color32::from_gray(0xf0), // DONE + extreme_bg_color: Color32::from_gray(0xff), // e.g. TextEdit background + code_bg_color: Color32::from_gray(230), + 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 + window_rounding: Rounding::same(6.0), + window_shadow: Shadow::big_light(), + window_fill: Color32::from_gray(0xF8), // DONE + window_stroke: Stroke::new(1.0, Color32::from_rgb(0x5d, 0x5c, 0x61)), // DONE + panel_fill: Color32::from_gray(0xF8), // DONE + popup_shadow: Shadow::small_light(), + resize_corner_size: 12.0, + text_cursor_width: 2.0, + 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, + } +} + +pub(super) fn font_definitions() -> FontDefinitions { + let mut font_data: BTreeMap = BTreeMap::new(); + let mut families = BTreeMap::new(); + + // Cantarell - gnome default + // code fonts - Inconsolata-g, Hack + + + font_data.insert( + "Inconsolata".to_owned(), + FontData::from_static(include_bytes!("../../fonts/Inconsolata-Regular.ttf")), + ); + + font_data.insert( + "FreeSans".to_owned(), + FontData::from_static(include_bytes!("../../fonts/freefont-20120503/FreeSans.otf")), + ); + + // Some good looking emojis. Use as first priority: + font_data.insert( + "NotoColorEmoji".to_owned(), + FontData::from_static(include_bytes!("../../fonts/NotoColorEmoji.ttf")).tweak( + FontTweak { + scale: 0.81, // make it smaller + y_offset_factor: -0.2, // move it up + y_offset: 0.0, + }, + ), + ); + + font_data.insert( + "NotoSansRegular".to_owned(), + FontData::from_static(include_bytes!("../../fonts/NotoSans-Regular.ttf")), + ); + + font_data.insert( + "NotoSansMonoRegular".to_owned(), + FontData::from_static(include_bytes!("../../fonts/NotoSansMono-Regular.ttf")), + ); + + families.insert( + FontFamily::Monospace, + vec![ + "Inconsolata".to_owned(), + "NotoColorEmoji".to_owned(), + "NotoSansMonoRegular".to_owned(), + ], + ); + + families.insert( + FontFamily::Proportional, + vec![ + "FreeSans".to_owned(), + "NotoColorEmoji".to_owned(), + "NotoSansRegular".to_owned(), + ], + ); + + FontDefinitions { + font_data, + families, + } +} diff --git a/src/ui/you.rs b/src/ui/you.rs new file mode 100644 index 00000000..17269f5a --- /dev/null +++ b/src/ui/you.rs @@ -0,0 +1,7 @@ +use super::GossipUi; +use eframe::egui; +use egui::{Context, Ui}; + +pub(super) fn update(_app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { + ui.label("YOU PAGE - Coming Soon".to_string()); +}