use std::{
borrow::{Borrow, Cow},
cell::{Ref, RefCell},
ops::Deref,
rc::Rc,
};
use chrono::NaiveDate;
use filamento::chat::Message as ChatMessage;
use iced::{
alignment::Horizontal::{self, Right},
border::Radius,
color,
theme::Palette,
widget::{
button, column, container, horizontal_space, row, scrollable, text, text_editor,
text_editor::Content, text_input, Column,
},
Border, Color, Element,
Length::{Fill, Shrink},
Theme,
};
use indexmap::IndexMap;
use jid::JID;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::{MacawChat, MacawMessage};
pub struct MessageView {
pub config: Config,
pub chat: Rc<RefCell<MacawChat>>,
pub messages: Vec<Rc<RefCell<MacawMessage>>>,
pub new_message: Content,
pub shift_pressed: bool,
}
impl MessageView {
pub fn chat(&self) -> Ref<'_, MacawChat> {
self.chat.as_ref().borrow()
}
pub fn messages(
&self,
) -> impl Iterator<Item = impl Deref<Target = MacawMessage> + use<'_>> + use<'_> {
self.messages
.iter()
.map(|message| message.as_ref().borrow())
}
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Config {
pub send_on_enter: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
send_on_enter: true,
}
}
}
#[derive(Debug, Clone)]
pub enum Message {
// MessageHistory(Vec<Rc<RefCell<MacawMessage>>>),
// Message(Rc<RefCell<MacawMessage>>),
MessageCompose(text_editor::Action),
SendMessage(String),
}
pub enum Action {
None,
SendMessage(String),
}
impl MessageView {
pub fn new(chat: Rc<RefCell<MacawChat>>, config: &super::Config) -> Self {
Self {
chat,
// TODO: save position in message history
messages: Vec::new(),
// TODO: save draft (as part of chat struct?)
new_message: Content::new(),
config: config.message_view_config.clone(),
// TODO: have centralised modifier state location?
shift_pressed: false,
}
}
pub fn update(&mut self, message: Message) -> Action {
match message {
Message::MessageCompose(a) => {
match &a {
text_editor::Action::Edit(edit) => match edit {
text_editor::Edit::Enter => {
if self.config.send_on_enter {
if !self.shift_pressed {
let message = self.new_message.text();
self.new_message = Content::new();
return Action::SendMessage(message);
}
} else {
if self.shift_pressed {
let message = self.new_message.text();
self.new_message = Content::new();
return Action::SendMessage(message);
}
}
}
_ => {}
},
_ => {}
}
self.new_message.perform(a);
Action::None
}
Message::SendMessage(m) => {
self.new_message = Content::new();
Action::SendMessage(m)
}
}
}
pub fn view(&self) -> Element<Message> {
let mut messages_view = column![].spacing(8).padding(8);
let mut latest_date = NaiveDate::MIN;
for message in self.messages() {
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 text_editor = text_editor(&self.new_message)
.placeholder("new message")
.on_action(Message::MessageCompose)
.wrapping(text::Wrapping::WordOrGlyph);
let message_send_input = row![
text_editor,
button("send").on_press(Message::SendMessage(self.new_message.text()))
]
.padding(8);
column![
scrollable(messages_view)
.height(Fill)
.width(Fill)
.spacing(1)
.anchor_bottom(),
message_send_input
]
.into()
}
pub fn message<'a, 'b, M>(&'a self, message: M) -> Element<'b, Message>
where
M: Deref<Target = MacawMessage> + 'b,
{
let timestamp = message.timestamp.naive_local();
let timestamp = timestamp.time().format("%H:%M").to_string();
if self.chat().user().jid == message.user().jid {
container(
container(
column![
text(message.body.body.clone()).wrapping(text::Wrapping::WordOrGlyph),
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: 0.,
// width: 4.,
radius: Radius::new(16),
})
}),
)
.align_left(Fill)
.into()
} else {
let element: Element<Message> = container(
container(
column![
text(message.body.body.clone()).wrapping(text::Wrapping::WordOrGlyph),
container(text(timestamp).wrapping(text::Wrapping::None).size(12))
.align_right(Fill) // row![
// // horizontal_space(),
// // horizontal_space(),
// text(timestamp).wrapping(text::Wrapping::None).size(12)
// ] // 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: 0.,
// 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()
}