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()
}