aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@bunny.garden>2025-04-11 08:32:50 +0100
committerLibravatar cel 🌸 <cel@bunny.garden>2025-04-11 08:32:50 +0100
commit4deb7470413a9d53323f6bedf26882ad2b0844a6 (patch)
tree2a3ca1b69a02300bbf0db40cd7e7fe410b8e938a /src/main.rs
parent1299841ecb5648328a590658c2ea6ad18ecf46e3 (diff)
downloadmacaw-4deb7470413a9d53323f6bedf26882ad2b0844a6.tar.gz
macaw-4deb7470413a9d53323f6bedf26882ad2b0844a6.tar.bz2
macaw-4deb7470413a9d53323f6bedf26882ad2b0844a6.zip
feat: nicks and avatars
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs724
1 files changed, 270 insertions, 454 deletions
diff --git a/src/main.rs b/src/main.rs
index 8b22ce3..0b8b3b8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,9 +17,7 @@ use filamento::{roster::Contact, user::User, UpdateMessage};
use iced::alignment::Horizontal::Right;
use iced::futures::{SinkExt, Stream, StreamExt};
use iced::keyboard::{on_key_press, on_key_release, Key, Modifiers};
-use iced::theme::palette::{
- Background, Danger, Extended, Pair, Primary, Secondary, Success, Warning,
-};
+use iced::theme::palette::{Background, Danger, Extended, Pair, Primary, Secondary, Success};
use iced::theme::{Custom, Palette};
use iced::widget::button::Status;
use iced::widget::text::{Fragment, IntoFragment, Wrapping};
@@ -70,92 +68,62 @@ impl Default for Config {
pub struct Macaw {
client: Account,
config: Config,
- // references users
- messages: HashMap<Uuid, Weak<RefCell<MacawMessage>>>,
- // references users
- roster: HashMap<JID, MacawContact>,
- // store count of how many things reference it. allows it to stay mutable.
- // or maybe store a bool that indicates whether it can be garbage collected
- // but then in that case, if you change the bool, then it can be dropped anyway....
- // realistically none of this stuff matters until there are group chats. and group chats will have a list of users anyway.
- // so whenever a group chat is closed any users that are both not in the roster and that one doesn't also have a chat with
- // can be dropped.
- // but then also users who are no longer in the chat but were loaded because of old messages must also be dropped.
- // so the set of users in the group chat must also include people who left, just marked as do-not-show/departed. solution!
- // this only doesn't work if there are multiple group chats open at the same time ig. in this case the other chats' user
- // lists would need to also be differenced.
- // i'm pretty sure this is just O(2 + n) where n = number of other group chats open for each drop attempt, and it can
- // happen in a separate thread in the background anyway so no slowdown.
- // TODO: add presences reference
- // references nothing, optionally contact
- users: HashMap<JID, Weak<RefCell<MacawUser>>>,
- // chat could have no messages, and therefore no latest message.
- // references users, latest message
- chats: IndexMap<JID, Rc<RefCell<MacawChat>>>,
- subscription_requests: HashSet<JID>,
- open_chat: Option<MessageView>,
+ presences: HashMap<JID, Presence>,
+ subscription_requests: HashSet<MacawUser>,
new_chat: Option<NewChat>,
+ // references chats, users, messages
+ open_chat: Option<MessageView>,
+ // references users, contacts
+ roster: HashMap<JID, MacawContact>,
+ // references chats, users, messages
+ chats_list: IndexMap<JID, ChatListItem>,
}
-#[derive(Debug)]
-pub struct MacawUser {
- inner: User,
- contact: Option<Rc<RefCell<MacawContact>>>,
+#[derive(Debug, Clone)]
+pub struct MacawMessage {
+ inner: ChatMessage,
+ from: MacawUser,
}
-impl Deref for MacawUser {
- type Target = User;
+impl Deref for MacawMessage {
+ type Target = ChatMessage;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
-impl DerefMut for MacawUser {
+impl DerefMut for MacawMessage {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
-impl MacawUser {
- pub fn contact(&self) -> Option<Ref<'_, MacawContact>> {
- self.contact
- .as_ref()
- .map(|contact| contact.as_ref().borrow())
- }
-}
-
#[derive(Debug, Clone)]
-pub struct MacawMessage {
- inner: ChatMessage,
- user: Rc<RefCell<MacawUser>>,
+pub struct MacawUser {
+ inner: User,
+ // contact not needed, as can always query the roster store to get this option.
+ // contact: Option<Contact>,
}
-impl Deref for MacawMessage {
- type Target = ChatMessage;
+impl Deref for MacawUser {
+ type Target = User;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
-impl DerefMut for MacawMessage {
+impl DerefMut for MacawUser {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
-impl MacawMessage {
- pub fn user(&self) -> Ref<'_, MacawUser> {
- let user = self.user.as_ref().borrow();
- user
- }
-}
-
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct MacawContact {
inner: Contact,
- user: Rc<RefCell<MacawUser>>,
+ user: User,
}
impl Deref for MacawContact {
@@ -172,45 +140,44 @@ impl DerefMut for MacawContact {
}
}
-impl MacawContact {
- pub fn user(&self) -> Ref<'_, MacawUser> {
- let user = self.user.as_ref().borrow();
- user
- }
-}
-
+#[derive(Debug, Clone)]
pub struct MacawChat {
inner: Chat,
- user: Rc<RefCell<MacawUser>>,
- message: Option<Rc<RefCell<MacawMessage>>>,
+ user: MacawUser,
}
-impl Deref for MacawChat {
- type Target = Chat;
+pub struct ChatListItem {
+ // references chats
+ inner: MacawChat,
+ // references users, messages
+ latest_message: Option<MacawMessage>,
+}
+
+impl Deref for ChatListItem {
+ type Target = MacawChat;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
-impl DerefMut for MacawChat {
+impl DerefMut for ChatListItem {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
-impl MacawChat {
- pub fn user(&self) -> Ref<'_, MacawUser> {
- let user = self.user.as_ref().borrow();
- user
+impl Deref for MacawChat {
+ type Target = Chat;
+
+ fn deref(&self) -> &Self::Target {
+ &self.inner
}
+}
- pub fn latest_message(&self) -> Option<Ref<'_, MacawMessage>> {
- let latest_message = self
- .message
- .as_ref()
- .map(|message| message.as_ref().borrow());
- latest_message
+impl DerefMut for MacawChat {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.inner
}
}
@@ -228,13 +195,12 @@ impl Macaw {
Self {
client: account,
config,
- roster: HashMap::new(),
- users: HashMap::new(),
- chats: IndexMap::new(),
+ presences: HashMap::new(),
subscription_requests: HashSet::new(),
- open_chat: None,
new_chat: None,
- messages: HashMap::new(),
+ open_chat: None,
+ roster: HashMap::new(),
+ chats_list: IndexMap::new(),
}
}
}
@@ -486,35 +452,41 @@ async fn main() -> iced::Result {
let luz_handle1 = luz_handle.clone();
let luz_handle2 = luz_handle.clone();
if cfg.auto_connect {
- Task::batch(
- [
- Task::batch([
- Task::perform(
- async move { luz_handle1.get_roster_with_users().await },
- |result| {
- let roster = result.unwrap();
- let mut macaw_roster = HashMap::new();
- for contact in roster {
- macaw_roster.insert(contact.0.user_jid.clone(), contact);
- }
- Message::RosterWithUsers(macaw_roster)
- },
- ),
- Task::perform(
- async move {
- luz_handle2.get_chats_ordered_with_latest_messages().await
- },
- |chats| {
- let chats = chats.unwrap();
- info!("got chats: {:?}", chats);
- Message::GotChats(chats)
- },
- ),
- ])
- .chain(Task::done(Message::Connect)),
- Task::stream(stream),
- ],
- )
+ Task::batch([
+ Task::batch([
+ Task::perform(
+ async move { luz_handle1.get_roster_with_users().await },
+ |result| {
+ let roster = result.unwrap();
+ let mut macaw_roster = HashMap::new();
+ for (contact, user) in roster {
+ macaw_roster.insert(
+ contact.user_jid.clone(),
+ MacawContact {
+ inner: contact,
+ user,
+ },
+ );
+ }
+ Message::Roster(macaw_roster)
+ },
+ ),
+ Task::perform(
+ async move {
+ luz_handle2
+ .get_chats_ordered_with_latest_messages_and_users()
+ .await
+ },
+ |chats| {
+ let chats = chats.unwrap();
+ info!("got chats: {:?}", chats);
+ Message::GotChats(chats)
+ },
+ ),
+ ])
+ .chain(Task::done(Message::Connect)),
+ Task::stream(stream),
+ ])
} else {
Task::batch([
Task::perform(
@@ -522,14 +494,24 @@ async fn main() -> iced::Result {
|result| {
let roster = result.unwrap();
let mut macaw_roster = HashMap::new();
- for contact in roster {
- macaw_roster.insert(contact.0.user_jid.clone(), contact);
+ for (contact, user) in roster {
+ macaw_roster.insert(
+ contact.user_jid.clone(),
+ MacawContact {
+ inner: contact,
+ user,
+ },
+ );
}
- Message::RosterWithUsers(macaw_roster)
+ Message::Roster(macaw_roster)
},
),
Task::perform(
- async move { luz_handle2.get_chats_ordered_with_latest_messages().await },
+ async move {
+ luz_handle2
+ .get_chats_ordered_with_latest_messages_and_users()
+ .await
+ },
|chats| {
let chats = chats.unwrap();
info!("got chats: {:?}", chats);
@@ -605,10 +587,10 @@ pub enum Message {
LoginModal(login_modal::Message),
ClientCreated(Client),
Luz(UpdateMessage),
- RosterWithUsers(HashMap<JID, (Contact, User)>),
+ Roster(HashMap<JID, MacawContact>),
Connect,
Disconnect,
- GotChats(Vec<(Chat, ChatMessage)>),
+ GotChats(Vec<((Chat, User), (ChatMessage, User))>),
ToggleChat(JID),
SendMessage(JID, String),
Error(Error),
@@ -668,58 +650,21 @@ impl Macaw {
presence: PresenceType::Online(online),
};
client.connection_state = ConnectionState::Online;
- let mut roster = HashMap::new();
- let mut get_users = Vec::new();
- for contact in vec {
- if let Some(Some(user)) =
- self.users.get(&contact.user_jid).map(|user| user.upgrade())
- {
- let contact = MacawContact {
- inner: contact,
- user,
- };
- roster.insert(contact.user_jid.clone(), contact);
- user.borrow_mut().contact = Some(Rc::new(RefCell::new(contact)))
- } else {
- match self.client {
- Account::LoggedIn(client) => get_users.push(Task::perform(
- client.get_user(contact.user_jid),
- |result| {
- let result = result.unwrap();
- (contact, result)
- },
- )),
- Account::LoggedOut(login_modal) => {}
- }
- }
- }
- if get_users.is_empty() {
- self.roster = roster;
- Task::none()
- } else {
- // TODO: potential race condition if two rosters are gotten at the same time?
- Task::batch(get_users).collect().then(|users| {
- for (contact, user) in users {
- let user = Rc::new(RefCell::new(MacawUser {
- inner: user,
- contact: None,
- }));
- let contact = MacawContact {
+ let roster = vec
+ .into_iter()
+ .map(|(contact, user)| {
+ (
+ contact.user_jid.clone(),
+ MacawContact {
inner: contact,
user,
- };
- roster.insert(contact.user_jid, contact);
- user.borrow_mut().contact =
- Some(Rc::new(RefCell::new(contact)));
- self.users.insert(
- contact.user_jid,
- Rc::<RefCell<MacawUser>>::downgrade(&user),
- );
- }
- self.roster = roster;
- Task::none()
+ },
+ )
})
- }
+ .collect();
+ // no need to also update users as any user updates will come in separately
+ self.roster = roster;
+ Task::none()
}
Account::LoggedOut(login_modal) => Task::none(),
},
@@ -737,99 +682,15 @@ impl Macaw {
Account::LoggedOut(login_modal) => Task::none(),
}
}
- UpdateMessage::FullRoster(vec) => {
- let mut roster = HashMap::new();
- let mut get_users = Vec::new();
- for contact in vec {
- if let Some(Some(user)) =
- self.users.get(&contact.user_jid).map(|user| user.upgrade())
- {
- let contact = MacawContact {
- inner: contact,
- user,
- };
- roster.insert(contact.user_jid.clone(), contact);
- user.borrow_mut().contact = Some(Rc::new(RefCell::new(contact)))
- } else {
- match self.client {
- Account::LoggedIn(client) => get_users.push(Task::perform(
- client.get_user(contact.user_jid),
- |result| {
- let result = result.unwrap();
- (contact, result)
- },
- )),
- Account::LoggedOut(login_modal) => {}
- }
- }
- }
- if get_users.is_empty() {
- self.roster = roster;
- Task::none()
- } else {
- // TODO: potential race condition if two rosters are gotten at the same time?
- Task::batch(get_users).collect().then(|users| {
- for (contact, user) in users {
- let user = Rc::new(RefCell::new(MacawUser {
- inner: user,
- contact: None,
- }));
- let contact = MacawContact {
- inner: contact,
- user,
- };
- roster.insert(contact.user_jid, contact);
- user.borrow_mut().contact = Some(Rc::new(RefCell::new(contact)));
- self.users.insert(
- contact.user_jid,
- Rc::<RefCell<MacawUser>>::downgrade(&user),
- );
- }
- self.roster = roster;
- Task::none()
- })
- }
- }
- UpdateMessage::RosterUpdate(contact) => {
- if let Some(Some(user)) =
- self.users.get(&contact.user_jid).map(|user| user.upgrade())
- {
- let contact = MacawContact {
+ UpdateMessage::RosterUpdate(contact, user) => {
+ self.roster.insert(
+ contact.user_jid.clone(),
+ MacawContact {
inner: contact,
user,
- };
- self.roster.insert(contact.user_jid.clone(), contact);
- user.borrow_mut().contact = Some(Rc::new(RefCell::new(contact)));
- Task::none()
- } else {
- match self.client {
- Account::LoggedIn(client) => {
- Task::perform(client.get_user(contact.user_jid), |result| {
- let result = result.unwrap();
- (contact, result)
- })
- .then(|(contact, user)| {
- let user = Rc::new(RefCell::new(MacawUser {
- inner: user,
- contact: None,
- }));
- let contact = MacawContact {
- inner: contact,
- user,
- };
- self.roster.insert(contact.user_jid.clone(), contact);
- user.borrow_mut().contact =
- Some(Rc::new(RefCell::new(contact)));
- self.users.insert(
- contact.user_jid,
- Rc::<RefCell<MacawUser>>::downgrade(&user),
- );
- Task::none()
- })
- }
- Account::LoggedOut(login_modal) => Task::none(),
- }
- }
+ },
+ );
+ Task::none()
}
UpdateMessage::RosterDelete(jid) => {
self.roster.remove(&jid);
@@ -837,123 +698,98 @@ impl Macaw {
}
UpdateMessage::Presence { from, presence } => {
// TODO: presence handling
+ self.presences.insert(from, presence);
Task::none()
}
- UpdateMessage::Message { to, message } => {
- if let Some(Some(user)) =
- self.users.get(&message.from).map(|user| user.upgrade())
+ UpdateMessage::Message { to, message, from } => {
+ let message = MacawMessage {
+ inner: message,
+ from: MacawUser { inner: from },
+ };
+ if let Some((chat_jid, mut chat_list_item)) =
+ self.chats_list.shift_remove_entry(&to)
{
- let message = MacawMessage {
- inner: message,
- user,
- };
- let message = Rc::new(RefCell::new(message));
- self.messages.insert(
- message.as_ref().borrow().id,
- Rc::<RefCell<MacawMessage>>::downgrade(&message),
- );
- if let Some((chat_jid, chat)) = self.chats.shift_remove_entry(&to) {
- chat.as_ref().borrow_mut().message = Some(message);
- self.chats.insert_before(0, chat_jid, chat);
- if let Some(open_chat) = &mut self.open_chat {
- if open_chat.chat().user().jid == to {
- open_chat.messages.push(message);
- }
+ chat_list_item.latest_message = Some(message.clone());
+ self.chats_list.insert_before(0, chat_jid, chat_list_item);
+ if let Some(open_chat) = &mut self.open_chat {
+ if open_chat.chat.user.jid == to {
+ open_chat.update(message_view::Message::Message(message));
}
- } else {
- let chat = Chat {
- correspondent: to.clone(),
- // TODO: should have a new chat event first...
- have_chatted: false,
- };
- let chat = MacawChat {
- inner: chat,
- user,
- message: Some(message),
- };
- self.chats.insert_before(0, to, Rc::new(RefCell::new(chat)));
}
- Task::none()
} else {
- match self.client {
- Account::LoggedIn(client) => {
- Task::perform(client.get_user(message.from), |result| {
- let result = result.unwrap();
- result
- })
- .then(|user| {
- let user = Rc::new(RefCell::new(MacawUser {
- inner: user,
- contact: None,
- }));
- self.users.insert(
- user.as_ref().borrow().jid,
- Rc::<RefCell<MacawUser>>::downgrade(&user),
- );
- let message = MacawMessage {
- inner: message,
- user,
- };
- let message = Rc::new(RefCell::new(message));
- self.messages.insert(
- message.as_ref().borrow().id,
- Rc::<RefCell<MacawMessage>>::downgrade(&message),
- );
- if let Some((chat_jid, chat)) =
- self.chats.shift_remove_entry(&to)
- {
- chat.as_ref().borrow_mut().message = Some(message);
- self.chats.insert_before(0, chat_jid, chat);
- if let Some(open_chat) = &mut self.open_chat {
- if open_chat.chat().user().jid == to {
- open_chat.messages.push(message);
- }
- }
- } else {
- let chat = Chat {
- correspondent: to.clone(),
- // TODO: should have a new chat event first...
- have_chatted: false,
- };
- let chat = MacawChat {
- inner: chat,
- user,
- message: Some(message),
- };
- self.chats.insert_before(
- 0,
- to,
- Rc::new(RefCell::new(chat)),
- );
- }
- Task::none()
- })
- }
- Account::LoggedOut(login_modal) => Task::none(),
- }
+ // TODO: get the actual chat from the thing, or send the chat first, from the client side.
+ let chat = Chat {
+ correspondent: to.clone(),
+ have_chatted: false,
+ };
+ let chat_list_item = ChatListItem {
+ inner: MacawChat {
+ inner: chat,
+ user: message.from.clone(),
+ },
+ latest_message: Some(message),
+ };
+ self.chats_list.insert_before(0, to, chat_list_item);
}
+ Task::none()
}
UpdateMessage::SubscriptionRequest(jid) => {
// TODO: subscription requests
Task::none()
}
- UpdateMessage::MessageDelivery { id, delivery } => {
- if let Some(Some(message)) =
- self.messages.get(&id).map(|message| message.upgrade())
- {
- message.as_ref().borrow_mut().delivery = Some(delivery)
+ UpdateMessage::MessageDelivery { chat, id, delivery } => {
+ if let Some(chat_list_item) = self.chats_list.get_mut(&chat) {
+ if let Some(latest_message) = &mut chat_list_item.latest_message {
+ if latest_message.id == id {
+ latest_message.delivery = Some(delivery)
+ }
+ }
+ }
+ if let Some(open_chat) = &mut self.open_chat {
+ if let Some(message) = open_chat.messages.get_mut(&id) {
+ message.delivery = Some(delivery)
+ }
}
Task::none()
}
UpdateMessage::NickChanged { jid, nick } => {
- if let Some(Some(user)) = self.users.get(&jid).map(|user| user.upgrade()) {
- user.as_ref().borrow_mut().nick = nick
+ // roster, chats_list, open chat
+ if let Some(contact) = self.roster.get_mut(&jid) {
+ contact.user.nick = nick.clone();
+ }
+ if let Some(chats_list_item) = self.chats_list.get_mut(&jid) {
+ chats_list_item.user.nick = nick.clone()
+ }
+ if let Some(open_chat) = &mut self.open_chat {
+ for (_, message) in &mut open_chat.messages {
+ if message.from.jid == jid {
+ message.from.nick = nick.clone()
+ }
+ }
+ if open_chat.chat.user.jid == jid {
+ open_chat.chat.user.nick = nick
+ }
}
Task::none()
}
UpdateMessage::AvatarChanged { jid, id } => {
- if let Some(Some(user)) = self.users.get(&jid).map(|user| user.upgrade()) {
- user.as_ref().borrow_mut().avatar = id
+ // roster, chats_list, open chat
+ if let Some(contact) = self.roster.get_mut(&jid) {
+ contact.user.avatar = id.clone();
+ }
+ if let Some(chats_list_item) = self.chats_list.get_mut(&jid) {
+ chats_list_item.user.avatar = id.clone()
+ }
+ if let Some(open_chat) = &mut self.open_chat {
+ // TODO: consider using an indexmap with two keys for speeding this up?
+ for (_, message) in &mut open_chat.messages {
+ if message.from.jid == jid {
+ message.from.avatar = id.clone()
+ }
+ }
+ if open_chat.chat.user.jid == jid {
+ open_chat.chat.user.avatar = id
+ }
}
Task::none()
}
@@ -970,17 +806,24 @@ impl Macaw {
|result| {
let roster = result.unwrap();
let mut macaw_roster = HashMap::new();
- for contact in roster {
- macaw_roster.insert(contact.0.user_jid.clone(), contact);
+ for (contact, user) in roster {
+ macaw_roster.insert(
+ contact.user_jid.clone(),
+ MacawContact {
+ inner: contact,
+ user,
+ },
+ );
}
- Message::RosterWithUsers(macaw_roster)
+ // TODO: clean this up
+ Message::Roster(macaw_roster)
},
),
Task::perform(
async move {
client2
.client
- .get_chats_ordered_with_latest_messages()
+ .get_chats_ordered_with_latest_messages_and_users()
.await
},
|chats| {
@@ -1002,17 +845,23 @@ impl Macaw {
|result| {
let roster = result.unwrap();
let mut macaw_roster = HashMap::new();
- for contact in roster {
- macaw_roster.insert(contact.0.user_jid.clone(), contact);
+ for (contact, user) in roster {
+ macaw_roster.insert(
+ contact.user_jid.clone(),
+ MacawContact {
+ inner: contact,
+ user,
+ },
+ );
}
- Message::RosterWithUsers(macaw_roster)
+ Message::Roster(macaw_roster)
},
),
Task::perform(
async move {
client2
.client
- .get_chats_ordered_with_latest_messages()
+ .get_chats_ordered_with_latest_messages_and_users()
.await
},
|chats| {
@@ -1028,22 +877,8 @@ impl Macaw {
])
}
}
- Message::RosterWithUsers(hash_map) => {
- for (_, (contact, user)) in hash_map {
- let user = MacawUser {
- inner: user,
- contact: None,
- };
- let user = Rc::new(RefCell::new(user));
- let contact = MacawContact {
- inner: contact,
- user,
- };
- self.roster.insert(contact.user_jid, contact);
- user.borrow_mut().contact = Some(Rc::new(RefCell::new(contact)));
- self.users
- .insert(contact.user_jid, Rc::<RefCell<MacawUser>>::downgrade(&user));
- }
+ Message::Roster(hash_map) => {
+ self.roster = hash_map;
Task::none()
}
Message::Connect => match &mut self.client {
@@ -1070,47 +905,34 @@ impl Macaw {
Message::ToggleChat(jid) => {
match &self.open_chat {
Some(message_view) => {
- if message_view.chat().user().jid == jid {
+ if message_view.chat.user.jid == jid {
self.open_chat = None;
return Task::none();
}
}
None => {}
}
- if let Some(chat) = self.chats.get(&jid) {
+ if let Some(chat) = self.chats_list.get(&jid) {
+ self.open_chat = Some(MessageView::new((*chat).clone(), &self.config));
match &self.client {
Account::LoggedIn(client) => {
let client = client.clone();
Task::perform(
- async move { client.get_messages(jid).await },
+ async move { client.get_messages_with_users(jid).await },
move |result| {
let message_history = result.unwrap();
- let messages = Vec::new();
- for message in message_history {
- // TODO: there must be users for the messages, but won't work for group chats.
- let user = self
- .users
- .get(&message.from)
- .unwrap()
- .upgrade()
- .unwrap();
- let message = MacawMessage {
+ let messages = message_history
+ .into_iter()
+ .map(|(message, user)| MacawMessage {
inner: message,
- user,
- };
- let message = Rc::new(RefCell::new(message));
- self.messages.insert(
- message.as_ref().borrow().id,
- Rc::<RefCell<MacawMessage>>::downgrade(&message),
- );
- messages.push(message)
- }
- let open_chat = MessageView::new(chat.clone(), &self.config);
- open_chat.messages = messages;
- self.open_chat = Some(open_chat);
+ from: MacawUser { inner: user },
+ })
+ .collect();
+ Message::MessageView(message_view::Message::MessageHistory(
+ messages,
+ ))
},
)
- .discard()
}
Account::LoggedOut(login_modal) => Task::none(),
}
@@ -1203,14 +1025,23 @@ impl Macaw {
return Task::none();
}
};
- for (chat, message) in chats {
+ for ((chat, chat_user), (message, message_user)) in chats {
let chat = MacawChat {
- inner: todo!(),
- user: todo!(),
- message: todo!(),
- }
- self.chats
- .insert(chat.0.correspondent.clone(), (chat.0.clone(), Some(chat.1)));
+ inner: chat,
+ user: MacawUser { inner: chat_user },
+ };
+ let latest_message = MacawMessage {
+ inner: message,
+ from: MacawUser {
+ inner: message_user,
+ },
+ };
+ let chat_list_item = ChatListItem {
+ inner: chat.clone(),
+ latest_message: Some(latest_message),
+ };
+ self.chats_list
+ .insert(chat.correspondent.clone(), chat_list_item);
}
Task::batch(tasks)
}
@@ -1238,10 +1069,9 @@ impl Macaw {
let action = message_view.update(message);
match action {
message_view::Action::None => Task::none(),
- message_view::Action::SendMessage(m) => Task::done(Message::SendMessage(
- message_view.chat().user().jid.clone(),
- m,
- )),
+ message_view::Action::SendMessage(m) => {
+ Task::done(Message::SendMessage(message_view.chat.user.jid.clone(), m))
+ }
}
} else {
Task::none()
@@ -1268,15 +1098,15 @@ impl Macaw {
let mut ui: Element<Message> = {
let mut chats_list: Column<Message> = column![];
if let Account::LoggedIn(client) = &self.client {
- for (jid, chat) in &self.chats {
+ for (jid, chat) in &self.chats_list {
let mut open = false;
if let Some(open_chat) = &self.open_chat {
- if open_chat.chat().user().jid == *jid {
+ if open_chat.chat.user.jid == *jid {
open = true;
}
}
let chat_list_item =
- chat_list_item(client.files_root(), chat.as_ref().borrow(), open);
+ chat_list_item(&self.roster, client.files_root(), chat, open);
chats_list = chats_list.push(chat_list_item);
}
}
@@ -1345,10 +1175,6 @@ impl Macaw {
color: color!(0x392c25),
text: color!(0xdcdcdc),
},
- weakest: Pair {
- color: color!(0xdcdcdc),
- text: color!(0x392c25),
- },
weak: Pair {
color: color!(0xdcdcdc),
text: color!(0x392c25),
@@ -1357,10 +1183,6 @@ impl Macaw {
color: color!(0x364b3b),
text: color!(0xdcdcdc),
},
- strongest: Pair {
- color: color!(0x364b3b),
- text: color!(0xdcdcdc),
- },
},
primary: Primary {
base: Pair {
@@ -1404,20 +1226,6 @@ impl Macaw {
text: color!(0xdcdcdc),
},
},
- warning: Warning {
- base: Pair {
- color: color!(0xFF9D00),
- text: color!(0x000000),
- },
- weak: Pair {
- color: color!(0xFF9D00),
- text: color!(0x000000),
- },
- strong: Pair {
- color: color!(0xFF9D00),
- text: color!(0x000000),
- },
- },
danger: Danger {
base: Pair {
color: color!(0xC1173C),
@@ -1479,28 +1287,33 @@ where
stack![base.into(), opaque(mouse_area)].into()
}
-fn chat_list_item<'a, C>(file_root: &'a Path, chat: C, open: bool) -> Element<'a, Message>
-where
- C: Deref<Target = MacawChat> + 'a,
-{
+fn chat_list_item<'a>(
+ roster: &HashMap<JID, MacawContact>,
+ file_root: &'a Path,
+ chat_list_item: &'a ChatListItem,
+ open: bool,
+) -> Element<'a, Message> {
let name: String;
- if let Some(Some(contact_name)) = chat.user().contact().map(|contact| contact.name.clone()) {
- name = contact_name
- } else if let Some(nick) = &chat.user().nick {
+ if let Some(Some(contact_name)) = roster
+ .get(chat_list_item.correspondent())
+ .map(|contact| &contact.name)
+ {
+ name = contact_name.clone()
+ } else if let Some(nick) = &chat_list_item.user.nick {
name = nick.clone()
} else {
- name = chat.correspondent().to_string();
+ name = chat_list_item.correspondent().to_string();
}
let avatar: Option<String>;
- if let Some(user_avatar) = &chat.user().avatar {
+ if let Some(user_avatar) = &chat_list_item.user.avatar {
avatar = Some(user_avatar.clone())
} else {
avatar = None
}
let latest_message_text: Option<(String, String)>;
- if let Some(latest_message) = chat.latest_message() {
+ if let Some(latest_message) = &chat_list_item.latest_message {
let message = latest_message.body.body.replace("\n", " ");
let date = latest_message.timestamp.naive_local();
let now = Local::now().naive_local();
@@ -1527,7 +1340,9 @@ where
}
let avatar_image = if let Some(avatar) = avatar {
- let path = file_root.join(avatar);
+ let mut path = file_root.join(avatar);
+ path.set_extension("jpg");
+ info!("got avatar: {:?}", path);
Some(image(path).width(48).height(48))
} else {
None
@@ -1570,7 +1385,8 @@ where
text(name).into()
}
};
- let mut button = button(content).on_press(Message::ToggleChat(chat.correspondent.clone()));
+ let mut button =
+ button(content).on_press(Message::ToggleChat(chat_list_item.correspondent().clone()));
if open {
button = button.style(|theme: &Theme, status| {
let palette = theme.extended_palette();