From: Simon Tatham Date: Wed, 10 Jan 2024 08:37:34 +0000 (+0000) Subject: Ability to display sensitive toots folded up. X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=1eed48aa679720525082c3a07b9f86dbfe92fc64;p=mastodonochrome.git Ability to display sensitive toots folded up. Not currently used: all our current DisplayStyleGetters unconditionally return true from their unfolded method. This has to apply to the quoted line of a toot in Re: lines, as well as the full display of the post contents. --- diff --git a/src/file.rs b/src/file.rs index 1ddf913..5b0e5e1 100644 --- a/src/file.rs +++ b/src/file.rs @@ -327,6 +327,8 @@ impl DisplayStyleGetter for FileDisplayStyles { } ) } + + fn unfolded(&self, _id: &str) -> bool { true } } struct File { diff --git a/src/text.rs b/src/text.rs index 4fd9dad..845914d 100644 --- a/src/text.rs +++ b/src/text.rs @@ -44,10 +44,12 @@ impl ConsumableHighlight for Option { // providing information to modify how things are displayed pub trait DisplayStyleGetter { fn poll_options(&self, id: &str) -> Option>; + fn unfolded(&self, id: &str) -> bool; } struct DefaultDisplayStyle; impl DisplayStyleGetter for DefaultDisplayStyle { fn poll_options(&self, _id: &str) -> Option> { None } + fn unfolded(&self, _id: &str) -> bool { true } } pub trait TextFragment { @@ -935,34 +937,69 @@ fn test_extendable() { pub struct InReplyToLine { para: Paragraph, + warning: Option, + id: String, } impl InReplyToLine { - pub fn new(post: Paragraph) -> Self { + pub fn new(post: Paragraph, warning: Option, 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, - _style: &dyn DisplayStyleGetter) + style: &dyn DisplayStyleGetter) -> Vec { - 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(); @@ -1755,7 +1792,7 @@ pub struct StatusDisplay { via: Option, irt: Option, vis: Option, - warning: Option, + warning: Option, content: Html, media: Vec, poll: Option, @@ -1795,11 +1832,7 @@ impl StatusDisplay { }; 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 }; @@ -1915,17 +1948,36 @@ impl TextFragment for StatusDisplay { 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); @@ -1936,8 +1988,8 @@ impl TextFragment for StatusDisplay { *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 {