diff options
Diffstat (limited to 'src/message_view.rs')
-rw-r--r-- | src/message_view.rs | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/message_view.rs b/src/message_view.rs new file mode 100644 index 0000000..4709dd6 --- /dev/null +++ b/src/message_view.rs @@ -0,0 +1,169 @@ +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<Uuid, ChatMessage>, + pub new_message: String, +} + +#[derive(Debug, Clone)] +pub enum Message { + MessageHistory(Vec<ChatMessage>), + 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<Message> { + 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<Message> = 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() +} |