// providing information to modify how things are displayed
pub trait DisplayStyleGetter {
fn poll_options(&self, id: &str) -> Option<HashSet<usize>>;
+ fn unfolded(&self, id: &str) -> bool;
}
struct DefaultDisplayStyle;
impl DisplayStyleGetter for DefaultDisplayStyle {
fn poll_options(&self, _id: &str) -> Option<HashSet<usize>> { None }
+ fn unfolded(&self, _id: &str) -> bool { true }
}
pub trait TextFragment {
pub struct InReplyToLine {
para: Paragraph,
+ warning: Option<Paragraph>,
+ id: String,
}
impl InReplyToLine {
- pub fn new(post: Paragraph) -> Self {
+ pub fn new(post: Paragraph, warning: Option<String>, id: &str) -> Self {
let mut para = Paragraph::new().add(ColouredString::plain("Re: "));
let currlen = para.words.len();
para.push_para(&post);
para.delete_mention_words_from(currlen);
- InReplyToLine { para }
+
+ let warning = warning.map(|text| {
+ let mut para = Paragraph::new()
+ .add(ColouredString::plain("Re: "))
+ .add(ColouredString::uniform("[-]", 'r'));
+ para.end_word();
+ para.add(ColouredString::plain(&text))
+ });
+
+ InReplyToLine {
+ para,
+ warning,
+ id: id.to_owned(),
+ }
}
pub fn from_id(id: &str, client: &mut Client) -> Self {
- let parent_text = match client.status_by_id(id) {
+ let st = client.status_by_id(id);
+ let parent_text = match &st {
Ok(st) => Html::new(&st.content).to_para(),
Err(e) => Paragraph::new().add(ColouredString::plain(
&format!("[unavailable: {}]", e)
)),
};
- Self::new(parent_text)
+
+ let warning = match &st {
+ Ok(st) => if st.sensitive {
+ Some(st.spoiler_text.clone())
+ } else {
+ None
+ }
+ Err(..) => None
+ };
+
+ Self::new(parent_text, warning, id)
}
}
impl TextFragment for InReplyToLine {
fn render_highlighted(&self, width: usize, _highlight: Option<Highlight>,
- _style: &dyn DisplayStyleGetter)
+ style: &dyn DisplayStyleGetter)
-> Vec<ColouredString>
{
- let rendered_para = self.para.render(width - min(width, 3));
+ let which_para = match self.warning.as_ref() {
+ Some(folded) => if !style.unfolded(&self.id) {
+ folded
+ } else {
+ &self.para
+ }
+ None => &self.para,
+ };
+
+ let rendered_para = which_para.render(width - min(width, 3));
let mut it = rendered_para.iter();
// "Re:" guarantees the first line must exist at least
let first_line = it.next().unwrap();
via: Option<UsernameHeader>,
irt: Option<InReplyToLine>,
vis: Option<VisibilityLine>,
- warning: Option<Paragraph>,
+ warning: Option<String>,
content: Html,
media: Vec<Media>,
poll: Option<Poll>,
};
let warning = if st.sensitive {
- let mut para = Paragraph::new();
- para = para.add(ColouredString::uniform("Content note:", 'r'));
- para.end_word();
- para = para.add(ColouredString::plain(&st.spoiler_text));
- Some(para)
+ Some(st.spoiler_text.clone())
} else {
None
};
push_fragment(&mut lines, self.vis.render(width));
push_fragment(&mut lines, self.irt.render(width));
push_fragment(&mut lines, self.blank.render(width));
- push_fragment_opt_highlight(&mut lines, self.warning.render(width));
- let rendered_content = self.content.render(width);
- let content_empty = rendered_content.is_empty();
- push_fragment_opt_highlight(&mut lines, rendered_content);
- if !content_empty {
- push_fragment(&mut lines, self.blank.render(width));
+
+ let folded = self.warning.is_some() && !style.unfolded(&self.id);
+ if let Some(warning_text) = &self.warning {
+ let mut para = Paragraph::new();
+ para = para.add(&ColouredString::uniform(
+ if folded {"[-]"} else {"[+]"}, 'r'));
+ para.end_word();
+ para = para.add(&ColouredString::plain(&warning_text));
+ push_fragment_opt_highlight(&mut lines, para.render(width));
}
- for m in &self.media {
- push_fragment_opt_highlight(&mut lines, m.render(width));
- push_fragment_opt_highlight(&mut lines, self.blank.render(width));
+
+ if folded {
+ push_fragment(&mut lines, self.blank.render(width));
+ } else {
+ let rendered_content = self.content.render(width);
+ let content_empty = rendered_content.is_empty();
+ push_fragment_opt_highlight(&mut lines, rendered_content);
+ if !content_empty {
+ push_fragment(&mut lines, self.blank.render(width));
+ }
+ for m in &self.media {
+ push_fragment_opt_highlight(&mut lines, m.render(width));
+ push_fragment_opt_highlight(
+ &mut lines, self.blank.render(width));
+ }
}
+
+ // Even if we're folded, display the fact of there being a
+ // poll, because otherwise it's just too painful to try to
+ // conditionalise selecting the poll options.
if let Some(poll) = &self.poll {
push_fragment_opt_highlight(&mut lines, poll.title.render(width));
let poll_options_selected = style.poll_options(&poll.id);
*voted, |opts| opts.contains(&i));
let option = Paragraph::new().set_indent(0, 2).add(
&ColouredString::uniform(
- if voted {"[X]"} else {"[ ]"}, 'H'))
- .add(desc);
+ if voted {"[X]"} else {"[ ]"}, 'H'));
+ let option = if folded { option } else { option.add(desc) };
let push_fragment_opt_highlight = if highlighting_this_option {
push_fragment_highlighted
} else {