[fractal] Message Widget: Initial html support



commit 6457c34192ae314b23ff6af5232902a0ed1220f7
Author: Maximiliano Sandoval R <msandova protonmail com>
Date:   Sat Oct 10 23:15:24 2020 +0200

    Message Widget: Initial html support
    
    Following !399.
    
    Ensure build_room_msg_body returns errors

 fractal-gtk/src/widgets/message.rs | 91 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 90 insertions(+), 1 deletion(-)
---
diff --git a/fractal-gtk/src/widgets/message.rs b/fractal-gtk/src/widgets/message.rs
index 2c89063a..e5fbd6a4 100644
--- a/fractal-gtk/src/widgets/message.rs
+++ b/fractal-gtk/src/widgets/message.rs
@@ -10,10 +10,12 @@ use crate::widgets::message_menu::MessageMenu;
 use crate::widgets::AvatarExt;
 use crate::widgets::ClipContainer;
 use crate::widgets::{AudioPlayerWidget, PlayerExt, VideoPlayerWidget};
+use anyhow::Context;
 use chrono::prelude::*;
 use either::Either;
 use glib::clone;
 use gtk::{prelude::*, ButtonExt, ContainerExt, LabelExt, Overlay, WidgetExt};
+use html2pango::block::{HtmlBlock, markup_html};
 use itertools::Itertools;
 use matrix_sdk::Client as MatrixClient;
 use std::cmp::max;
@@ -517,6 +519,83 @@ fn build_room_msg(
     (body, type_extras)
 }
 
+fn build_room_msg_body_html(_container: &MessageBoxContainer, msg: &Message) -> anyhow::Result<gtk::Box> {
+    let raw = msg.msg.formatted_body.clone().unwrap_or_default();
+
+    let blocks =
+        markup_html(&raw).with_context(|| format!("Could not render message: {}", &raw))?;
+    let bx = gtk::Box::new(gtk::Orientation::Vertical, 6);
+    for b in blocks {
+        let widget = render_html_block(&b);
+        bx.add(&widget);
+    }
+    Ok(bx)
+}
+
+fn render_html_block(block: &HtmlBlock) -> gtk::Widget {
+    match block {
+        HtmlBlock::Heading(n, s) => {
+            let w = gtk::Label::new(None);
+            set_label_styles(&w);
+            w.set_markup(&s);
+            w.get_style_context().add_class(&format!("h{}", n));
+            w.upcast::<gtk::Widget>()
+        }
+        HtmlBlock::UList(elements) => {
+            let w = gtk::Label::new(None);
+            set_label_styles(&w);
+
+            let text = elements
+                .iter()
+                .map(|li| format!(" • {}", li))
+                .collect::<Vec<String>>()
+                .join("\n");
+            w.set_markup(&text);
+
+            w.upcast::<gtk::Widget>()
+        }
+        HtmlBlock::OList(elements) => {
+            let w = gtk::Label::new(None);
+            set_label_styles(&w);
+
+            let text = elements
+                .iter()
+                .enumerate()
+                .map(|(i, li)| format!(" {}. {}", i + 1, li))
+                .collect::<Vec<String>>()
+                .join("\n");
+
+            w.set_markup(&text);
+
+            w.upcast::<gtk::Widget>()
+        }
+        HtmlBlock::Code(s) => {
+            let buffer = sourceview4::Buffer::new::<gtk::TextTagTable>(None);
+            buffer.set_text(&s);
+            let view = sourceview4::View::with_buffer(&buffer);
+            view.set_editable(false);
+            view.set_wrap_mode(gtk::WrapMode::WordChar);
+            view.get_style_context().add_class("codeview");
+            view.upcast::<gtk::Widget>()
+        }
+        HtmlBlock::Quote(blocks) => {
+            let bx = gtk::Box::new(gtk::Orientation::Vertical, 6);
+            bx.get_style_context().add_class("quote");
+            for b in blocks.iter() {
+                let w = render_html_block(&b);
+                bx.add(&w);
+            }
+            bx.upcast::<gtk::Widget>()
+        }
+        HtmlBlock::Text(s) => {
+            let w = gtk::Label::new(None);
+            set_label_styles(&w);
+            w.set_markup(&s);
+            w.upcast::<gtk::Widget>()
+        }
+    }
+}
+
 fn build_room_msg_sticker(session_client: MatrixClient, msg: &Message) -> BodyAndType {
     let bx = gtk::Box::new(gtk::Orientation::Horizontal, 0);
     if let Some(url) = msg.msg.url.clone() {
@@ -751,6 +830,16 @@ fn build_room_msg_file(msg: &Message) -> BodyAndType {
 }
 
 fn build_room_msg_body(container: &MessageBoxContainer, msg: &Message) -> BodyAndType {
+    let bx = match msg.msg.format.as_deref() {
+        Some("org.matrix.custom.html") =>
+            build_room_msg_body_html(container, &msg)
+            .unwrap_or_else(|_err| build_room_msg_body_text(container, &msg)),
+        _ => build_room_msg_body_text(container, &msg),
+    };
+    (bx, MessageBodyType::Text)
+}
+
+fn build_room_msg_body_text(container: &MessageBoxContainer, msg: &Message) -> gtk::Box {
     let bx = gtk::Box::new(gtk::Orientation::Vertical, 6);
 
     let msgs_by_kind_of_line = msg.msg.body.lines().group_by(|&line| kind_of_line(line));
@@ -811,7 +900,7 @@ fn build_room_msg_body(container: &MessageBoxContainer, msg: &Message) -> BodyAn
         bx.add(&part);
     }
 
-    (bx, MessageBodyType::Text)
+    bx
 }
 
 #[derive(Clone, Debug)]


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]