use std::borrow::Cow; use chrono::NaiveDate; use iced::{ alignment::Horizontal::{self, Right}, border::Radius, color, theme::Palette, widget::{button, column, container, row, scrollable, text, text_input, Column}, Border, Color, Element, Length::{Fill, Shrink}, Theme, }; use indexmap::IndexMap; use jid::JID; use luz::chat::Message as ChatMessage; use uuid::Uuid; pub struct MessageView { pub jid: JID, pub message_history: IndexMap, pub new_message: String, } #[derive(Debug, Clone)] pub enum Message { MessageHistory(Vec), Message(ChatMessage), MessageCompose(String), SendMessage(String), } pub enum Action { None, SendMessage(String), } impl MessageView { pub fn new(jid: JID) -> Self { Self { jid, // TODO: save position in message history message_history: IndexMap::new(), // TODO: save draft (as part of chat struct?) new_message: String::new(), } } pub fn update(&mut self, message: Message) -> Action { match message { Message::MessageHistory(messages) => { if self.message_history.is_empty() { self.message_history = messages .into_iter() .map(|message| (message.id.clone(), message)) .collect(); } Action::None } Message::Message(message) => { let i = self .message_history .iter() .position(|(_id, m)| m.timestamp > message.timestamp); if let Some(i) = i { self.message_history.insert_before(i, message.id, message); } else { self.message_history.insert(message.id, message); } Action::None } Message::MessageCompose(s) => { self.new_message = s; Action::None } Message::SendMessage(m) => { self.new_message = String::new(); Action::SendMessage(m) } } } pub fn view(&self) -> Element { let mut messages_view = column![].spacing(8); let mut latest_date = NaiveDate::MIN; for (_id, message) in &self.message_history { let message_date = message.timestamp.naive_local().date(); if message_date > latest_date { latest_date = message_date; messages_view = messages_view.push(date(latest_date)); } messages_view = messages_view.push(self.message(message)); } let message_send_input = row![ text_input("new message", &self.new_message).on_input(Message::MessageCompose), button("send").on_press(Message::SendMessage(self.new_message.clone())) ]; column![ scrollable(messages_view) .height(Fill) .width(Fill) .spacing(1) .anchor_bottom(), message_send_input ] .into() } pub fn message<'a>(&'a self, message: &'a ChatMessage) -> Element<'a, Message> { let timestamp = message.timestamp.naive_local(); let timestamp = timestamp.time().format("%H:%M").to_string(); if self.jid == message.from.as_bare() { container( container( column![ text(message.body.body.as_str()), container(text(timestamp).wrapping(text::Wrapping::None).size(12)) .align_right(Fill) ] .width(Shrink) .max_width(500), ) .padding(16) .style(|theme: &Theme| { let palette = theme.extended_palette(); container::Style::default() .background(palette.primary.weak.color) .border(Border { color: Color::BLACK, width: 4., radius: Radius::new(16), }) }), ) .align_left(Fill) .into() } else { let element: Element = container( container( column![ text(message.body.body.as_str()), container(text(timestamp).wrapping(text::Wrapping::None).size(12)) .align_right(Fill) ] .width(Shrink) .max_width(500), ) .padding(16) .style(|theme: &Theme| { let palette = theme.extended_palette(); container::Style::default() .background(palette.primary.base.color) .border(Border { color: Color::BLACK, width: 4., radius: Radius::new(16), }) }), ) .align_right(Fill) .into(); // element.explain(Color::BLACK) element } } } pub fn date(date: NaiveDate) -> Element<'static, Message> { container(text(date.to_string())).center_x(Fill).into() }