diff --git a/src/login.rs b/src/login.rs index d0b41c7..2f9b9d8 100644 --- a/src/login.rs +++ b/src/login.rs @@ -77,6 +77,9 @@ impl Login { } pub fn write_live_chat_msg(&self, link: &NostrLink, msg: &str) -> Result { + if msg.len() == 0 { + return Err(anyhow::anyhow!("Empty message")); + } let secret = self.secret_key()?; EventBuilder::new(Kind::LiveEventMessage, msg, [Tag::parse(&link.to_tag())?]) .to_event(&secret) diff --git a/src/route/stream.rs b/src/route/stream.rs index dd960f2..113d8f7 100644 --- a/src/route/stream.rs +++ b/src/route/stream.rs @@ -3,8 +3,9 @@ use crate::note_util::OwnedNote; use crate::route::RouteServices; use crate::services::ndb_wrapper::{NDBWrapper, SubWrapper}; use crate::stream_info::StreamInfo; +use crate::theme::{MARGIN_DEFAULT, NEUTRAL_800, ROUNDING_DEFAULT}; use crate::widgets::{Chat, NostrWidget, StreamPlayer, StreamTitle, WriteChat}; -use egui::{vec2, Response, Ui, Vec2, Widget}; +use egui::{vec2, Align, Frame, Layout, Response, Stroke, Ui, Vec2, Widget}; use nostrdb::{Filter, Note, NoteKey, Transaction}; use std::borrow::Borrow; @@ -37,31 +38,37 @@ impl StreamPage { ui: &mut Ui, services: &mut RouteServices<'_>, ) -> Response { - if let Some(player) = &mut self.player { - player.ui(ui); - } - StreamTitle::new(&event).render(ui, services); - let chat_h = 60.0; let w = ui.available_width(); let h = ui .available_height() - .max(ui.available_rect_before_wrap().height()) - .max(chat_h); - ui.allocate_ui(Vec2::new(w, h - chat_h), |ui| { - if let Some(c) = self.chat.as_mut() { - c.render(ui, services); - } else { - ui.label("Loading.."); - } - // consume rest of space - if ui.available_height().is_finite() { - ui.add_space(ui.available_height()); - } - }); - ui.allocate_ui(vec2(w, chat_h), |ui| { - self.new_msg.render(ui, services); - }); + .max(ui.available_rect_before_wrap().height()); + ui.allocate_ui_with_layout( + Vec2::new(w, h), + Layout::top_down_justified(Align::Min), + |ui| { + if let Some(player) = &mut self.player { + let video_h = + ((ui.available_width() / 16.0) * 9.0).min(ui.available_height() * 0.33); + ui.allocate_ui(vec2(ui.available_width(), video_h), |ui| player.ui(ui)); + } + StreamTitle::new(&event).render(ui, services); + + if let Some(c) = self.chat.as_mut() { + ui.allocate_ui( + vec2(ui.available_width(), ui.available_height() - chat_h), + |ui| c.render(ui, services), + ); + } else { + ui.label("Loading.."); + } + // consume rest of space + if ui.available_height().is_finite() { + ui.add_space(ui.available_height() - chat_h); + } + self.new_msg.render(ui, services); + }, + ); ui.response() } @@ -76,33 +83,45 @@ impl StreamPage { let video_width = ui.available_width() - chat_w; let video_height = max_h.min((video_width / 16.0) * 9.0); - ui.horizontal_top(|ui| { - ui.vertical(|ui| { - if let Some(player) = &mut self.player { - ui.allocate_ui(vec2(video_width, video_height), |ui| player.ui(ui)); - } - ui.add_space(10.); - StreamTitle::new(&event).render(ui, services); - }); - ui.allocate_ui(vec2(chat_w, max_h), |ui| { + ui.with_layout( + Layout::left_to_right(Align::TOP).with_main_justify(true), + |ui| { ui.vertical(|ui| { - let chat_h = 60.0; - if let Some(c) = self.chat.as_mut() { - ui.allocate_ui(vec2(chat_w, max_h - chat_h), |ui| { - c.render(ui, services); - if ui.available_height().is_finite() { - ui.add_space(ui.available_height() - chat_h); - } - }); - } else { - ui.label("Loading.."); + if let Some(player) = &mut self.player { + ui.allocate_ui(vec2(video_width, video_height), |ui| player.ui(ui)); } - ui.allocate_ui(vec2(chat_w, chat_h), |ui| { - self.new_msg.render(ui, services); - }); - }) - }); - }); + ui.add_space(10.); + StreamTitle::new(&event).render(ui, services); + }); + ui.allocate_ui_with_layout( + vec2(chat_w, max_h), + Layout::top_down_justified(Align::Min), + |ui| { + Frame::none() + .stroke(Stroke::new(1.0, NEUTRAL_800)) + .outer_margin(MARGIN_DEFAULT) + .rounding(ROUNDING_DEFAULT) + .show(ui, |ui| { + let chat_h = 60.0; + if let Some(c) = self.chat.as_mut() { + ui.allocate_ui( + vec2(ui.available_width(), ui.available_height() - chat_h), + |ui| { + c.render(ui, services); + }, + ); + } else { + ui.label("Loading.."); + } + if ui.available_height().is_finite() { + ui.add_space(ui.available_height() - chat_h); + } + self.new_msg.render(ui, services); + }); + }, + ); + }, + ); ui.response() } diff --git a/src/services/image_cache.rs b/src/services/image_cache.rs index a14fc3c..c6fcf4b 100644 --- a/src/services/image_cache.rs +++ b/src/services/image_cache.rs @@ -41,7 +41,7 @@ impl ImageCache { ctx, dir: out, placeholder, - cache: Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(100).unwrap()))), + cache: Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(1000).unwrap()))), fetch_cache: Arc::new(Mutex::new(HashSet::new())), } } diff --git a/src/widgets/stream_player.rs b/src/widgets/stream_player.rs index eff4146..777ad68 100644 --- a/src/widgets/stream_player.rs +++ b/src/widgets/stream_player.rs @@ -17,9 +17,7 @@ impl StreamPlayer { impl Widget for &mut StreamPlayer { fn ui(self, ui: &mut Ui) -> Response { - let w = ui.available_width(); - let h = w / 16. * 9.; - let size = Vec2::new(w, h); + let size = ui.available_size(); if let Some(p) = self.player.as_mut() { ui.add_sized(size, p) diff --git a/src/widgets/stream_title.rs b/src/widgets/stream_title.rs index d8191f3..150f6da 100644 --- a/src/widgets/stream_title.rs +++ b/src/widgets/stream_title.rs @@ -33,8 +33,10 @@ impl<'a> NostrWidget for StreamTitle<'a> { .get_tag_value("summary") .and_then(|r| r.variant().str()) { - let summary = RichText::new(summary).color(Color32::WHITE); - ui.add(Label::new(summary).wrap_mode(TextWrapMode::Truncate)); + if summary.len() > 0 { + let summary = RichText::new(summary).color(Color32::WHITE); + ui.add(Label::new(summary).wrap_mode(TextWrapMode::Truncate)); + } } }) .response diff --git a/src/widgets/text_input.rs b/src/widgets/text_input.rs index 4ac87c7..d818f7f 100644 --- a/src/widgets/text_input.rs +++ b/src/widgets/text_input.rs @@ -1,5 +1,5 @@ use crate::route::{RouteAction, RouteServices}; -use crate::theme::{MARGIN_DEFAULT, NEUTRAL_500, NEUTRAL_800, ROUNDING_DEFAULT}; +use crate::theme::{MARGIN_DEFAULT, NEUTRAL_500, NEUTRAL_900, ROUNDING_DEFAULT}; use crate::widgets::NostrWidget; use egui::{Frame, Response, TextEdit, Ui}; @@ -7,6 +7,7 @@ use egui::{Frame, Response, TextEdit, Ui}; pub struct NativeTextInput<'a> { pub text: &'a mut String, hint_text: Option<&'a str>, + frame: bool, } impl<'a> NativeTextInput<'a> { @@ -14,6 +15,7 @@ impl<'a> NativeTextInput<'a> { Self { text, hint_text: None, + frame: false, } } @@ -21,20 +23,31 @@ impl<'a> NativeTextInput<'a> { self.hint_text = Some(hint_text); self } + + pub fn with_frame(mut self, frame: bool) -> Self { + self.frame = frame; + self + } } impl<'a> NostrWidget for NativeTextInput<'a> { fn render(&mut self, ui: &mut Ui, services: &mut RouteServices<'_>) -> Response { - let mut editor = TextEdit::singleline(self.text).frame(false); + let mut editor = TextEdit::singleline(self.text) + .frame(false) + .desired_width(f32::INFINITY); if let Some(hint_text) = self.hint_text { editor = editor.hint_text(egui::RichText::new(hint_text).color(NEUTRAL_500)); } - let response = Frame::none() - .inner_margin(MARGIN_DEFAULT) - .fill(NEUTRAL_800) - .rounding(ROUNDING_DEFAULT) - .show(ui, |ui| ui.add(editor)) - .inner; + let response = if self.frame { + Frame::none() + .inner_margin(MARGIN_DEFAULT) + .fill(NEUTRAL_900) + .rounding(ROUNDING_DEFAULT) + .show(ui, |ui| ui.add(editor)) + .inner + } else { + ui.add(editor) + }; if response.lost_focus() { services.action(RouteAction::HideKeyboard); } diff --git a/src/widgets/write_chat.rs b/src/widgets/write_chat.rs index 9184c45..2baf406 100644 --- a/src/widgets/write_chat.rs +++ b/src/widgets/write_chat.rs @@ -25,36 +25,29 @@ impl NostrWidget for WriteChat { let logo_bytes = include_bytes!("../resources/send-03.svg"); Frame::none() .inner_margin(MARGIN_DEFAULT) - .stroke(Stroke::new(1.0, NEUTRAL_900)) + .outer_margin(MARGIN_DEFAULT) + .fill(NEUTRAL_900) + .rounding(ROUNDING_DEFAULT) .show(ui, |ui| { - Frame::none() - .fill(NEUTRAL_900) - .rounding(ROUNDING_DEFAULT) - .inner_margin(MARGIN_DEFAULT) - .show(ui, |ui| { - ui.horizontal(|ui| { - if services - .img_cache - .load_bytes("send-03.svg", logo_bytes) - .sense(Sense::click()) - .ui(ui) - .clicked() - { - if let Ok(ev) = - services.login.write_live_chat_msg(&self.link, &self.msg) - { - info!("Sending: {:?}", ev); - services.broadcast_event(ev); - } - self.msg.clear(); - } + ui.with_layout(Layout::right_to_left(Align::Center), |ui| { + if services + .img_cache + .load_bytes("send-03.svg", logo_bytes) + .sense(Sense::click()) + .ui(ui) + .clicked() + { + if let Ok(ev) = services.login.write_live_chat_msg(&self.link, &self.msg) { + info!("Sending: {:?}", ev); + services.broadcast_event(ev); + } + self.msg.clear(); + } - ui.allocate_ui(ui.available_size(), |ui| { - let mut editor = NativeTextInput::new(&mut self.msg); - editor.render(ui, services); - }); - }); - }) + let mut editor = + NativeTextInput::new(&mut self.msg).with_hint_text("Message.."); + editor.render(ui, services); + }); }) .response }