diff --git a/meli/src/mail/view.rs b/meli/src/mail/view.rs index eea75aeb..0bd86d37 100644 --- a/meli/src/mail/view.rs +++ b/meli/src/mail/view.rs @@ -61,6 +61,7 @@ pub struct MailView { forward_dialog: Option>>>, theme_default: ThemeAttribute, active_jobs: HashSet, + initialized: bool, state: MailViewState, main_loop_handler: MainLoopHandler, id: ComponentId, @@ -86,6 +87,7 @@ impl Drop for MailView { impl MailView { pub fn new( coordinates: Option<(AccountHash, MailboxHash, EnvelopeHash)>, + initialize_now: bool, context: &mut Context, ) -> Self { let mut ret = MailView { @@ -95,12 +97,15 @@ impl MailView { forward_dialog: None, theme_default: crate::conf::value(context, "mail.view.body"), active_jobs: Default::default(), + initialized: false, state: MailViewState::default(), main_loop_handler: context.main_loop_handler.clone(), id: ComponentId::default(), }; - ret.init_futures(context); + if initialize_now { + ret.init_futures(context); + } ret } @@ -163,6 +168,7 @@ impl MailView { if let Some(p) = pending_action { self.perform_action(p, context); } + self.initialized = true; } fn perform_action(&mut self, action: PendingReplyAction, context: &mut Context) { @@ -284,6 +290,10 @@ impl Component for MailView { return; }; + if !self.initialized { + self.init_futures(context); + return; + } { let account = &context.accounts[&coordinates.0]; if !account.contains_key(coordinates.2) { @@ -782,7 +792,7 @@ impl Component for MailView { }; } UIEvent::Action(Listing(OpenInNewTab)) => { - let mut new_tab = Self::new(self.coordinates, context); + let mut new_tab = Self::new(self.coordinates, true, context); new_tab.set_dirty(true); context .replies diff --git a/meli/src/mail/view/thread.rs b/meli/src/mail/view/thread.rs index 2ae2d492..3227759b 100644 --- a/meli/src/mail/view/thread.rs +++ b/meli/src/mail/view/thread.rs @@ -182,10 +182,9 @@ impl ThreadView { #[inline(always)] fn make_entry( i: (usize, ThreadNodeHash, usize), - account_hash: AccountHash, - mailbox_hash: MailboxHash, - msg_hash: EnvelopeHash, + (account_hash, mailbox_hash, msg_hash): (AccountHash, MailboxHash, EnvelopeHash), seen: bool, + initialize_now: bool, timestamp: UnixTimestamp, context: &mut Context, ) -> ThreadEntry { @@ -195,6 +194,7 @@ impl ThreadView { indentation: ind, mailview: Box::new(MailView::new( Some((account_hash, mailbox_hash, msg_hash)), + initialize_now, context, )), msg_hash, @@ -214,6 +214,34 @@ impl ThreadView { } let (account_hash, mailbox_hash, _) = self.coordinates; + // Find out how many entries there are going to be, and prioritize + // initialization to the open entry and the most recent ones. + // + // This helps skip initializing the whole thread at once, which will make the UI + // loading slower. + // + // This won't help at all if the latest entry is a reply to an older entry but + // oh well. + let mut total_entries = vec![]; + for (_, thread_node_hash) in threads.thread_iter(self.thread_group) { + if let Some(msg_hash) = threads.thread_nodes()[&thread_node_hash].message() { + if Some(msg_hash) == expanded_hash { + continue; + } + let env_ref = collection.get_env(msg_hash); + total_entries.push((msg_hash, env_ref.timestamp)); + }; + } + total_entries.sort_by_key(|e| std::cmp::Reverse(e.1)); + let tokens = f64::from(u32::try_from(total_entries.len()).unwrap_or(0)) * 0.29; + let tokens = tokens.ceil() as usize; + total_entries.truncate(tokens); + + // Now, only the expanded envelope plus the ones that remained in total_entries + // (around 30% of the total messages in the thread) will be scheduled + // for loading immediately. The others will be lazily loaded when the + // user opens them for reading. + let thread_iter = threads.thread_iter(self.thread_group); self.entries.clear(); let mut earliest_unread = 0; @@ -231,12 +259,29 @@ impl ThreadView { } (env_ref.is_seen(), env_ref.timestamp) }; + let initialize_now = if total_entries.is_empty() { + false + } else { + // ExtractIf but it hasn't been stabilized yet. + // https://doc.rust-lang.org/std/vec/struct.Vec.html#method.extract_if + let mut i = 0; + let mut result = false; + while i < total_entries.len() { + if total_entries[i].0 == msg_hash { + total_entries.remove(i); + result = true; + break; + } else { + i += 1; + } + } + result + }; make_entry( (ind, thread_node_hash, line), - account_hash, - mailbox_hash, - msg_hash, + (account_hash, mailbox_hash, msg_hash), is_seen, + initialize_now || expanded_hash == Some(msg_hash), timestamp, context, )