From f7021094bcbcf9239ab09afebb8666b6c045d046 Mon Sep 17 00:00:00 2001 From: kieran Date: Tue, 7 Jan 2025 14:13:41 +0000 Subject: [PATCH] wip --- Cargo.lock | 9 +++-- Cargo.toml | 6 +-- src/app.rs | 45 ++++++++++++++++------- src/lib.rs | 3 +- src/profiles.rs | 30 +++++++++++++++ src/route/home.rs | 9 +++-- src/route/mod.rs | 69 ++++++++++++++++++++++------------- src/route/stream.rs | 14 ++++--- src/services/ffmpeg_loader.rs | 7 +--- src/widgets/chat.rs | 9 +++-- src/widgets/chat_message.rs | 4 +- src/widgets/header.rs | 18 ++++----- src/widgets/stream_list.rs | 2 +- src/widgets/stream_tile.rs | 9 +---- src/widgets/stream_title.rs | 9 +---- src/widgets/write_chat.rs | 12 +----- 16 files changed, 155 insertions(+), 100 deletions(-) create mode 100644 src/profiles.rs diff --git a/Cargo.lock b/Cargo.lock index ccb5e92..8f5954f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1639,7 +1639,7 @@ checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" [[package]] name = "enostr" version = "0.1.0" -source = "git+https://git.v0l.io/nostr/notedeck.git?rev=e08e30f9125b9cf7391e97a2683ba0034bff1644#e08e30f9125b9cf7391e97a2683ba0034bff1644" +source = "git+https://github.com/damus-io/notedeck?rev=06417ff69e772f24ffd7fb2b025f879463d8c51f#06417ff69e772f24ffd7fb2b025f879463d8c51f" dependencies = [ "bech32", "ewebsock", @@ -3023,7 +3023,7 @@ dependencies = [ [[package]] name = "notedeck" version = "0.1.0" -source = "git+https://git.v0l.io/nostr/notedeck.git?rev=e08e30f9125b9cf7391e97a2683ba0034bff1644#e08e30f9125b9cf7391e97a2683ba0034bff1644" +source = "git+https://github.com/damus-io/notedeck?rev=06417ff69e772f24ffd7fb2b025f879463d8c51f#06417ff69e772f24ffd7fb2b025f879463d8c51f" dependencies = [ "base32", "dirs", @@ -3036,6 +3036,7 @@ dependencies = [ "security-framework", "serde", "serde_json", + "sha2", "strum", "strum_macros", "thiserror 2.0.9", @@ -3047,7 +3048,7 @@ dependencies = [ [[package]] name = "notedeck_chrome" version = "0.2.0" -source = "git+https://git.v0l.io/nostr/notedeck.git?rev=e08e30f9125b9cf7391e97a2683ba0034bff1644#e08e30f9125b9cf7391e97a2683ba0034bff1644" +source = "git+https://github.com/damus-io/notedeck?rev=06417ff69e772f24ffd7fb2b025f879463d8c51f#06417ff69e772f24ffd7fb2b025f879463d8c51f" dependencies = [ "android-activity 0.4.3", "eframe", @@ -3071,7 +3072,7 @@ dependencies = [ [[package]] name = "notedeck_columns" version = "0.2.0" -source = "git+https://git.v0l.io/nostr/notedeck.git?rev=e08e30f9125b9cf7391e97a2683ba0034bff1644#e08e30f9125b9cf7391e97a2683ba0034bff1644" +source = "git+https://github.com/damus-io/notedeck?rev=06417ff69e772f24ffd7fb2b025f879463d8c51f#06417ff69e772f24ffd7fb2b025f879463d8c51f" dependencies = [ "bitflags 2.6.0", "dirs", diff --git a/Cargo.toml b/Cargo.toml index 25b2e09..fe64dcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,9 +26,9 @@ egui-video = { git = "https://github.com/v0l/egui-video.git", rev = "d2ea3b4db21 # notedeck stuff nostr = { version = "0.37.0", default-features = false, features = ["std", "nip49"] } nostrdb = { git = "https://github.com/damus-io/nostrdb-rs", rev = "2111948b078b24a1659d0bd5d8570f370269c99b" } -notedeck-chrome = { git = "https://git.v0l.io/nostr/notedeck.git", rev = "e08e30f9125b9cf7391e97a2683ba0034bff1644", package = "notedeck_chrome", optional = true } -notedeck = { git = "https://git.v0l.io/nostr/notedeck.git", rev = "e08e30f9125b9cf7391e97a2683ba0034bff1644", package = "notedeck", optional = true } -enostr = { git = "https://git.v0l.io/nostr/notedeck.git", rev = "e08e30f9125b9cf7391e97a2683ba0034bff1644", package = "enostr", optional = true } +notedeck-chrome = { git = "https://github.com/damus-io/notedeck", rev = "06417ff69e772f24ffd7fb2b025f879463d8c51f", package = "notedeck_chrome", optional = true } +notedeck = { git = "https://github.com/damus-io/notedeck", rev = "06417ff69e772f24ffd7fb2b025f879463d8c51f", package = "notedeck", optional = true } +enostr = { git = "https://github.com/damus-io/notedeck", rev = "06417ff69e772f24ffd7fb2b025f879463d8c51f", package = "enostr", optional = true } poll-promise = "0.3.0" ehttp = "0.5.0" diff --git a/src/app.rs b/src/app.rs index 7aadd23..d2acae2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,14 +1,13 @@ -use crate::route::{page, RouteServices, RouteType}; +use crate::profiles::ProfileLoader; +use crate::route::{page, RouteAction, RouteServices, RouteType}; use crate::widgets::{Header, NostrWidget}; use eframe::epaint::{FontFamily, Margin}; use eframe::CreationContext; -use egui::{Color32, FontData, FontDefinitions, Ui}; -use enostr::ewebsock::{WsEvent, WsMessage}; +use egui::{Color32, FontData, FontDefinitions, Theme, Ui, Visuals}; use enostr::{PoolEvent, RelayEvent, RelayMessage}; use log::{error, info, warn}; -use nostrdb::Transaction; +use nostrdb::{Filter, Transaction}; use notedeck::AppContext; -use std::ops::Div; use std::sync::mpsc; pub struct ZapStreamApp { @@ -17,6 +16,7 @@ pub struct ZapStreamApp { routes_tx: mpsc::Sender, widget: Box, + profiles: ProfileLoader, } impl ZapStreamApp { @@ -34,6 +34,7 @@ impl ZapStreamApp { Self { current: RouteType::HomePage, widget: Box::new(page::HomePage::new()), + profiles: ProfileLoader::new(), routes_tx: tx, routes_rx: rx, } @@ -59,16 +60,26 @@ impl notedeck::App for ZapStreamApp { } } - let mut app_frame = egui::containers::Frame::default(); - let margin = self.frame_margin(); + // reset theme + ui.ctx().set_visuals_of( + Theme::Dark, + Visuals { + panel_fill: Color32::BLACK, + override_text_color: Some(Color32::WHITE), + ..Default::default() + }, + ); - app_frame.inner_margin = margin; - app_frame.stroke.color = Color32::BLACK; + let mut app_frame = egui::containers::Frame::default(); + app_frame.inner_margin = self.frame_margin(); // handle app state changes while let Ok(r) = self.routes_rx.try_recv() { if let RouteType::Action(a) = r { match a { + RouteAction::DemandProfile(p) => { + self.profiles.demand(p); + } _ => info!("Not implemented"), } } else { @@ -91,17 +102,16 @@ impl notedeck::App for ZapStreamApp { egui::CentralPanel::default() .frame(app_frame) .show(ui.ctx(), |ui| { - ui.visuals_mut().override_text_color = Some(Color32::WHITE); - + let tx = Transaction::new(ctx.ndb).expect("transaction"); // display app ui.vertical(|ui| { let mut svc = RouteServices { router: self.routes_tx.clone(), - tx: Transaction::new(ctx.ndb).expect("transaction"), + tx: &tx, egui: ui.ctx().clone(), ctx, }; - Header::new().render(ui, &mut svc); + Header::new().render(ui, &mut svc, &tx); if let Err(e) = self.widget.update(&mut svc) { error!("{}", e); } @@ -109,6 +119,15 @@ impl notedeck::App for ZapStreamApp { }) .response }); + + let profiles = self.profiles.next(); + if !profiles.is_empty() { + info!("Profiles: {:?}", profiles); + ctx.pool.subscribe( + "profiles".to_string(), + vec![Filter::new().kinds([0]).authors(&profiles).build()], + ); + } } } diff --git a/src/lib.rs b/src/lib.rs index 7ed988d..33314ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,14 +2,15 @@ mod android; pub mod app; mod link; +mod note_ref; mod note_util; mod note_view; +mod profiles; mod route; mod services; mod stream_info; mod theme; mod widgets; -mod note_ref; #[cfg(target_os = "android")] use android_activity::AndroidApp; diff --git a/src/profiles.rs b/src/profiles.rs new file mode 100644 index 0000000..1ac1d1a --- /dev/null +++ b/src/profiles.rs @@ -0,0 +1,30 @@ +use std::collections::HashSet; + +pub struct ProfileLoader { + queue: HashSet<[u8; 32]>, + fetched: HashSet<[u8; 32]>, +} + +impl ProfileLoader { + pub fn new() -> Self { + Self { + queue: HashSet::new(), + fetched: HashSet::new(), + } + } + + pub fn demand(&mut self, pubkey: [u8; 32]) { + if self.fetched.contains(&pubkey) { + return; + } + self.queue.insert(pubkey); + } + + pub fn next(&mut self) -> Vec<[u8; 32]> { + let ret: Vec<[u8; 32]> = self.queue.drain().collect(); + for p in ret.iter() { + self.fetched.insert(*p); + } + ret + } +} diff --git a/src/route/home.rs b/src/route/home.rs index ac50f68..f0a54f7 100644 --- a/src/route/home.rs +++ b/src/route/home.rs @@ -37,7 +37,8 @@ impl NostrWidget for HomePage { .collect(); let events_live = NotesView::from_vec( - events.iter() + events + .iter() .filter(|r| matches!(r.status(), StreamStatus::Live)) .collect(), ); @@ -50,7 +51,8 @@ impl NostrWidget for HomePage { .render(ui, services); } let events_planned = NotesView::from_vec( - events.iter() + events + .iter() .filter(|r| matches!(r.status(), StreamStatus::Planned)) .collect(), ); @@ -63,7 +65,8 @@ impl NostrWidget for HomePage { .render(ui, services); } let events_ended = NotesView::from_vec( - events.iter() + events + .iter() .filter(|r| matches!(r.status(), StreamStatus::Ended)) .collect(), ); diff --git a/src/route/mod.rs b/src/route/mod.rs index 9e4cb73..b5bf4c9 100644 --- a/src/route/mod.rs +++ b/src/route/mod.rs @@ -1,21 +1,18 @@ use crate::link::NostrLink; -use crate::route::home::HomePage; -use crate::route::login::LoginPage; -use crate::route::stream::StreamPage; use crate::services::ffmpeg_loader::FfmpegLoader; -use crate::widgets::{Header, NostrWidget, PlaceholderRect}; -use anyhow::{bail, Result}; -use egui::{Context, Image, Response, TextureHandle, Ui}; -use egui_inbox::{RequestRepaintTrait, UiInbox, UiInboxSender}; -use enostr::{EventClientMessage, Note}; +use egui::load::SizedTexture; +use egui::{Context, Image, TextureHandle}; +use egui_inbox::RequestRepaintTrait; +use enostr::EventClientMessage; use itertools::Itertools; use log::{info, warn}; -use nostr::{ClientMessage, Event, EventBuilder, JsonUtil, Kind, Tag}; -use nostrdb::{Ndb, NdbProfile, NoteKey, Transaction}; +use nostr::{Event, EventBuilder, JsonUtil, Kind, Tag}; +use nostrdb::{NdbProfile, NoteKey, Transaction}; use notedeck::{AppContext, ImageCache}; use poll_promise::Promise; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::sync::mpsc; +use std::task::Poll; mod home; mod login; @@ -46,12 +43,14 @@ pub enum RouteType { } #[derive(PartialEq)] -pub enum RouteAction {} +pub enum RouteAction { + DemandProfile([u8; 32]), +} pub struct RouteServices<'a, 'ctx> { pub router: mpsc::Sender, - pub tx: Transaction, pub egui: Context, + pub tx: &'a Transaction, pub ctx: &'a mut AppContext<'ctx>, } @@ -82,8 +81,17 @@ impl<'a, 'ctx> RouteServices<'a, 'ctx> { /// Load/Fetch profiles pub fn profile(&self, pk: &[u8; 32]) -> Option> { - // TODO - None + let p = self + .ctx + .ndb + .get_profile_by_pubkey(self.tx, pk) + .map(|p| p.record().profile()) + .ok() + .flatten(); + if p.is_none() { + self.action(RouteAction::DemandProfile(pk.clone())); + } + p } /// Load image from URL @@ -116,14 +124,18 @@ impl<'a, 'ctx> RouteServices<'a, 'ctx> { None } } - +const BLACK_PIXEL: [u8; 4] = [0, 0, 0, 0]; pub fn image_from_cache<'a>(img_cache: &mut ImageCache, ctx: &Context, url: &str) -> Image<'a> { - let m_cached_promise = img_cache.map().get(url); - if m_cached_promise.is_none() { + if let Some(promise) = img_cache.map().get(url) { + match promise.poll() { + Poll::Ready(Ok(t)) => Image::new(SizedTexture::from_handle(t)), + _ => Image::from_bytes(url.to_string(), &BLACK_PIXEL), + } + } else { let fetch = fetch_img(img_cache, ctx, url); img_cache.map_mut().insert(url.to_string(), fetch); + Image::from_bytes(url.to_string(), &BLACK_PIXEL) } - Image::new(url.to_string()) } fn fetch_img( @@ -137,7 +149,8 @@ fn fetch_img( let ctx = ctx.clone(); let url = url.to_owned(); let dst_path = dst_path.clone(); - Promise::spawn_async(async move { + Promise::spawn_blocking(move || { + info!("Loading image from disk: {}", dst_path.display()); match FfmpegLoader::new().load_image(dst_path) { Ok(img) => Ok(ctx.load_texture(&url, img, Default::default())), Err(e) => Err(notedeck::Error::Generic(e.to_string())), @@ -159,12 +172,18 @@ fn fetch_img_from_net( let cloned_url = url.to_owned(); let cache_path = cache_path.to_owned(); ehttp::fetch(request, move |response| { - let handle = response.map_err(notedeck::Error::Generic).map(|img| { - std::fs::write(&cache_path, &img.bytes).unwrap(); - let img_loaded = FfmpegLoader::new().load_image(cache_path).unwrap(); + let handle = response + .and_then(|img| { + std::fs::create_dir_all(cache_path.parent().unwrap()).unwrap(); + std::fs::write(&cache_path, &img.bytes).unwrap(); + info!("Loading image from net: {}", cloned_url); + let img_loaded = FfmpegLoader::new() + .load_image(cache_path) + .map_err(|e| e.to_string())?; - ctx.load_texture(&cloned_url, img_loaded, Default::default()) - }); + Ok(ctx.load_texture(&cloned_url, img_loaded, Default::default())) + }) + .map_err(notedeck::Error::Generic); sender.send(handle); ctx.request_repaint(); diff --git a/src/route/stream.rs b/src/route/stream.rs index 5abd3bf..9febb9e 100644 --- a/src/route/stream.rs +++ b/src/route/stream.rs @@ -6,7 +6,7 @@ use crate::widgets::{ sub_or_poll, Chat, NostrWidget, PlaceholderRect, StreamPlayer, StreamTitle, WriteChat, }; use egui::{vec2, Align, Frame, Layout, Response, Stroke, Ui, Vec2, Widget}; -use nostrdb::{Filter, Note, NoteKey, Subscription}; +use nostrdb::{Filter, Note, Subscription}; use crate::note_ref::NoteRef; use std::borrow::Borrow; @@ -14,7 +14,6 @@ use std::collections::HashSet; pub struct StreamPage { link: NostrLink, - event: Option, player: Option, chat: Option, new_msg: WriteChat, @@ -28,7 +27,6 @@ impl StreamPage { Self { new_msg: WriteChat::new(link.clone()), link, - event: None, chat: None, player: None, events: HashSet::new(), @@ -146,7 +144,11 @@ impl StreamPage { impl NostrWidget for StreamPage { fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_, '_>) -> Response { - let events: Vec = vec![]; + let events: Vec = self + .events + .iter() + .map_while(|e| services.ctx.ndb.get_note_by_key(services.tx, e.key).ok()) + .collect(); if let Some(event) = events.first() { if let Some(stream) = event.stream() { @@ -173,14 +175,14 @@ impl NostrWidget for StreamPage { } fn update(&mut self, services: &mut RouteServices<'_, '_>) -> anyhow::Result<()> { - let filt = self.get_filters(); + let filters = self.get_filters(); sub_or_poll( services.ctx.ndb, &services.tx, &mut services.ctx.pool, &mut self.events, &mut self.sub, - filt, + filters, )?; if let Some(c) = self.chat.as_mut() { c.update(services)?; diff --git a/src/services/ffmpeg_loader.rs b/src/services/ffmpeg_loader.rs index d2f2533..2e49384 100644 --- a/src/services/ffmpeg_loader.rs +++ b/src/services/ffmpeg_loader.rs @@ -17,11 +17,7 @@ impl FfmpegLoader { Self::load_image_from_demuxer(demux) } - pub fn load_image_bytes( - &self, - key: &str, - data: &'static [u8], - ) -> Result { + pub fn load_image_bytes(&self, key: &str, data: &'static [u8]) -> Result { let demux = Demuxer::new_custom_io(data, Some(key.to_string()))?; Self::load_image_from_demuxer(demux) } @@ -57,6 +53,7 @@ impl FfmpegLoader { av_frame_free(&mut frame); let image = video_frame_to_image(frame_rgb); + av_packet_free(&mut pkt); return Ok(image); } } diff --git a/src/widgets/chat.rs b/src/widgets/chat.rs index 837ede9..4df3e13 100644 --- a/src/widgets/chat.rs +++ b/src/widgets/chat.rs @@ -38,7 +38,7 @@ impl NostrWidget for Chat { let stream = services .ctx .ndb - .get_note_by_key(&services.tx, self.stream) + .get_note_by_key(services.tx, self.stream) .unwrap(); ScrollArea::vertical() @@ -55,9 +55,10 @@ impl NostrWidget for Chat { .sorted_by(|a, b| a.created_at.cmp(&b.created_at)) { if let Ok(ev) = - services.ctx.ndb.get_note_by_key(&services.tx, ev.key) + services.ctx.ndb.get_note_by_key(services.tx, ev.key) { - ChatMessage::new(&stream, &ev, &None) + let profile = services.profile(ev.pubkey()); + ChatMessage::new(&stream, &ev, &profile) .render(ui, services.ctx.img_cache); } } @@ -72,7 +73,7 @@ impl NostrWidget for Chat { let filters = vec![self.get_filter()]; sub_or_poll( services.ctx.ndb, - &services.tx, + services.tx, &mut services.ctx.pool, &mut self.events, &mut self.sub, diff --git a/src/widgets/chat_message.rs b/src/widgets/chat_message.rs index 2478a26..c3f0c7c 100644 --- a/src/widgets/chat_message.rs +++ b/src/widgets/chat_message.rs @@ -33,7 +33,9 @@ impl<'a> ChatMessage<'a> { job.wrap.break_anywhere = true; let is_host = self.stream.host().eq(self.ev.pubkey()); - let name = self.profile.map_or("Nostrich", |f| f.name().map_or("Nostrich", |f| f)); + let name = self + .profile + .map_or("Nostrich", |f| f.name().map_or("Nostrich", |f| f)); let name_color = if is_host { PRIMARY } else { NEUTRAL_500 }; diff --git a/src/widgets/header.rs b/src/widgets/header.rs index a2e9329..f998552 100644 --- a/src/widgets/header.rs +++ b/src/widgets/header.rs @@ -4,6 +4,7 @@ use crate::widgets::{Button, NostrWidget}; use eframe::emath::Align; use eframe::epaint::Vec2; use egui::{CursorIcon, Frame, Layout, Margin, Response, Sense, Ui, Widget}; +use nostrdb::Transaction; pub struct Header; @@ -11,10 +12,12 @@ impl Header { pub fn new() -> Self { Self {} } -} - -impl NostrWidget for Header { - fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_, '_>) -> Response { + pub fn render( + &mut self, + ui: &mut Ui, + services: &mut RouteServices<'_, '_>, + tx: &Transaction, + ) -> Response { let logo_bytes = include_bytes!("../resources/logo.svg"); Frame::none() .outer_margin(Margin::symmetric(16., 8.)) @@ -37,7 +40,8 @@ impl NostrWidget for Header { ui.with_layout(Layout::right_to_left(Align::Center), |ui| { if let Some(acc) = services.ctx.accounts.get_selected_account() { - Avatar::pubkey(&acc.pubkey, services.ctx.ndb, &services.tx).render(ui, services.ctx.img_cache); + Avatar::pubkey(&acc.pubkey, services.ctx.ndb, tx) + .render(ui, services.ctx.img_cache); } else if Button::new().show(ui, |ui| ui.label("Login")).clicked() { services.navigate(RouteType::LoginPage); } @@ -47,8 +51,4 @@ impl NostrWidget for Header { }) .response } - - fn update(&mut self, _services: &mut RouteServices<'_, '_>) -> anyhow::Result<()> { - Ok(()) - } } diff --git a/src/widgets/stream_list.rs b/src/widgets/stream_list.rs index add83cf..f36fb9b 100644 --- a/src/widgets/stream_list.rs +++ b/src/widgets/stream_list.rs @@ -66,4 +66,4 @@ impl<'a> StreamList<'a> { }) .response } -} \ No newline at end of file +} diff --git a/src/widgets/stream_tile.rs b/src/widgets/stream_tile.rs index 0428746..18d1c24 100644 --- a/src/widgets/stream_tile.rs +++ b/src/widgets/stream_tile.rs @@ -21,9 +21,8 @@ impl<'a> StreamEvent<'a> { pub fn new(event: &'a Note<'a>) -> Self { Self { event } } -} -impl NostrWidget for StreamEvent<'_> { - fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_, '_>) -> Response { + + pub fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_, '_>) -> Response { ui.vertical(|ui| { ui.style_mut().spacing.item_spacing = Vec2::new(12., 16.); @@ -127,8 +126,4 @@ impl NostrWidget for StreamEvent<'_> { }) .response } - - fn update(&mut self, _services: &mut RouteServices<'_, '_>) -> anyhow::Result<()> { - Ok(()) - } } diff --git a/src/widgets/stream_title.rs b/src/widgets/stream_title.rs index 6f79984..fd17346 100644 --- a/src/widgets/stream_title.rs +++ b/src/widgets/stream_title.rs @@ -13,10 +13,7 @@ impl<'a> StreamTitle<'a> { pub fn new(event: &'a Note<'a>) -> StreamTitle<'a> { StreamTitle { event } } -} - -impl NostrWidget for StreamTitle<'_> { - fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_, '_>) -> Response { + pub fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_, '_>) -> Response { Frame::none() .outer_margin(Margin::symmetric(12., 8.)) .show(ui, |ui| { @@ -43,8 +40,4 @@ impl NostrWidget for StreamTitle<'_> { }) .response } - - fn update(&mut self, _services: &mut RouteServices<'_, '_>) -> anyhow::Result<()> { - Ok(()) - } } diff --git a/src/widgets/write_chat.rs b/src/widgets/write_chat.rs index 139b2e6..e5c0240 100644 --- a/src/widgets/write_chat.rs +++ b/src/widgets/write_chat.rs @@ -1,12 +1,10 @@ use crate::link::NostrLink; use crate::route::RouteServices; use crate::theme::{MARGIN_DEFAULT, NEUTRAL_900, ROUNDING_DEFAULT}; -use crate::widgets::{NativeTextInput, NostrWidget}; +use crate::widgets::NativeTextInput; use eframe::emath::Align; use egui::{Frame, Layout, Response, Sense, Ui, Widget}; use log::info; -use nostrdb::Filter; -use notedeck::AppContext; pub struct WriteChat { link: NostrLink, @@ -20,10 +18,8 @@ impl WriteChat { msg: String::new(), } } -} -impl NostrWidget for WriteChat { - fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_, '_>) -> Response { + pub fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_, '_>) -> Response { let logo_bytes = include_bytes!("../resources/send-03.svg"); Frame::none() .inner_margin(MARGIN_DEFAULT) @@ -52,8 +48,4 @@ impl NostrWidget for WriteChat { }) .response } - - fn update(&mut self, _services: &mut RouteServices<'_, '_>) -> anyhow::Result<()> { - Ok(()) - } }