From 8595b2e23b2f719e83b312a28f9dc72b9b01c1b3 Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Thu, 20 Mar 2025 17:20:15 +0000 Subject: feat: 'proper' chats list with latest message timestamps and previews --- src/main.rs | 103 +++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 39 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6b1b2fe..bc60f0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,18 +6,20 @@ use std::path::PathBuf; use std::str::FromStr; use std::sync::Arc; +use chrono::Local; +use iced::alignment::Horizontal::Right; use iced::futures::{SinkExt, Stream, StreamExt}; use iced::theme::palette::{ Background, Danger, Extended, Pair, Primary, Secondary, Success, Warning, }; use iced::theme::{Custom, Palette}; use iced::widget::button::Status; -use iced::widget::text::{Fragment, IntoFragment}; +use iced::widget::text::{Fragment, IntoFragment, Wrapping}; use iced::widget::{ - button, center, checkbox, column, container, mouse_area, opaque, row, scrollable, stack, text, - text_input, toggler, Column, Text, Toggler, + button, center, checkbox, column, container, horizontal_space, mouse_area, opaque, row, + scrollable, stack, text, text_input, toggler, Column, Text, Toggler, }; -use iced::Length::Fill; +use iced::Length::{self, Fill, Shrink}; use iced::{color, stream, Color, Element, Subscription, Task, Theme}; use indexmap::{indexmap, IndexMap}; use jid::JID; @@ -333,10 +335,9 @@ pub enum Message { Roster(HashMap), Connect, Disconnect, - OpenChat(JID), GotChats(Vec), GotMessageHistory(Chat, IndexMap), - CloseChat(JID), + ToggleChat(JID), MessageCompose(String), SendMessage(JID, String), Error(Error), @@ -537,7 +538,16 @@ impl Macaw { } Account::LoggedOut(login_modal) => Task::none(), }, - Message::OpenChat(jid) => { + Message::ToggleChat(jid) => { + match &self.open_chat { + Some(message_view) => { + if message_view.jid == jid { + self.open_chat = None; + return Task::none(); + } + } + None => {} + } self.open_chat = Some(MessageView::new(jid.clone())); let jid1 = jid.clone(); match &self.client { @@ -681,10 +691,6 @@ impl Macaw { } Task::none() } - Message::CloseChat(jid) => { - self.open_chat = None; - Task::none() - } Message::MessageCompose(m) => { if let Some(open_chat) = &mut self.open_chat { open_chat.new_message = m; @@ -727,26 +733,19 @@ impl Macaw { fn view(&self) -> Element { let mut ui: Element = { let mut chats_list: Column = column![]; - for (jid, chat) in &self.chats { - let cow_jid: Cow<'_, str> = (jid).into(); - let mut toggler: Toggler = iced::widget::toggler(false); + for (jid, (chat, latest_message)) in &self.chats { + let mut open = false; if let Some(open_chat) = &self.open_chat { if open_chat.jid == *jid { - toggler = iced::widget::toggler(true) + open = true; } } - let toggler = toggler - .on_toggle(|open| { - if open { - Message::OpenChat(jid.clone()) - } else { - Message::CloseChat(jid.clone()) - } - }) - .label(cow_jid); - chats_list = chats_list.push(toggler); + let chat_list_item = chat_list_item(chat, latest_message, open); + chats_list = chats_list.push(chat_list_item); } - let chats_list = scrollable(chats_list).height(Fill); + let chats_list = scrollable(chats_list.spacing(8).padding(8)) + .spacing(1) + .height(Fill); let connection_status = self.client.connection_status(); let client_jid: Cow<'_, str> = match &self.client { @@ -769,7 +768,8 @@ impl Macaw { .label(connection_status), ]; - let sidebar = column![chats_list, account_view].height(Fill); + // TODO: config width/resizing + let sidebar = column![chats_list, account_view].height(Fill).width(300); let message_view; if let Some(open_chat) = &self.open_chat { @@ -779,18 +779,6 @@ impl Macaw { } row![sidebar, container(message_view).width(Fill)] - - // old - - // let mut contacts: Vec> = Vec::new(); - // for (_, contact) in &self.roster { - // let jid: Cow<'_, str> = (&contact.user_jid).into(); - // contacts.push( - // button(text(jid)) - // .on_press(Message::OpenChat(contact.user_jid.clone())) - // .into(), - // ); - // } } .into(); @@ -951,3 +939,40 @@ where } stack![base.into(), opaque(mouse_area)].into() } + +fn chat_list_item<'a>( + chat: &'a Chat, + latest_message: &'a Option, + open: bool, +) -> Element<'a, Message> { + let mut content: Column = column![text(chat.correspondent.to_string())]; + if let Some(latest_message) = latest_message { + let date = latest_message.timestamp.naive_local(); + let now = Local::now().naive_local(); + let timeinfo; + if date.date() == now.date() { + // TODO: localisation/config + timeinfo = text(date.time().format("%H:%M").to_string()) + } else { + timeinfo = text(date.date().format("%d/%m").to_string()) + } + content = content.push( + row![ + container(text(latest_message.body.body.clone()).wrapping(Wrapping::None)) + .clip(true) + .width(Fill), + timeinfo + ] + .spacing(8) + .width(Fill), + ); + } + let mut button = button(content).on_press(Message::ToggleChat(chat.correspondent.clone())); + if open { + button = button.style(|theme: &Theme, status| { + let palette = theme.extended_palette(); + button::Style::default().with_background(palette.primary.weak.color) + }); + } + button.width(Fill).into() +} -- cgit