summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2022-12-09 12:30:09 +0200
committerManos Pitsidianakis <el13635@mail.ntua.gr>2022-12-09 12:30:51 +0200
commit4f45b109745ebc29febc452b9bcb0cd88f131ffc (patch)
tree02363281d477ca7784c85cb38a888baa7cd59854
parent5634f9555315deb2d39ed8fce577a35f4d535ac1 (diff)
downloadmeli-4f45b109745ebc29febc452b9bcb0cd88f131ffc.zip
mail/listing: fix tag updates not showing up right away
Closes #132 Closes #133
-rw-r--r--src/components/mail/listing/compact.rs170
-rw-r--r--src/components/mail/listing/conversations.rs111
-rw-r--r--src/components/mail/listing/plain.rs125
-rw-r--r--src/components/mail/listing/thread.rs119
4 files changed, 404 insertions, 121 deletions
diff --git a/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs
index 52387433..3ddc89c6 100644
--- a/src/components/mail/listing/compact.rs
+++ b/src/components/mail/listing/compact.rs
@@ -22,7 +22,9 @@
use super::*;
use crate::components::PageMovement;
use crate::jobs::JoinHandle;
+use indexmap::IndexSet;
use std::cmp;
+use std::collections::BTreeMap;
use std::convert::TryInto;
use std::iter::FromIterator;
@@ -329,6 +331,13 @@ impl MailListingTrait for CompactListing {
SmallVec::new(),
);
+ let tags_lck = account.collection.tag_index.read().unwrap();
+
+ let mut other_subjects = IndexSet::new();
+ let mut tags = IndexSet::new();
+ let mut from_address_list = Vec::new();
+ let mut from_address_set: std::collections::HashSet<Vec<u8>> =
+ std::collections::HashSet::new();
'items_for_loop: for thread in items {
let thread_node = &threads.thread_nodes()[&threads.thread_ref(thread).root()];
let root_env_hash = if let Some(h) = thread_node.message().or_else(|| {
@@ -374,6 +383,45 @@ impl MailListingTrait for CompactListing {
continue;
}
}
+ other_subjects.clear();
+ tags.clear();
+ from_address_list.clear();
+ from_address_set.clear();
+ for (envelope, show_subject) in threads
+ .thread_group_iter(thread)
+ .filter_map(|(_, h)| {
+ Some((
+ threads.thread_nodes()[&h].message()?,
+ threads.thread_nodes()[&h].show_subject(),
+ ))
+ })
+ .map(|(env_hash, show_subject)| {
+ (
+ context.accounts[&self.cursor_pos.0]
+ .collection
+ .get_env(env_hash),
+ show_subject,
+ )
+ })
+ {
+ if show_subject {
+ other_subjects.insert(envelope.subject().to_string());
+ }
+ if account.backend_capabilities.supports_tags {
+ for &t in envelope.tags().iter() {
+ tags.insert(t);
+ }
+ }
+
+ for addr in envelope.from().iter() {
+ if from_address_set.contains(addr.address_spec_raw()) {
+ continue;
+ }
+ from_address_set.insert(addr.address_spec_raw().to_vec());
+ from_address_list.push(addr.clone());
+ }
+ }
+
let row_attr = row_attr!(
self.color_cache,
self.length % 2 == 0,
@@ -383,7 +431,16 @@ impl MailListingTrait for CompactListing {
);
self.rows.row_attr_cache.insert(self.length, row_attr);
- let entry_strings = self.make_entry_string(&root_envelope, context, &threads, thread);
+ let entry_strings = self.make_entry_string(
+ &root_envelope,
+ context,
+ &tags_lck,
+ &from_address_list,
+ &threads,
+ &other_subjects,
+ &tags,
+ thread,
+ );
row_widths
.0
.push(digits_of_num!(self.length).try_into().unwrap_or(255));
@@ -843,18 +900,21 @@ impl CompactListing {
fn make_entry_string(
&self,
- e: &Envelope,
+ root_envelope: &Envelope,
context: &Context,
+ tags_lck: &BTreeMap<TagHash, String>,
+ from: &[Address],
threads: &Threads,
+ other_subjects: &IndexSet<String>,
+ tags: &IndexSet<TagHash>,
hash: ThreadHash,
) -> EntryStrings {
let thread = threads.thread_ref(hash);
- let mut tags = String::new();
+ let mut tags_string = String::new();
let mut colors: SmallVec<[_; 8]> = SmallVec::new();
let account = &context.accounts[&self.cursor_pos.0];
if account.backend_capabilities.supports_tags {
- let tags_lck = account.collection.tag_index.read().unwrap();
- for t in e.tags().iter() {
+ for t in tags {
if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1]
.tags
@@ -867,9 +927,9 @@ impl CompactListing {
{
continue;
}
- tags.push(' ');
- tags.push_str(tags_lck.get(t).as_ref().unwrap());
- tags.push(' ');
+ tags_string.push(' ');
+ tags_string.push_str(tags_lck.get(t).as_ref().unwrap());
+ tags_string.push(' ');
colors.push(
mailbox_settings!(context[self.cursor_pos.0][&self.cursor_pos.1].tags.colors)
.get(t)
@@ -882,22 +942,44 @@ impl CompactListing {
}),
);
}
- if !tags.is_empty() {
- tags.pop();
+ if !tags_string.is_empty() {
+ tags_string.pop();
}
}
- let mut subject = e.subject().to_string();
+ let mut subject = if *mailbox_settings!(
+ context[self.cursor_pos.0][&self.cursor_pos.1]
+ .listing
+ .thread_subject_pack
+ ) {
+ other_subjects
+ .into_iter()
+ .fold(String::new(), |mut acc, s| {
+ if !acc.is_empty() {
+ acc.push_str(", ");
+ }
+ acc.push_str(s);
+ acc
+ })
+ } else {
+ root_envelope.subject().to_string()
+ };
subject.truncate_at_boundary(150);
EntryStrings {
date: DateString(ConversationsListing::format_date(context, thread.date())),
subject: if thread.len() > 1 {
- SubjectString(format!("{} ({})", subject, thread.len(),))
+ SubjectString(format!("{} ({})", subject, thread.len()))
} else {
SubjectString(subject)
},
flag: FlagString(format!(
"{selected}{snoozed}{unseen}{attachments}{whitespace}",
- selected = if self.rows.selection.get(&e.hash()).cloned().unwrap_or(false) {
+ selected = if self
+ .rows
+ .selection
+ .get(&root_envelope.hash())
+ .cloned()
+ .unwrap_or(false)
+ {
mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1]
.listing
@@ -945,7 +1027,12 @@ impl CompactListing {
} else {
""
},
- whitespace = if self.rows.selection.get(&e.hash()).cloned().unwrap_or(false)
+ whitespace = if self
+ .rows
+ .selection
+ .get(&root_envelope.hash())
+ .cloned()
+ .unwrap_or(false)
|| thread.unseen() > 0
|| thread.snoozed()
|| thread.has_attachments()
@@ -955,8 +1042,8 @@ impl CompactListing {
""
},
)),
- from: FromString(address_list!((e.from()) as comma_sep_list)),
- tags: TagString(tags, colors),
+ from: FromString(address_list!((from) as comma_sep_list)),
+ tags: TagString(tags_string, colors),
}
}
@@ -981,6 +1068,7 @@ impl CompactListing {
* arrive */
return;
}
+ let tags_lck = account.collection.tag_index.read().unwrap();
let envelope: EnvelopeRef = account.collection.get_env(env_hash);
let thread_hash = self.rows.env_to_thread[&env_hash];
let threads = account.collection.get_threads(self.cursor_pos.1);
@@ -994,7 +1082,55 @@ impl CompactListing {
self.rows.is_thread_selected(thread_hash)
);
self.rows.row_attr_cache.insert(idx, row_attr);
- let strings = self.make_entry_string(&envelope, context, &threads, thread_hash);
+
+ let mut other_subjects = IndexSet::new();
+ let mut tags = IndexSet::new();
+ let mut from_address_list = Vec::new();
+ let mut from_address_set: std::collections::HashSet<Vec<u8>> =
+ std::collections::HashSet::new();
+ for (envelope, show_subject) in threads
+ .thread_group_iter(thread_hash)
+ .filter_map(|(_, h)| {
+ threads.thread_nodes()[&h]
+ .message()
+ .map(|env_hash| (env_hash, threads.thread_nodes()[&h].show_subject()))
+ })
+ .map(|(env_hash, show_subject)| {
+ (
+ context.accounts[&self.cursor_pos.0]
+ .collection
+ .get_env(env_hash),
+ show_subject,
+ )
+ })
+ {
+ if show_subject {
+ other_subjects.insert(envelope.subject().to_string());
+ }
+ if account.backend_capabilities.supports_tags {
+ for &t in envelope.tags().iter() {
+ tags.insert(t);
+ }
+ }
+ for addr in envelope.from().iter() {
+ if from_address_set.contains(addr.address_spec_raw()) {
+ continue;
+ }
+ from_address_set.insert(addr.address_spec_raw().to_vec());
+ from_address_list.push(addr.clone());
+ }
+ }
+
+ let strings = self.make_entry_string(
+ &envelope,
+ context,
+ &tags_lck,
+ &from_address_list,
+ &threads,
+ &other_subjects,
+ &tags,
+ thread_hash,
+ );
drop(envelope);
let columns = &mut self.data_columns.columns;
let min_width = (
diff --git a/src/components/mail/listing/conversations.rs b/src/components/mail/listing/conversations.rs
index d462d738..a014afaf 100644
--- a/src/components/mail/listing/conversations.rs
+++ b/src/components/mail/listing/conversations.rs
@@ -23,6 +23,7 @@ use super::*;
use crate::components::PageMovement;
use crate::jobs::JoinHandle;
use indexmap::IndexSet;
+use std::collections::BTreeMap;
use std::iter::FromIterator;
macro_rules! row_attr {
@@ -226,6 +227,8 @@ impl MailListingTrait for ConversationsListing {
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
+ let tags_lck = account.collection.tag_index.read().unwrap();
+
self.rows.clear();
self.length = 0;
if self.error.is_err() {
@@ -234,6 +237,7 @@ impl MailListingTrait for ConversationsListing {
let mut max_entry_columns = 0;
let mut other_subjects = IndexSet::new();
+ let mut tags = IndexSet::new();
let mut from_address_list = Vec::new();
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
std::collections::HashSet::new();
@@ -267,7 +271,23 @@ impl MailListingTrait for ConversationsListing {
panic!();
}
+ let root_envelope: &EnvelopeRef = &context.accounts[&self.cursor_pos.0]
+ .collection
+ .get_env(root_env_hash);
+ use melib::search::QueryTrait;
+ if let Some(filter_query) = mailbox_settings!(
+ context[self.cursor_pos.0][&self.cursor_pos.1]
+ .listing
+ .filter
+ )
+ .as_ref()
+ {
+ if !root_envelope.is_match(filter_query) {
+ continue;
+ }
+ }
other_subjects.clear();
+ tags.clear();
from_address_list.clear();
from_address_set.clear();
for (envelope, show_subject) in threads
@@ -290,6 +310,11 @@ impl MailListingTrait for ConversationsListing {
if show_subject {
other_subjects.insert(envelope.subject().to_string());
}
+ if account.backend_capabilities.supports_tags {
+ for &t in envelope.tags().iter() {
+ tags.insert(t);
+ }
+ }
for addr in envelope.from().iter() {
if from_address_set.contains(addr.address_spec_raw()) {
@@ -299,28 +324,15 @@ impl MailListingTrait for ConversationsListing {
from_address_list.push(addr.clone());
}
}
- let root_envelope: &EnvelopeRef = &context.accounts[&self.cursor_pos.0]
- .collection
- .get_env(root_env_hash);
- use melib::search::QueryTrait;
- if let Some(filter_query) = mailbox_settings!(
- context[self.cursor_pos.0][&self.cursor_pos.1]
- .listing
- .filter
- )
- .as_ref()
- {
- if !root_envelope.is_match(filter_query) {
- continue;
- }
- }
let strings = self.make_entry_string(
root_envelope,
context,
+ &tags_lck,
&from_address_list,
&threads,
&other_subjects,
+ &tags,
thread,
);
max_entry_columns = std::cmp::max(
@@ -628,20 +640,21 @@ impl ConversationsListing {
pub(super) fn make_entry_string(
&self,
- e: &Envelope,
+ root_envelope: &Envelope,
context: &Context,
+ tags_lck: &BTreeMap<TagHash, String>,
from: &[Address],
threads: &Threads,
other_subjects: &IndexSet<String>,
+ tags: &IndexSet<TagHash>,
hash: ThreadHash,
) -> EntryStrings {
let thread = threads.thread_ref(hash);
- let mut tags = String::new();
+ let mut tags_string = String::new();
let mut colors = SmallVec::new();
let account = &context.accounts[&self.cursor_pos.0];
if account.backend_capabilities.supports_tags {
- let tags_lck = account.collection.tag_index.read().unwrap();
- for t in e.tags().iter() {
+ for t in tags {
if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1]
.tags
@@ -654,9 +667,9 @@ impl ConversationsListing {
{
continue;
}
- tags.push(' ');
- tags.push_str(tags_lck.get(t).as_ref().unwrap());
- tags.push(' ');
+ tags_string.push(' ');
+ tags_string.push_str(tags_lck.get(t).as_ref().unwrap());
+ tags_string.push(' ');
colors.push(
mailbox_settings!(context[self.cursor_pos.0][&self.cursor_pos.1].tags.colors)
.get(t)
@@ -669,8 +682,8 @@ impl ConversationsListing {
}),
);
}
- if !tags.is_empty() {
- tags.pop();
+ if !tags_string.is_empty() {
+ tags_string.pop();
}
}
let mut subject = if *mailbox_settings!(
@@ -688,33 +701,23 @@ impl ConversationsListing {
acc
})
} else {
- e.subject().to_string()
+ root_envelope.subject().to_string()
};
subject.truncate_at_boundary(100);
- if thread.len() > 1 {
- EntryStrings {
- date: DateString(ConversationsListing::format_date(context, thread.date())),
- subject: SubjectString(format!("{} ({})", subject, thread.len())),
- flag: FlagString(format!(
- "{}{}",
- if thread.has_attachments() { "📎" } else { "" },
- if thread.snoozed() { "💤" } else { "" }
- )),
- from: FromString(address_list!((from) as comma_sep_list)),
- tags: TagString(tags, colors),
- }
- } else {
- EntryStrings {
- date: DateString(ConversationsListing::format_date(context, thread.date())),
- subject: SubjectString(subject),
- flag: FlagString(format!(
- "{}{}",
- if thread.has_attachments() { "📎" } else { "" },
- if thread.snoozed() { "💤" } else { "" }
- )),
- from: FromString(address_list!((from) as comma_sep_list)),
- tags: TagString(tags, colors),
- }
+ EntryStrings {
+ date: DateString(ConversationsListing::format_date(context, thread.date())),
+ subject: SubjectString(if thread.len() > 1 {
+ format!("{} ({})", subject, thread.len())
+ } else {
+ subject
+ }),
+ flag: FlagString(format!(
+ "{}{}",
+ if thread.has_attachments() { "📎" } else { "" },
+ if thread.snoozed() { "💤" } else { "" }
+ )),
+ from: FromString(address_list!((from) as comma_sep_list)),
+ tags: TagString(tags_string, colors),
}
}
@@ -768,9 +771,11 @@ impl ConversationsListing {
let account = &context.accounts[&self.cursor_pos.0];
let thread_hash = self.rows.env_to_thread[&env_hash];
let threads = account.collection.get_threads(self.cursor_pos.1);
+ let tags_lck = account.collection.tag_index.read().unwrap();
let idx: usize = self.rows.thread_order[&thread_hash];
let mut other_subjects = IndexSet::new();
+ let mut tags = IndexSet::new();
let mut from_address_list = Vec::new();
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
std::collections::HashSet::new();
@@ -793,6 +798,11 @@ impl ConversationsListing {
if show_subject {
other_subjects.insert(envelope.subject().to_string());
}
+ if account.backend_capabilities.supports_tags {
+ for &t in envelope.tags().iter() {
+ tags.insert(t);
+ }
+ }
for addr in envelope.from().iter() {
if from_address_set.contains(addr.address_spec_raw()) {
continue;
@@ -805,9 +815,11 @@ impl ConversationsListing {
let strings = self.make_entry_string(
&envelope,
context,
+ &tags_lck,
&from_address_list,
&threads,
&other_subjects,
+ &tags,
thread_hash,
);
drop(envelope);
@@ -819,6 +831,7 @@ impl ConversationsListing {
fn draw_rows(&self, grid: &mut CellBuffer, area: Area, context: &Context, top_idx: usize) {
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
+ clear_area(grid, area, self.color_cache.theme_default);
let (mut upper_left, bottom_right) = area;
for (idx, ((thread_hash, root_env_hash), strings)) in
self.rows.entries.iter().enumerate().skip(top_idx)
diff --git a/src/components/mail/listing/plain.rs b/src/components/mail/listing/plain.rs
index 1d28f389..44eef4f1 100644
--- a/src/components/mail/listing/plain.rs
+++ b/src/components/mail/listing/plain.rs
@@ -968,6 +968,130 @@ impl PlainListing {
_ => melib::datetime::timestamp_to_string(envelope.datetime(), None, false),
}
}
+
+ fn update_line(&mut self, context: &Context, env_hash: EnvelopeHash) {
+ let account = &context.accounts[&self.cursor_pos.0];
+
+ if !account.contains_key(env_hash) {
+ /* The envelope has been renamed or removed, so wait for the appropriate event to
+ * arrive */
+ return;
+ }
+ let envelope: EnvelopeRef = account.collection.get_env(env_hash);
+ let thread_hash = self.rows.env_to_thread[&env_hash];
+ let idx = self.rows.env_order[&env_hash];
+ let row_attr = row_attr!(
+ self.color_cache,
+ idx % 2 == 0,
+ !envelope.is_seen(),
+ false,
+ self.rows.selection[&env_hash]
+ );
+ self.rows.row_attr_cache.insert(idx, row_attr);
+
+ let strings = self.make_entry_string(&envelope, context);
+ drop(envelope);
+ let columns = &mut self.data_columns.columns;
+ let min_width = (
+ columns[0].size().0,
+ columns[1].size().0,
+ columns[2].size().0,
+ columns[3].size().0,
+ );
+
+ clear_area(&mut columns[0], ((0, idx), (min_width.0, idx)), row_attr);
+ clear_area(&mut columns[1], ((0, idx), (min_width.1, idx)), row_attr);
+ clear_area(&mut columns[2], ((0, idx), (min_width.2, idx)), row_attr);
+ clear_area(&mut columns[3], ((0, idx), (min_width.3, idx)), row_attr);
+
+ let (x, _) = write_string_to_grid(
+ &idx.to_string(),
+ &mut columns[0],
+ row_attr.fg,
+ row_attr.bg,
+ row_attr.attrs,
+ ((0, idx), (min_width.0, idx)),
+ None,
+ );
+ for c in columns[0].row_iter(x..min_width.0, idx) {
+ columns[0][c].set_bg(row_attr.bg).set_attrs(row_attr.attrs);
+ }
+ let (x, _) = write_string_to_grid(
+ &strings.date,
+ &mut columns[1],
+ row_attr.fg,
+ row_attr.bg,
+ row_attr.attrs,
+ ((0, idx), (min_width.1, idx)),
+ None,
+ );
+ for c in columns[1].row_iter(x..min_width.1, idx) {
+ columns[1][c].set_bg(row_attr.bg).set_attrs(row_attr.attrs);
+ }
+ let (x, _) = write_string_to_grid(
+ &strings.from,
+ &mut columns[2],
+ row_attr.fg,
+ row_attr.bg,
+ row_attr.attrs,
+ ((0, idx), (min_width.2, idx)),
+ None,
+ );
+ for c in columns[2].row_iter(x..min_width.2, idx) {
+ columns[2][c].set_bg(row_attr.bg).set_attrs(row_attr.attrs);
+ }
+ let (x, _) = write_string_to_grid(
+ &strings.flag,
+ &mut columns[3],
+ row_attr.fg,
+ row_attr.bg,
+ row_attr.attrs,
+ ((0, idx), (min_width.3, idx)),
+ None,
+ );
+ let (x, _) = write_string_to_grid(
+ &strings.subject,
+ &mut columns[3],
+ row_attr.fg,
+ row_attr.bg,
+ row_attr.attrs,
+ ((x, idx), (min_width.3, idx)),
+ None,
+ );
+ let x = {
+ let mut x = x + 1;
+ for (t, &color) in strings.tags.split_whitespace().zip(strings.tags.1.iter()) {
+ let color = color.unwrap_or(self.color_cache.tag_default.bg);
+ let (_x, _) = write_string_to_grid(
+ t,
+ &mut columns[3],
+ self.color_cache.tag_default.fg,
+ color,
+ self.color_cache.tag_default.attrs,
+ ((x + 1, idx), (min_width.3, idx)),
+ None,
+ );
+ for c in columns[3].row_iter(x..(x + 1), idx) {
+ columns[3][c].set_bg(color);
+ }
+ for c in columns[3].row_iter(_x..(_x + 1), idx) {
+ columns[3][c].set_bg(color).set_keep_bg(true);
+ }
+ for c in columns[3].row_iter((x + 1)..(_x + 1), idx) {
+ columns[3][c].set_keep_fg(true).set_keep_bg(true);
+ }
+ for c in columns[3].row_iter(x..(x + 1), idx) {
+ columns[3][c].set_keep_bg(true);
+ }
+ x = _x + 1;
+ }
+ x
+ };
+ for c in columns[3].row_iter(x..min_width.3, idx) {
+ columns[3][c].set_bg(row_attr.bg).set_attrs(row_attr.attrs);
+ }
+ *self.rows.entries.get_mut(idx).unwrap() = ((thread_hash, env_hash), strings);
+ }
}
impl Component for PlainListing {
@@ -1181,6 +1305,7 @@ impl Component for PlainListing {
if !self.rows.row_updates.is_empty() {
while let Some(env_hash) = self.rows.row_updates.pop() {
+ self.update_line(context, env_hash);
let row: usize = self.rows.env_order[&env_hash];
let envelope: EnvelopeRef = context.accounts[&self.cursor_pos.0]
.collection
diff --git a/src/components/mail/listing/thread.rs b/src/components/mail/listing/thread.rs
index 89b641c7..3d9eb8b0 100644
--- a/src/components/mail/listing/thread.rs
+++ b/src/components/mail/listing/thread.rs
@@ -122,10 +122,10 @@ pub struct ThreadListing {
)>,
data_columns: DataColumns<5>,
- rows_drawn: SegmentTree,
rows: RowsState<(ThreadHash, EnvelopeHash)>,
/// If we must redraw on next redraw event
dirty: bool,
+ force_draw: bool,
/// If `self.view` is focused or not.
focus: Focus,
initialised: bool,
@@ -408,12 +408,6 @@ impl MailListingTrait for ThreadListing {
CellBuffer::new_with_context(min_width.4, self.rows.len(), None, context);
self.data_columns.segment_tree[4] = row_widths.4.into();
- self.rows_drawn = SegmentTree::from(
- std::iter::repeat(1)
- .take(self.rows.len())
- .collect::<SmallVec<_>>(),
- );
- debug_assert!(self.rows_drawn.array.len() == self.rows.len());
self.draw_rows(
context,
0,
@@ -490,11 +484,6 @@ impl ListingTrait for ThreadListing {
let page_no = (self.new_cursor_pos.2).wrapping_div(rows);
let top_idx = page_no * rows;
- self.draw_rows(
- context,
- top_idx,
- cmp::min(self.length.saturating_sub(1), top_idx + rows - 1),
- );
/* If cursor position has changed, remove the highlight from the previous position and
* apply it in the new one. */
@@ -516,7 +505,9 @@ impl ListingTrait for ThreadListing {
}
context.dirty_areas.push_back(new_area);
}
- return;
+ if !self.force_draw {
+ return;
+ }
} else if self.cursor_pos != self.new_cursor_pos {
self.cursor_pos = self.new_cursor_pos;
}
@@ -526,20 +517,16 @@ impl ListingTrait for ThreadListing {
self.new_cursor_pos.2 = self.length - 1;
self.cursor_pos.2 = self.new_cursor_pos.2;
}
+ self.draw_rows(
+ context,
+ top_idx,
+ cmp::min(self.length.saturating_sub(1), top_idx + rows - 1),
+ );
_ = self
.data_columns
.recalc_widths((width!(area), height!(area)), top_idx);
clear_area(grid, area, self.color_cache.theme_default);
- /* Page_no has changed, so draw new page */
- self.data_columns
- .draw(grid, top_idx, self.cursor_pos.2, grid.bounds_iter(area));
-
- /* Page_no has changed, so draw new page */
- _ = self
- .data_columns
- .recalc_widths((width!(area), height!(area)), top_idx);
- clear_area(grid, area, self.color_cache.theme_default);
/* copy table columns */
self.data_columns
.draw(grid, top_idx, self.cursor_pos.2, grid.bounds_iter(area));
@@ -650,11 +637,11 @@ impl ListingTrait for ThreadListing {
/* If self.rows.row_updates is not empty and we exit a thread, the row_update events
* will be performed but the list will not be drawn. So force a draw in any case.
* */
- // self.force_draw = true;
+ self.force_draw = true;
}
Focus::Entry => {
if let Some(env_hash) = self.get_env_under_cursor(self.cursor_pos.2) {
- // self.force_draw = true;
+ self.force_draw = true;
self.dirty = true;
let coordinates = (self.cursor_pos.0, self.cursor_pos.1, env_hash);
@@ -699,9 +686,9 @@ impl ThreadListing {
subsort: (Default::default(), Default::default()),
color_cache: ColorCache::default(),
data_columns: DataColumns::default(),
- rows_drawn: SegmentTree::default(),
rows: RowsState::default(),
dirty: true,
+ force_draw: true,
focus: Focus::None,
view: None,
initialised: false,
@@ -840,14 +827,7 @@ impl ThreadListing {
return;
}
debug_assert!(end >= start);
- if self.rows_drawn.get_max(start, end) == 0 {
- //debug!("not drawing {}-{}", start, end);
- return;
- }
//debug!("drawing {}-{}", start, end);
- for i in start..=end {
- self.rows_drawn.update(i, 0);
- }
let min_width = (
self.data_columns.columns[0].size().0,
self.data_columns.columns[1].size().0,
@@ -997,6 +977,50 @@ impl ThreadListing {
}
}
}
+
+ fn update_line(&mut self, context: &Context, env_hash: EnvelopeHash) {
+ let account = &context.accounts[&self.cursor_pos.0];
+
+ if !account.contains_key(env_hash) {
+ /* The envelope has been renamed or removed, so wait for the appropriate event to
+ * arrive */
+ return;
+ }
+ let envelope: EnvelopeRef = account.collection.get_env(env_hash);
+ let thread_hash = self.rows.env_to_thread[&env_hash];
+ let idx = self.rows.env_order[&env_hash];
+ let row_attr = row_attr!(
+ self.color_cache,
+ idx % 2 == 0,
+ !envelope.is_seen(),
+ false,
+ self.rows.selection[&env_hash]
+ );
+ self.rows.row_attr_cache.insert(idx, row_attr);
+
+ let mut strings = self.make_entry_string(&envelope, context);
+ drop(envelope);
+ std::mem::swap(
+ &mut self.rows.entries.get_mut(idx).unwrap().1.subject,
+ &mut strings.subject,
+ );
+ let columns = &mut self.data_columns.columns;
+ let min_width = (
+ columns[0].size().0,
+ columns[1].size().0,
+ columns[2].size().0,
+ columns[3].size().0,
+ columns[4].size().0,
+ );
+
+ clear_area(&mut columns[0], ((0, idx), (min_width.0, idx)), row_attr);
+ clear_area(&mut columns[1], ((0, idx), (min_width.1, idx)), row_attr);
+ clear_area(&mut columns[2], ((0, idx), (min_width.2, idx)), row_attr);
+ clear_area(&mut columns[3], ((0, idx), (min_width.3, idx)), row_attr);
+ clear_area(&mut columns[4], ((0, idx), (min_width.4, idx)), row_attr);
+
+ *self.rows.entries.get_mut(idx).unwrap() = ((thread_hash, env_hash), strings);
+ }
}
impl Component for ThreadListing {
@@ -1161,7 +1185,7 @@ impl Component for ThreadListing {
}
}
}
- //self.force_draw = true;
+ self.force_draw = true;
}
if !self.rows.row_updates.is_empty() {
@@ -1169,30 +1193,15 @@ impl Component for ThreadListing {
let top_idx = page_no * rows;
while let Some(env_hash) = self.rows.row_updates.pop() {
+ self.update_line(context, env_hash);
let row: usize = self.rows.env_order[&env_hash];
- if row >= top_idx && row <= top_idx + rows {
- let new_area = nth_row_area(area, row % rows);
- self.data_columns.draw(
- grid,
- row,
- self.cursor_pos.2,
- grid.bounds_iter(new_area),
- );
- let envelope: EnvelopeRef = context.accounts[&self.cursor_pos.0]
- .collection
- .get_env(env_hash);
- let row_attr = row_attr!(
- self.color_cache,
- row % 2 == 0,
- !envelope.is_seen(),
- false,
- self.rows.selection[&env_hash]
- );
- self.rows.row_attr_cache.insert(row, row_attr);
- change_colors(grid, new_area, row_attr.fg, row_attr.bg);
- context.dirty_areas.push_back(new_area);
- }
+ self.force_draw |= row >= top_idx && row < top_idx + rows;
+ }
+ if self.force_draw {
+ /* Draw the entire list */
+ self.draw_list(grid, area, context);
+ self.force_draw = false;
}
}