aboutsummaryrefslogblamecommitdiffstats
path: root/src/message_view.rs
blob: e936b69dd0e50aef164d37a1a7cefba0b396cdbe (plain) (tree)
1
2
3
4
5
6
7
8
9

                      
                   
                                                                                                  




                           
                                    

               

                                     
                        



                                               
                       
                             
                            












                                        



                       

                                      
                                        








                        
                                                                 
              
                 
                                                     
                                      
                                                         

                                                       

                                                              

         
 

                                                          



                                                                   












                                                                          





                                            


                                        
                                                  

                                      






































                                                                                                 

         
 
                                            
                                                                
                                             
                                              






                                                                      



                                                        
                                      



                                                                                  










                                     
                                                                                  


                                                                     
                                                   


                            
                                                                                              
                                                                                                                










                                                               

                                         









                                                      
                                                                                              
                                                                                          





                                                                                                                         










                                                               

                                         














                                                           
use chrono::NaiveDate;
use iced::{
    border::Radius,
    widget::{button, column, container, row, scrollable, text, text_editor, text_editor::Content},
    Border, Color, Element,
    Length::{Fill, Shrink},
    Theme,
};
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::{MacawChat, MacawMessage};

pub struct MessageView {
    // references chats, users
    pub chat: MacawChat,
    // references users, messages
    pub messages: IndexMap<Uuid, MacawMessage>,
    pub config: Config,
    pub new_message: Content,
    pub shift_pressed: bool,
}

#[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<MacawMessage>),
    Message(MacawMessage),
    MessageCompose(text_editor::Action),
    SendMessage(String),
}

pub enum Action {
    None,
    SendMessage(String),
}

impl MessageView {
    pub fn new(chat: MacawChat, config: &super::Config) -> Self {
        Self {
            chat,
            // TODO: save position in message history
            messages: IndexMap::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)
            }
            Message::MessageHistory(macaw_messages) => {
                if self.messages.is_empty() {
                    self.messages = macaw_messages
                        .into_iter()
                        .map(|message| (message.id, message))
                        .collect()
                } else {
                    for message in macaw_messages {
                        let index = match self
                            .messages
                            .binary_search_by(|_, value| value.timestamp.cmp(&message.timestamp))
                        {
                            Ok(i) => i,
                            Err(i) => i,
                        };
                        self.messages.insert_before(index, message.id, message);
                    }
                }
                Action::None
            }
            Message::Message(macaw_message) => {
                if let Some((_, last)) = self.messages.last() {
                    if last.timestamp < macaw_message.timestamp {
                        self.messages.insert(macaw_message.id, macaw_message);
                    } else {
                        let index = match self.messages.binary_search_by(|_, value| {
                            value.timestamp.cmp(&macaw_message.timestamp)
                        }) {
                            Ok(i) => i,
                            Err(i) => i,
                        };
                        self.messages
                            .insert_before(index, macaw_message.id, macaw_message);
                    }
                } else {
                    self.messages.insert(macaw_message.id, macaw_message);
                }
                Action::None
            }
        }
    }

    pub fn view(&self) -> Element<Message> {
        let mut messages_view = column![].spacing(8).padding(8);
        let mut latest_date = NaiveDate::MIN;
        for (_id, 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>(&'a self, message: &MacawMessage) -> Element<'a, Message> {
        let timestamp = message.timestamp.naive_local();
        let timestamp = timestamp.time().format("%H:%M").to_string();

        if self.chat.user.jid == message.from.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()
}