summaryrefslogtreecommitdiffstats
path: root/ui/src/components
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2020-01-18 01:48:29 +0200
committerManos Pitsidianakis <el13635@mail.ntua.gr>2020-01-20 16:03:06 +0200
commit47a69f8eb9c62cfc6b3e58002a2a978a6a16acdc (patch)
tree2929282b09cf69e423623d7b473d810d3294f930 /ui/src/components
parent20f86f2741cb1d78c983b723cfc5f927846e7354 (diff)
melib: add ThreadGroup
Instead of using Union/Find to gather mail that belongs in the same e-mail thread together, add a new entity ThreadGroup that ThreadNodes point to. ThreadGroup represents an actual Thread: A thread root ThreadGroup::Group or a reply ThreadGroup::Node. To make semantics more accurate: - ThreadNode hash should be renamed to ThreadNodeHash - ThreadGroupHash should be renamed to ThreadHash - ThreadGroup::Group should be a struct named Thread instead - move ThreadGroup::Node logic to ThreadNode akin to Union/Find - rename ThreaddGroup::Group to Thread
Diffstat (limited to 'ui/src/components')
-rw-r--r--ui/src/components/mail/compose.rs51
-rw-r--r--ui/src/components/mail/listing.rs39
-rw-r--r--ui/src/components/mail/listing/compact.rs249
-rw-r--r--ui/src/components/mail/listing/conversations.rs291
-rw-r--r--ui/src/components/mail/listing/plain.rs9
-rw-r--r--ui/src/components/mail/listing/thread.rs6
-rw-r--r--ui/src/components/mail/view.rs12
-rw-r--r--ui/src/components/mail/view/thread.rs19
8 files changed, 253 insertions, 423 deletions
diff --git a/ui/src/components/mail/compose.rs b/ui/src/components/mail/compose.rs
index 0c3a42ad..19790f4c 100644
--- a/ui/src/components/mail/compose.rs
+++ b/ui/src/components/mail/compose.rs
@@ -63,7 +63,7 @@ impl std::ops::DerefMut for EmbedStatus {
#[derive(Debug)]
pub struct Composer {
- reply_context: Option<(usize, usize)>, // (folder_index, thread_node_index)
+ reply_context: Option<(FolderHash, EnvelopeHash)>,
account_cursor: usize,
cursor: Cursor,
@@ -148,11 +148,7 @@ impl Composer {
..Default::default()
}
}
- /*
- * coordinates: (account index, mailbox index, root set thread_node index)
- * msg: index of message we reply to in thread_nodes
- * context: current context
- */
+
pub fn edit(account_pos: usize, h: EnvelopeHash, context: &Context) -> Result<Self> {
let mut ret = Composer::default();
let op = context.accounts[account_pos].operation(h);
@@ -163,18 +159,15 @@ impl Composer {
ret.account_cursor = account_pos;
Ok(ret)
}
+
pub fn with_context(
- coordinates: (usize, usize, usize),
- msg: ThreadHash,
+ coordinates: (usize, FolderHash),
+ msg: EnvelopeHash,
context: &Context,
) -> Self {
let account = &context.accounts[coordinates.0];
- let mailbox = &account[coordinates.1].unwrap();
- let threads = &account.collection.threads[&mailbox.folder.hash()];
- let thread_nodes = &threads.thread_nodes();
let mut ret = Composer::default();
- let p = &thread_nodes[&msg];
- let parent_message = account.collection.get_env(p.message().unwrap());
+ let parent_message = account.collection.get_env(msg);
/* If message is from a mailing list and we detect a List-Post header, ask user if they
* want to reply to the mailing list or the submitter of the message */
if let Some(actions) = list_management::ListActions::detect(&parent_message) {
@@ -202,32 +195,22 @@ impl Composer {
}
}
- let mut op = account.operation(parent_message.hash());
+ let mut op = account.operation(msg);
let parent_bytes = op.as_bytes();
ret.draft = Draft::new_reply(&parent_message, parent_bytes.unwrap());
+ let subject = parent_message.subject();
ret.draft.headers_mut().insert(
"Subject".into(),
- if p.show_subject() {
- format!(
- "Re: {}",
- account
- .collection
- .get_env(p.message().unwrap())
- .subject()
- .clone()
- )
+ if !subject.starts_with("Re: ") {
+ format!("Re: {}", subject)
} else {
- account
- .collection
- .get_env(p.message().unwrap())
- .subject()
- .into()
+ subject.into()
},
);
ret.account_cursor = coordinates.0;
- ret.reply_context = Some((coordinates.1, coordinates.2));
+ ret.reply_context = Some((coordinates.1, msg));
ret
}
@@ -553,13 +536,13 @@ impl Component for Composer {
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
let shortcuts = self.get_shortcuts(context);
- match (&mut self.mode, &mut self.reply_context, &event) {
- (ViewMode::Edit, _, _) => {
+ match (&mut self.mode, &event) {
+ (ViewMode::Edit, _) => {
if self.pager.process_event(event, context) {
return true;
}
}
- (ViewMode::Send(ref mut selector), _, _) => {
+ (ViewMode::Send(ref mut selector), _) => {
if selector.process_event(event, context) {
if selector.is_done() {
let s = match std::mem::replace(&mut self.mode, ViewMode::Edit) {
@@ -594,7 +577,7 @@ impl Component for Composer {
return true;
}
}
- (ViewMode::SelectRecipients(ref mut selector), _, _) => {
+ (ViewMode::SelectRecipients(ref mut selector), _) => {
if selector.process_event(event, context) {
if selector.is_done() {
let s = match std::mem::replace(&mut self.mode, ViewMode::Edit) {
@@ -615,7 +598,7 @@ impl Component for Composer {
return true;
}
}
- (ViewMode::Discard(_, ref mut selector), _, _) => {
+ (ViewMode::Discard(_, ref mut selector), _) => {
if selector.process_event(event, context) {
if selector.is_done() {
let (u, s) = match std::mem::replace(&mut self.mode, ViewMode::Edit) {
diff --git a/ui/src/components/mail/listing.rs b/ui/src/components/mail/listing.rs
index 67c38233..e8663621 100644
--- a/ui/src/components/mail/listing.rs
+++ b/ui/src/components/mail/listing.rs
@@ -53,37 +53,18 @@ pub trait MailListingTrait: ListingTrait {
fn perform_action(
&mut self,
context: &mut Context,
- thread_hash: ThreadHash,
+ thread_hash: ThreadGroupHash,
a: &ListingAction,
) {
let account = &mut context.accounts[self.coordinates().0];
let mut envs_to_set: SmallVec<[EnvelopeHash; 8]> = SmallVec::new();
let folder_hash = account[self.coordinates().1].unwrap().folder.hash();
- {
- let mut stack: SmallVec<[ThreadHash; 8]> = SmallVec::new();
- stack.push(thread_hash);
- while let Some(thread_iter) = stack.pop() {
- {
- let threads = account.collection.threads.get_mut(&folder_hash).unwrap();
- threads
- .thread_nodes
- .entry(thread_iter)
- .and_modify(|t| t.set_has_unseen(false));
- }
- let threads = &account.collection.threads[&folder_hash];
- if let Some(env_hash) = threads[&thread_iter].message() {
- if !account.contains_key(env_hash) {
- /* The envelope has been renamed or removed, so wait for the appropriate event to
- * arrive */
- continue;
- }
- envs_to_set.push(env_hash);
- }
- for c in 0..threads[&thread_iter].children().len() {
- let c = threads[&thread_iter].children()[c];
- stack.push(c);
- }
- }
+ for (_, h) in account.collection.threads[&folder_hash].thread_group_iter(thread_hash) {
+ envs_to_set.push(
+ account.collection.threads[&folder_hash].thread_nodes()[&h]
+ .message()
+ .unwrap(),
+ );
}
for env_hash in envs_to_set {
let op = account.operation(env_hash);
@@ -139,9 +120,9 @@ pub trait MailListingTrait: ListingTrait {
}
}
- fn row_updates(&mut self) -> &mut SmallVec<[ThreadHash; 8]>;
- fn get_focused_items(&self, _context: &Context) -> SmallVec<[ThreadHash; 8]>;
- fn redraw_list(&mut self, context: &Context, items: Box<dyn Iterator<Item = ThreadHash>>) {
+ fn row_updates(&mut self) -> &mut SmallVec<[ThreadGroupHash; 8]>;
+ fn get_focused_items(&self, _context: &Context) -> SmallVec<[ThreadGroupHash; 8]>;
+ fn redraw_list(&mut self, context: &Context, items: Box<dyn Iterator<Item = ThreadGroupHash>>) {
unimplemented!()
}
}
diff --git a/ui/src/components/mail/listing/compact.rs b/ui/src/components/mail/listing/compact.rs
index 72d7713b..90a607e8 100644
--- a/ui/src/components/mail/listing/compact.rs
+++ b/ui/src/components/mail/listing/compact.rs
@@ -54,33 +54,33 @@ pub struct CompactListing {
length: usize,
sort: (SortField, SortOrder),
subsort: (SortField, SortOrder),
- all_threads: fnv::FnvHashSet<ThreadHash>,
- order: FnvHashMap<ThreadHash, usize>,
+ all_threads: fnv::FnvHashSet<ThreadGroupHash>,
+ order: FnvHashMap<ThreadGroupHash, usize>,
/// Cache current view.
data_columns: DataColumns,
filter_term: String,
- filtered_selection: Vec<ThreadHash>,
- filtered_order: FnvHashMap<ThreadHash, usize>,
- selection: FnvHashMap<ThreadHash, bool>,
+ filtered_selection: Vec<ThreadGroupHash>,
+ filtered_order: FnvHashMap<ThreadGroupHash, usize>,
+ selection: FnvHashMap<ThreadGroupHash, bool>,
/// If we must redraw on next redraw event
dirty: bool,
force_draw: bool,
/// If `self.view` exists or not.
unfocused: bool,
view: ThreadView,
- row_updates: SmallVec<[ThreadHash; 8]>,
+ row_updates: SmallVec<[ThreadGroupHash; 8]>,
movement: Option<PageMovement>,
id: ComponentId,
}
impl MailListingTrait for CompactListing {
- fn row_updates(&mut self) -> &mut SmallVec<[ThreadHash; 8]> {
+ fn row_updates(&mut self) -> &mut SmallVec<[ThreadGroupHash; 8]> {
&mut self.row_updates
}
- fn get_focused_items(&self, context: &Context) -> SmallVec<[ThreadHash; 8]> {
+ fn get_focused_items(&self, context: &Context) -> SmallVec<[ThreadGroupHash; 8]> {
let is_selection_empty = self.selection.values().cloned().any(std::convert::identity);
let i = [self.get_thread_under_cursor(self.cursor_pos.2, context)];
let cursor_iter;
@@ -118,14 +118,13 @@ impl ListingTrait for CompactListing {
if self.length == 0 {
return;
}
- let i = self.get_thread_under_cursor(idx, context);
+ let thread = self.get_thread_under_cursor(idx, context);
let account = &context.accounts[self.cursor_pos.0];
let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash();
let threads = &account.collection.threads[&folder_hash];
- let thread_node = &threads.thread_nodes[&i];
- let fg_color = if thread_node.has_unseen() {
+ let fg_color = if threads.groups[&thread].unseen() > 0 {
Color::Byte(0)
} else {
Color::Default
@@ -133,9 +132,9 @@ impl ListingTrait for CompactListing {
let bg_color = if context.settings.terminal.theme == "light" {
if self.cursor_pos.2 == idx {
Color::Byte(244)
- } else if self.selection[&i] {
+ } else if self.selection[&thread] {
Color::Byte(210)
- } else if thread_node.has_unseen() {
+ } else if threads.groups[&thread].unseen() > 0 {
Color::Byte(251)
} else if idx % 2 == 0 {
Color::Byte(252)
@@ -145,9 +144,9 @@ impl ListingTrait for CompactListing {
} else {
if self.cursor_pos.2 == idx {
Color::Byte(246)
- } else if self.selection[&i] {
+ } else if self.selection[&thread] {
Color::Byte(210)
- } else if thread_node.has_unseen() {
+ } else if threads.groups[&thread].unseen() > 0 {
Color::Byte(251)
} else if idx % 2 == 0 {
Color::Byte(236)
@@ -444,21 +443,19 @@ impl ListingTrait for CompactListing {
if !threads.thread_nodes.contains_key(&env_hash_thread_hash) {
continue;
}
- let thread_group = melib::find_root_hash(
- &threads.thread_nodes,
- threads.thread_nodes[&env_hash_thread_hash].thread_group(),
- );
- if self.filtered_order.contains_key(&thread_group) {
+ let thread =
+ threads.find_group(threads.thread_nodes[&env_hash_thread_hash].group);
+ if self.filtered_order.contains_key(&thread) {
continue;
}
- if self.all_threads.contains(&thread_group) {
- self.filtered_selection.push(thread_group);
+ if self.all_threads.contains(&thread) {
+ self.filtered_selection.push(thread);
self.filtered_order
- .insert(thread_group, self.filtered_selection.len() - 1);
+ .insert(thread, self.filtered_selection.len() - 1);
}
}
if !self.filtered_selection.is_empty() {
- threads.vec_inner_sort_by(
+ threads.group_inner_sort_by(
&mut self.filtered_selection,
self.sort,
&context.accounts[self.cursor_pos.0].collection.envelopes,
@@ -472,7 +469,7 @@ impl ListingTrait for CompactListing {
self.redraw_list(
context,
Box::new(self.filtered_selection.clone().into_iter())
- as Box<dyn Iterator<Item = ThreadHash>>,
+ as Box<dyn Iterator<Item = ThreadGroupHash>>,
);
}
Err(e) => {
@@ -550,12 +547,9 @@ impl CompactListing {
e: &Envelope,
context: &Context,
threads: &Threads,
- hash: ThreadHash,
+ hash: ThreadGroupHash,
) -> EntryStrings {
- let is_snoozed: bool = threads.is_snoozed(hash);
- let date =
- threads.thread_dates[&melib::thread::find_thread_group(threads.thread_nodes(), hash)];
- let thread_node = &threads[&hash];
+ let thread = &threads.groups[&hash];
let folder_hash = &context.accounts[self.cursor_pos.0][self.cursor_pos.1]
.unwrap()
.folder
@@ -597,26 +591,26 @@ impl CompactListing {
}
let mut subject = e.subject().to_string();
subject.truncate_at_boundary(150);
- if thread_node.len() > 0 {
+ if thread.len() > 1 {
EntryStrings {
- date: DateString(ConversationsListing::format_date(context, date)),
- subject: SubjectString(format!("{} ({})", subject, thread_node.len(),)),
+ date: DateString(ConversationsListing::format_date(context, thread.date())),
+ subject: SubjectString(format!("{} ({})", subject, thread.len(),)),
flag: FlagString(format!(
"{}{}",
if e.has_attachments() { "📎" } else { "" },
- if is_snoozed { "💤" } else { "" }
+ if thread.snoozed() { "💤" } else { "" }
)),
from: FromString(address_list!((e.from()) as comma_sep_list)),
tags: TagString(tags, colors),
}
} else {
EntryStrings {
- date: DateString(ConversationsListing::format_date(context, date)),
+ date: DateString(ConversationsListing::format_date(context, thread.date())),
subject: SubjectString(subject),
flag: FlagString(format!(
"{}{}",
if e.has_attachments() { "📎" } else { "" },
- if is_snoozed { "💤" } else { "" }
+ if thread.snoozed() { "💤" } else { "" }
)),
from: FromString(address_list!((e.from()) as comma_sep_list)),
tags: TagString(tags, colors),
@@ -669,28 +663,31 @@ impl CompactListing {
return;
}
}
- if old_cursor_pos == self.new_cursor_pos {
- self.view.update(context);
- } else if self.unfocused {
- self.view = ThreadView::new(self.new_cursor_pos, None, context);
- }
let threads = &context.accounts[self.cursor_pos.0].collection.threads[&folder_hash];
- threads.sort_by(
+ self.all_threads.clear();
+ let mut roots = threads.roots();
+ threads.group_inner_sort_by(
+ &mut roots,
self.sort,
- self.subsort,
&context.accounts[self.cursor_pos.0].collection.envelopes,
);
- self.all_threads.clear();
self.redraw_list(
context,
- Box::new(threads.root_iter().collect::<Vec<ThreadHash>>().into_iter())
- as Box<dyn Iterator<Item = ThreadHash>>,
+ Box::new(roots.into_iter()) as Box<dyn Iterator<Item = ThreadGroupHash>>,
);
+
+ if old_cursor_pos == self.new_cursor_pos {
+ self.view.update(context);
+ } else if self.unfocused {
+ let thread = self.get_thread_under_cursor(self.cursor_pos.2, context);
+
+ self.view = ThreadView::new(self.new_cursor_pos, thread, None, context);
+ }
}
- fn redraw_list(&mut self, context: &Context, items: Box<dyn Iterator<Item = ThreadHash>>) {
+ fn redraw_list(&mut self, context: &Context, items: Box<dyn Iterator<Item = ThreadGroupHash>>) {
let account = &context.accounts[self.cursor_pos.0];
let mailbox = &account[self.cursor_pos.1].unwrap();
@@ -714,18 +711,19 @@ impl CompactListing {
SmallVec::new(),
);
- for (idx, root_idx) in items.enumerate() {
+ for (idx, thread) in items.enumerate() {
+ debug!(thread);
self.length += 1;
- let thread_node = &threads.thread_nodes()[&root_idx];
- let i = thread_node.message().unwrap_or_else(|| {
+ let thread_node = &threads.thread_nodes()[&threads.groups[&thread].root().unwrap()];
+ let root_env_hash = thread_node.message().unwrap_or_else(|| {
let mut iter_ptr = thread_node.children()[0];
while threads.thread_nodes()[&iter_ptr].message().is_none() {
iter_ptr = threads.thread_nodes()[&iter_ptr].children()[0];
}
threads.thread_nodes()[&iter_ptr].message().unwrap()
});
- if !context.accounts[self.cursor_pos.0].contains_key(i) {
- debug!("key = {}", i);
+ if !context.accounts[self.cursor_pos.0].contains_key(root_env_hash) {
+ debug!("key = {}", root_env_hash);
debug!(
"name = {} {}",
mailbox.name(),
@@ -735,10 +733,11 @@ impl CompactListing {
panic!();
}
- let root_envelope: EnvelopeRef =
- context.accounts[self.cursor_pos.0].collection.get_env(i);
+ let root_envelope: EnvelopeRef = context.accounts[self.cursor_pos.0]
+ .collection
+ .get_env(root_env_hash);
- let entry_strings = self.make_entry_string(&root_envelope, context, threads, root_idx);
+ let entry_strings = self.make_entry_string(&root_envelope, context, threads, thread);
row_widths.1.push(
entry_strings
.date
@@ -772,11 +771,11 @@ impl CompactListing {
min_width.4,
entry_strings.subject.grapheme_width() + 1 + entry_strings.tags.grapheme_width(),
); /* subject */
- rows.push(((idx, root_idx), entry_strings));
- self.all_threads.insert(root_idx);
+ rows.push(((idx, (thread, root_env_hash)), entry_strings));
+ self.all_threads.insert(thread);
- self.order.insert(root_idx, idx);
- self.selection.insert(root_idx, false);
+ self.order.insert(thread, idx);
+ self.selection.insert(thread, false);
}
min_width.0 = self.length.saturating_sub(1).to_string().len();
@@ -800,17 +799,9 @@ impl CompactListing {
CellBuffer::new_with_context(min_width.4, rows.len(), Cell::with_char(' '), context);
self.data_columns.segment_tree[4] = row_widths.4.into();
- for ((idx, root_idx), strings) in rows {
- let thread_node = &threads.thread_nodes()[&root_idx];
- let i = thread_node.message().unwrap_or_else(|| {
- let mut iter_ptr = thread_node.children()[0];
- while threads.thread_nodes()[&iter_ptr].message().is_none() {
- iter_ptr = threads.thread_nodes()[&iter_ptr].children()[0];
- }
- threads.thread_nodes()[&iter_ptr].message().unwrap()
- });
- if !context.accounts[self.cursor_pos.0].contains_key(i) {
- //debug!("key = {}", i);
+ for ((idx, (thread, root_env_hash)), strings) in rows {
+ if !context.accounts[self.cursor_pos.0].contains_key(root_env_hash) {
+ //debug!("key = {}", root_env_hash);
//debug!(
// "name = {} {}",
// mailbox.name(),
@@ -820,13 +811,13 @@ impl CompactListing {
panic!();
}
- let fg_color = if thread_node.has_unseen() {
+ let fg_color = if threads.groups[&thread].unseen() > 0 {
Color::Byte(0)
} else {
Color::Default
};
let bg_color = if context.settings.terminal.theme == "light" {
- if thread_node.has_unseen() {
+ if threads.groups[&thread].unseen() > 0 {
Color::Byte(251)
} else if idx % 2 == 0 {
Color::Byte(252)
@@ -834,7 +825,7 @@ impl CompactListing {
Color::Default
}
} else {
- if thread_node.has_unseen() {
+ if threads.groups[&thread].unseen() > 0 {
Color::Byte(251)
} else if idx % 2 == 0 {
Color::Byte(236)
@@ -930,10 +921,10 @@ impl CompactListing {
self.data_columns.columns[4][(x, idx)].set_bg(bg_color);
}
match (
- threads.is_snoozed(root_idx),
+ threads.groups[&thread].snoozed(),
context.accounts[self.cursor_pos.0]
.collection
- .get_env(i)
+ .get_env(root_env_hash)
.has_attachments(),
) {
(true, true) => {
@@ -970,7 +961,7 @@ impl CompactListing {
}
}
- fn get_thread_under_cursor(&self, cursor: usize, context: &Context) -> ThreadHash {
+ fn get_thread_under_cursor(&self, cursor: usize, context: &Context) -> ThreadGroupHash {
//let account = &context.accounts[self.cursor_pos.0];
//let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash();
if self.filter_term.is_empty() {
@@ -983,17 +974,18 @@ impl CompactListing {
panic!();
})
.0
- //threads.root_set(cursor)
} else {
self.filtered_selection[cursor]
}
}
- fn update_line(&mut self, context: &Context, thread_hash: ThreadHash) {
+ fn update_line(&mut self, context: &Context, thread_hash: ThreadGroupHash) {
let account = &context.accounts[self.cursor_pos.0];
let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash();
let threads = &account.collection.threads[&folder_hash];
- if let Some(env_hash) = threads[&thread_hash].message() {
+ if let Some(env_hash) =
+ threads.thread_nodes()[&threads.groups[&thread_hash].root().unwrap()].message()
+ {
if !account.contains_key(env_hash) {
/* The envelope has been renamed or removed, so wait for the appropriate event to
* arrive */
@@ -1001,14 +993,14 @@ impl CompactListing {
}
let envelope: EnvelopeRef = account.collection.get_env(env_hash);
let has_attachments = envelope.has_attachments();
- let fg_color = if threads[&thread_hash].has_unseen() {
+ let fg_color = if threads.groups[&thread_hash].unseen() > 0 {
Color::Byte(0)
} else {
Color::Default
};
let idx = self.order[&thread_hash];
let bg_color = if context.settings.terminal.theme == "light" {
- if threads[&thread_hash].has_unseen() {
+ if threads.groups[&thread_hash].unseen() > 0 {
Color::Byte(251)
} else if idx % 2 == 0 {
Color::Byte(252)
@@ -1016,7 +1008,7 @@ impl CompactListing {
Color::Default
}
} else {
- if threads[&thread_hash].has_unseen() {
+ if threads.groups[&thread_hash].unseen() > 0 {
Color::Byte(253)
} else if idx % 2 == 0 {
Color::Byte(236)
@@ -1125,7 +1117,7 @@ impl CompactListing {
columns[4][c].set_ch(' ');
columns[4][c].set_bg(bg_color);
}
- match (threads.is_snoozed(thread_hash), has_attachments) {
+ match (threads.groups[&thread_hash].snoozed(), has_attachments) {
(true, true) => {
columns[3][(0, idx)].set_fg(Color::Byte(103));
columns[3][(2, idx)].set_fg(Color::Red);
@@ -1225,22 +1217,8 @@ impl Component for CompactListing {
k == shortcuts[CompactListing::DESCRIPTION]["open_thread"]
) =>
{
- if self.filtered_selection.is_empty() {
- self.view = ThreadView::new(self.cursor_pos, None, context);
- } else {
- let mut temp = self.cursor_pos;
- let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2, context);
- let account = &context.accounts[self.cursor_pos.0];
- let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash();
- let threads = &account.collection.threads[&folder_hash];
- let root_thread_index = threads.root_iter().position(|t| t == thread_hash);
- if let Some(pos) = root_thread_index {
- temp.2 = pos;
- self.view = ThreadView::new(temp, Some(thread_hash), context);
- } else {
- return true;
- }
- }
+ let thread = self.get_thread_under_cursor(self.cursor_pos.2, context);
+ self.view = ThreadView::new(self.cursor_pos, thread, None, context);
self.unfocused = true;
self.dirty = true;
return true;
@@ -1269,48 +1247,34 @@ impl Component for CompactListing {
self.selection.entry(thread_hash).and_modify(|e| *e = !*e);
}
UIEvent::Action(ref action) => match action {
- Action::SubSort(field, order) if !self.unfocused => {
- debug!("SubSort {:?} , {:?}", field, order);
- self.subsort = (*field, *order);
- //if !self.filtered_selection.is_empty() {
- // let threads = &account.collection.threads[&folder_hash];
- // threads.vec_inner_sort_by(&mut self.filtered_selection, self.sort, &account.collection);
- //} else {
- // self.refresh_mailbox(context);
- //}
- return true;
- }
Action::Sort(field, order) if !self.unfocused => {
debug!("Sort {:?} , {:?}", field, order);
self.sort = (*field, *order);
if !self.filtered_selection.is_empty() {
- let folder_hash = context.accounts[self.cursor_pos.0]
- [self.cursor_pos.1]
- .unwrap()
- .folder
- .hash();
- let threads = &context.accounts[self.cursor_pos.0].collection.threads
- [&folder_hash];
- threads.vec_inner_sort_by(
- &mut self.filtered_selection,
- self.sort,
- &context.accounts[self.cursor_pos.0].collection.envelopes,
- );
+ // FIXME: perform sort
self.dirty = true;
} else {
self.refresh_mailbox(context);
}
return true;
}
+ Action::SubSort(field, order) if !self.unfocused => {
+ debug!("SubSort {:?} , {:?}", field, order);
+ self.subsort = (*field, *order);
+ // FIXME: perform subsort.
+ return true;
+ }
Action::ToggleThreadSnooze if !self.unfocused => {
- let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2, context);
+ let thread = self.get_thread_under_cursor(self.cursor_pos.2, context);
let account = &mut context.accounts[self.cursor_pos.0];
let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash();
let threads = account.collection.threads.entry(folder_hash).or_default();
- let root_node = threads.thread_nodes.entry(thread_hash).or_default();
- let is_snoozed = root_node.snoozed();
- root_node.set_snoozed(!is_snoozed);
- self.row_updates.push(thread_hash);
+ let is_snoozed = threads.groups[&thread].snoozed();
+ threads
+ .groups
+ .entry(thread)
+ .and_modify(|entry| entry.set_snoozed(!is_snoozed));
+ self.row_updates.push(thread);
self.refresh_mailbox(context);
return true;
}
@@ -1352,33 +1316,10 @@ impl Component for CompactListing {
if !threads.thread_nodes.contains_key(&new_env_thread_hash) {
return false;
}
- let thread_group = melib::find_root_hash(
- &threads.thread_nodes,
- threads.thread_nodes[&new_env_thread_hash].thread_group(),
- );
- let (&thread_hash, &row): (&ThreadHash, &usize) = self
- .order
- .iter()
- .find(|(n, _)| {
- melib::find_root_hash(
- &threads.thread_nodes,
- threads.thread_nodes[&n].thread_group(),
- ) == thread_group
- })
- .unwrap();
-
- let new_thread_hash = threads.root_set(row);
- self.row_updates.push(new_thread_hash);
- if let Some(row) = self.order.remove(&thread_hash) {
- self.order.insert(new_thread_hash, row);
- let selection_status = self.selection.remove(&thread_hash).unwrap();
- self.selection.insert(new_thread_hash, selection_status);
- for h in self.filtered_selection.iter_mut() {
- if *h == thread_hash {
- *h = new_thread_hash;
- break;
- }
- }
+ let thread: ThreadGroupHash =
+ threads.find_group(threads.thread_nodes()[&new_env_thread_hash].group);
+ if self.order.contains_key(&thread) {
+ self.row_updates.push(thread);
}
self.dirty = true;
diff --git a/ui/src/components/mail/listing/conversations.rs b/ui/src/components/mail/listing/conversations.rs
index 23e590a6..b9096762 100644
--- a/ui/src/components/mail/listing/conversations.rs
+++ b/ui/src/components/mail/listing/conversations.rs
@@ -85,33 +85,33 @@ pub struct ConversationsListing {
length: usize,
sort: (SortField, SortOrder),
subsort: (SortField, SortOrder),
- all_threads: fnv::FnvHashSet<ThreadHash>,
- order: FnvHashMap<ThreadHash, usize>,
+ all_threads: fnv::FnvHashSet<ThreadGroupHash>,
+ order: FnvHashMap<ThreadGroupHash, usize>,
/// Cache current view.
content: CellBuffer,
filter_term: String,
- filtered_selection: Vec<ThreadHash>,
- filtered_order: FnvHashMap<ThreadHash, usize>,
- selection: FnvHashMap<ThreadHash, bool>,
+ filtered_selection: Vec<ThreadGroupHash>,
+ filtered_order: FnvHashMap<ThreadGroupHash, usize>,
+ selection: FnvHashMap<ThreadGroupHash, bool>,
/// If we must redraw on next redraw event
dirty: bool,
force_draw: bool,
/// If `self.view` exists or not.
unfocused: bool,
view: ThreadView,
- row_updates: SmallVec<[ThreadHash; 8]>,
+ row_updates: SmallVec<[ThreadGroupHash; 8]>,
movement: Option<PageMovement>,
id: ComponentId,
}
impl MailListingTrait for ConversationsListing {
- fn row_updates(&mut self) -> &mut SmallVec<[ThreadHash; 8]> {
+ fn row_updates(&mut self) -> &mut SmallVec<[ThreadGroupHash; 8]> {
&mut self.row_updates
}
- fn get_focused_items(&self, context: &Context) -> SmallVec<[ThreadHash; 8]> {
+ fn get_focused_items(&self, context: &Context) -> SmallVec<[ThreadGroupHash; 8]> {
let is_selection_empty = self.selection.values().cloned().any(std::convert::identity);
let i = [self.get_thread_under_cursor(self.cursor_pos.2, context)];
let cursor_iter;
@@ -149,23 +149,22 @@ impl ListingTrait for ConversationsListing {
if self.length == 0 {
return;
}
- let i = self.get_thread_under_cursor(idx, context);
+ let thread = self.get_thread_under_cursor(idx, context);
let account = &context.accounts[self.cursor_pos.0];
let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash();
let threads = &account.collection.threads[&folder_hash];
- let thread_node = &threads.thread_nodes[&i];
- let fg_color = if thread_node.has_unseen() {
+ let fg_color = if threads.groups[&thread].unseen() > 0 {
Color::Byte(0)
} else {
Color::Default
};
let bg_color = if self.cursor_pos.2 == idx {
Color::Byte(246)
- } else if self.selection[&i] {
+ } else if self.selection[&thread] {
Color::Byte(210)
- } else if thread_node.has_unseen() {
+ } else if threads.groups[&thread].unseen() > 0 {
Color::Byte(251)
} else {
Color::Default
@@ -187,7 +186,7 @@ impl ListingTrait for ConversationsListing {
let (upper_left, bottom_right) = area;
let width = self.content.size().0;
let (x, y) = upper_left;
- if self.cursor_pos.2 == idx || self.selection[&i] {
+ if self.cursor_pos.2 == idx || self.selection[&thread] {