From 7aa14cc37ca1304704f8383dd83bb5874e42f493 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Wed, 21 Dec 2022 15:49:58 +1300 Subject: [PATCH] UI work - style, about page --- src/about.rs | 7 +- src/ui/about.rs | 73 ++++++++++++- src/ui/mod.rs | 54 ++++++---- src/ui/style.rs | 271 ++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 344 insertions(+), 61 deletions(-) diff --git a/src/about.rs b/src/about.rs index 6c0a9127..f5dfdb60 100644 --- a/src/about.rs +++ b/src/about.rs @@ -7,7 +7,7 @@ pub struct About { pub repository: String, pub homepage: String, pub license: String, - pub database_path: String, + pub storage_path: String, } #[allow(dead_code)] @@ -15,8 +15,7 @@ pub fn about() -> About { let data_dir = match dirs::data_dir() { Some(mut d) => { d.push("gossip"); - d.push("gossip.sqlite"); - format!("{}", d.display()) + format!("{}/", d.display()) } None => "Cannot find a directory to store application data.".to_owned(), }; @@ -29,6 +28,6 @@ pub fn about() -> About { repository: env!("CARGO_PKG_REPOSITORY").to_string(), homepage: env!("CARGO_PKG_HOMEPAGE").to_string(), license: env!("CARGO_PKG_LICENSE").to_string(), - database_path: data_dir, + storage_path: data_dir, } } diff --git a/src/ui/about.rs b/src/ui/about.rs index 380bbc28..1db918c4 100644 --- a/src/ui/about.rs +++ b/src/ui/about.rs @@ -1,7 +1,74 @@ use super::GossipUi; use eframe::egui; -use egui::{Context, Ui}; +use egui::{Align, Context, FontFamily, Layout, RichText, TextStyle, Ui, vec2}; + +pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { + + ui.with_layout(Layout::top_down(Align::Center), |ui| { + + ui.add_space(30.0); + + ui.image(&app.icon, app.icon.size_vec2()); + + ui.add_space(15.0); + + ui.label( + RichText::new(&app.about.name) + .text_style(TextStyle::Name("Bold".into())) + ); + + ui.add_space(15.0); + + ui.label( + RichText::new(&app.about.version) + .text_style(TextStyle::Body) + ); + + ui.add_space(15.0); + + ui.label( + RichText::new(&app.about.description) + .text_style(TextStyle::Body) + ); + + ui.add_space(35.0); + + ui.label( + RichText::new(&format!("nostr is a protocol and specification for storing and retrieving social media events onto servers called relays. Many users store their events onto multiple relays for reliability, censorship resistance, and to spread their reach. If you didn't store an event on a particular relay, don't expect anyone to find it there because relays normally don't share events with each other. + +Users are defined by their keypair, and are known by the public key of that pair. All events they generate are signed by their private key, and verifiable by their public key. + +We are storing data on your system in this file: {}. This data is only used locally by this client - the nostr protocol does not use clients as a store of data for other people. We are storing your settings, your private and public key, information about relays, and a cache of events. We cache events in your feed so that we don't have to ask relays for them again, which means less network traffic and faster startup times. +", app.about.storage_path)) + .text_style(TextStyle::Body) + ); + + ui.add_space(22.0); + + ui.hyperlink_to("Learn More about Nostr", "https://github.com/nostr-protocol/nostr"); + + ui.add_space(30.0); + + ui.hyperlink_to("Source Code", &app.about.homepage); + ui.label( + RichText::new("by") + .text_style(TextStyle::Small) + ); + ui.label( + RichText::new(&app.about.authors) + .text_style(TextStyle::Small) + ); + + ui.add_space(15.0); + + ui.label( + RichText::new("This program comes with absolutely no warranty.") + .text_style(TextStyle::Small) + ); + ui.label( + RichText::new("See the MIT License for details.") + .text_style(TextStyle::Small) + ); + }); -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/mod.rs b/src/ui/mod.rs index 421f1457..24a3cefb 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -8,8 +8,9 @@ mod style; mod you; use crate::error::Error; +use crate::about::About; use eframe::{egui, IconData, Theme}; -use egui::Context; +use egui::{ColorImage, Context, ImageData, TextureHandle, TextureOptions}; pub fn run() -> Result<(), Error> { let icon_bytes = include_bytes!("../../gossip.png"); @@ -53,17 +54,42 @@ enum Page { struct GossipUi { page: Page, - initial_dark_mode_set: bool, - fonts_installed: bool, - + about: About, + icon: TextureHandle } impl GossipUi { - fn new(_cc: &eframe::CreationContext<'_>) -> Self { + fn new(cctx: &eframe::CreationContext<'_>) -> Self { + if cctx.egui_ctx.style().visuals.dark_mode { + cctx.egui_ctx.set_visuals(style::dark_mode_visuals()); + } else { + cctx.egui_ctx.set_visuals(style::light_mode_visuals()); + }; + + cctx.egui_ctx.set_fonts(style::font_definitions()); + + let mut style: egui::Style = (*cctx.egui_ctx.style()).clone(); + style.text_styles = style::text_styles(); + cctx.egui_ctx.set_style(style); + + let icon_bytes = include_bytes!("../../gossip.png"); + let image = image::load_from_memory(icon_bytes).unwrap(); + let size = [image.width() as _, image.height() as _]; + let image_buffer = image.to_rgba8(); + let pixels = image_buffer.as_flat_samples(); + let icon_texture_handle = cctx.egui_ctx.load_texture( + "icon", + ImageData::Color(ColorImage::from_rgba_unmultiplied( + size, + pixels.as_slice(), + )), + TextureOptions::default() // magnification, minification + ); + GossipUi { page: Page::Feed, - initial_dark_mode_set: false, - fonts_installed: false, + about: crate::about::about(), + icon: icon_texture_handle, } } } @@ -72,20 +98,6 @@ impl eframe::App for GossipUi { 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| { ui.selectable_value(&mut self.page, Page::Feed, "Feed"); diff --git a/src/ui/style.rs b/src/ui/style.rs index 9f5ee01e..34a50b8a 100644 --- a/src/ui/style.rs +++ b/src/ui/style.rs @@ -1,6 +1,6 @@ use eframe::{egui, epaint}; use egui::style::{Selection, Visuals, Widgets}; -use egui::{Color32, FontData, FontDefinitions, FontFamily, FontTweak, Rounding, Stroke}; +use egui::{Color32, FontData, FontDefinitions, FontFamily, FontId, FontTweak, Rounding, Stroke, TextStyle}; use epaint::Shadow; use std::collections::BTreeMap; @@ -64,28 +64,78 @@ pub(super) fn light_mode_visuals() -> Visuals { } } +pub(super) fn text_styles() -> BTreeMap { + let mut text_styles: BTreeMap = BTreeMap::new(); + + text_styles.insert(TextStyle::Small, FontId { + size: 12.0, + family: FontFamily::Proportional, + }); + + text_styles.insert(TextStyle::Body, FontId { + size: 14.0, + family: FontFamily::Proportional, + }); + + text_styles.insert(TextStyle::Monospace, FontId { + size: 14.0, + family: FontFamily::Monospace, + }); + + text_styles.insert(TextStyle::Button, FontId { + size: 15.0, + family: FontFamily::Proportional, + }); + + text_styles.insert(TextStyle::Heading, FontId { + size: 16.0, + family: FontFamily::Name("BoldOblique".into()), + }); + + text_styles.insert(TextStyle::Name("Bold".into()), FontId { + size: 14.0, + family: FontFamily::Name("Bold".into()), + }); + + text_styles.insert(TextStyle::Name("MonoBold".into()), FontId { + size: 14.0, + family: FontFamily::Name("MonoBold".into()), + }); + + text_styles.insert(TextStyle::Name("MonoOblique".into()), FontId { + size: 14.0, + family: FontFamily::Name("MonoOblique".into()), + }); + + text_styles.insert(TextStyle::Name("MonoBoldOblique".into()), FontId { + size: 14.0, + family: FontFamily::Name("MonoBoldOblique".into()), + }); + + text_styles +} + +/* + * We configure their font families + * Proportional + * Monospace + * We define the following Font Families: + * Bold, + * Oblique, + * BoldOblique + * MonoBold, + * MonoOblique + * MonoBoldOblique + */ 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: + // Good Looking Emojis font_data.insert( "NotoColorEmoji".to_owned(), - FontData::from_static(include_bytes!("../../fonts/NotoColorEmoji.ttf")).tweak( + FontData::from_static(include_bytes!("../../fonts/noto/NotoColorEmoji.ttf")).tweak( FontTweak { scale: 0.81, // make it smaller y_offset_factor: -0.2, // move it up @@ -94,36 +144,191 @@ pub(super) fn font_definitions() -> FontDefinitions { ), ); + // Proportional Regular + + font_data.insert( + "DejaVuSansRegular".to_owned(), + FontData::from_static(include_bytes!("../../fonts/DejaVuSans/DejaVuSans.ttf")), + ); + 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(), - ], + FontData::from_static(include_bytes!("../../fonts/noto/NotoSans-Regular.ttf")), ); families.insert( FontFamily::Proportional, vec![ - "FreeSans".to_owned(), + "DejaVuSansRegular".to_owned(), "NotoColorEmoji".to_owned(), "NotoSansRegular".to_owned(), ], ); + // Proportional Bold + + font_data.insert( + "DejaVuSansBold".to_owned(), + FontData::from_static(include_bytes!("../../fonts/DejaVuSans/DejaVuSans-Bold.ttf")), + ); + + font_data.insert( + "NotoSansBold".to_owned(), + FontData::from_static(include_bytes!("../../fonts/noto/NotoSans-Bold.ttf")), + ); + + families.insert( + FontFamily::Name("Bold".into()), + vec![ + "DejaVuSansBold".to_owned(), + "NotoColorEmoji".to_owned(), + "NotoSansBold".to_owned(), + ], + ); + + // Proportional Oblique + + font_data.insert( + "DejaVuSansOblique".to_owned(), + FontData::from_static(include_bytes!("../../fonts/DejaVuSans/DejaVuSans-Oblique.ttf")), + ); + + font_data.insert( + "NotoSansOblique".to_owned(), + FontData::from_static(include_bytes!("../../fonts/noto/NotoSans-Italic.ttf")), + ); + + families.insert( + FontFamily::Name("Oblique".into()), + vec![ + "DejaVuSansOblique".to_owned(), + "NotoColorEmoji".to_owned(), + "NotoSansOblique".to_owned(), + ], + ); + + // Proportional Bold Oblique + + font_data.insert( + "DejaVuSansBoldOblique".to_owned(), + FontData::from_static(include_bytes!("../../fonts/DejaVuSans/DejaVuSans-BoldOblique.ttf")), + ); + + font_data.insert( + "NotoSansBoldOblique".to_owned(), + FontData::from_static(include_bytes!("../../fonts/noto/NotoSans-BoldItalic.ttf")), + ); + + families.insert( + FontFamily::Name("BoldOblique".into()), + vec![ + "DejaVuSansBoldOblique".to_owned(), + "NotoColorEmoji".to_owned(), + "NotoSansBoldOblique".to_owned(), + ], + ); + + // Monospace Regular + + font_data.insert( + "InconsolataRegular".to_owned(), + FontData::from_static(include_bytes!("../../fonts/inconsolata/Inconsolata-SemiCondensedLight.ttf")).tweak( + FontTweak { + scale: 1.1, // Make it bigger. Inconsolata is smaller than DejaVu. + y_offset_factor: 0.0, + y_offset: 0.0, + }, + ), + ); + + font_data.insert( + "DejaVuSansMonoRegular".to_owned(), + FontData::from_static(include_bytes!("../../fonts/DejaVuSans/DejaVuSansMono.ttf")), + ); + + font_data.insert( + "NotoSansMonoRegular".to_owned(), + FontData::from_static(include_bytes!("../../fonts/noto/NotoSansMono-Regular.ttf")), + ); + + families.insert( + FontFamily::Monospace, + vec![ + "InconsolataRegular".to_owned(), + "DejaVuSansMonoRegular".to_owned(), + "NotoColorEmoji".to_owned(), + "NotoSansMonoRegular".to_owned(), + ], + ); + + // Monospace Bold + + font_data.insert( + "InconsolataBold".to_owned(), + FontData::from_static(include_bytes!("../../fonts/inconsolata/Inconsolata-SemiCondensedSemiBold.ttf")).tweak( + FontTweak { + scale: 1.1, // Make it bigger. Inconsolata is smaller than DejaVu. + y_offset_factor: 0.0, + y_offset: 0.0, + }, + ), + ); + + font_data.insert( + "DejaVuSansMonoBold".to_owned(), + FontData::from_static(include_bytes!("../../fonts/DejaVuSans/DejaVuSansMono-Bold.ttf")), + ); + + font_data.insert( + "NotoSansMonoBold".to_owned(), + FontData::from_static(include_bytes!("../../fonts/noto/NotoSansMono-Bold.ttf")), + ); + + families.insert( + FontFamily::Name("MonoBold".into()), + vec![ + "InconsolataBold".to_owned(), + "DejaVuSansMonoBold".to_owned(), + "NotoColorEmoji".to_owned(), + "NotoSansMonoBold".to_owned(), + ], + ); + + // Monospace Oblique + + font_data.insert( + "DejaVuSansMonoOblique".to_owned(), + FontData::from_static(include_bytes!("../../fonts/DejaVuSans/DejaVuSansMono-Oblique.ttf")), + ); + + families.insert( + FontFamily::Name("MonoOblique".into()), + vec![ + "DejaVuSansMonoOblique".to_owned(), + "NotoColorEmoji".to_owned(), + "NotoSansMonoRegular".to_owned(), // they don't have an oblique + ], + ); + + // Monospace Bold Oblique + + font_data.insert( + "DejaVuSansMonoBoldOblique".to_owned(), + FontData::from_static(include_bytes!("../../fonts/DejaVuSans/DejaVuSansMono-BoldOblique.ttf")), + ); + + families.insert( + FontFamily::Name("MonoBoldOblique".into()), + vec![ + "DejaVuSansMonoBoldOblique".to_owned(), + "NotoColorEmoji".to_owned(), + "NotoSansMonoBold".to_owned(), // they don't have a bold oblique + ], + ); + FontDefinitions { font_data, families, } } +