Skip to content

Commit

Permalink
Add HTML Renderer (#469)
Browse files Browse the repository at this point in the history
* add color code parser

* process font style

* build labels by looping though each html character
  • Loading branch information
ugwueze-dev committed Jul 2, 2021
1 parent cb68f3c commit 1e4bb07
Show file tree
Hide file tree
Showing 9 changed files with 660 additions and 106 deletions.
3 changes: 3 additions & 0 deletions go.mod
Expand Up @@ -4,6 +4,8 @@ go 1.13

require (
gioui.org v0.0.0-20210418151603-3b69b5ed0512
github.com/JohannesKaufmann/html-to-markdown v1.2.1
github.com/PuerkitoBio/goquery v1.6.1
github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d
github.com/decred/dcrd/chaincfg v1.5.2 // indirect
github.com/decred/dcrd/chaincfg/chainhash v1.0.3-0.20200921185235-6d75c7ec1199
Expand All @@ -21,6 +23,7 @@ require (
github.com/yeqown/go-qrcode v1.5.1
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/text v0.3.3
)
Expand Down
14 changes: 14 additions & 0 deletions go.sum
Expand Up @@ -48,6 +48,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/JohannesKaufmann/html-to-markdown v1.2.1 h1:VgNHWizxsocCx99W8VOd6NkGLQsq7tzRWcGdxP65RpQ=
github.com/JohannesKaufmann/html-to-markdown v1.2.1/go.mod h1:JNSClIRYICFDiFhw6RBhBeWGnMSSKVZ6sPQA+TK4tyM=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
Expand All @@ -56,6 +58,9 @@ github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuN
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/PuerkitoBio/goquery v1.6.1 h1:FgjbQZKl5HTmcn4sKBgvx8vv63nhyhIpv7lJpFGCWpk=
github.com/PuerkitoBio/goquery v1.6.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/Sereal/Sereal v0.0.0-20181211220259-509a78ddbda3/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863 h1:BRrxwOZBolJN4gIwvZMJY1tzqBvQgpaZiQRuIDD40jM=
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
Expand All @@ -71,6 +76,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
github.com/apache/beam v2.27.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
Expand Down Expand Up @@ -753,6 +760,9 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sebdah/goldie/v2 v2.5.1/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
Expand Down Expand Up @@ -806,6 +816,7 @@ github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.0/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.0/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
Expand Down Expand Up @@ -888,6 +899,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180808004115-f9ce57c11b24/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -918,6 +930,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
Expand Down Expand Up @@ -1172,6 +1185,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
Expand Down
69 changes: 24 additions & 45 deletions ui/modal_templates.go
Expand Up @@ -6,6 +6,7 @@ import (
"gioui.org/widget"

"github.com/planetdecred/godcr/ui/decredmaterial"
"github.com/planetdecred/godcr/ui/renderers"
"github.com/planetdecred/godcr/ui/values"
"golang.org/x/exp/shiny/materialdesign/icons"
)
Expand All @@ -22,23 +23,26 @@ const (
func verifyMessageInfo(th *decredmaterial.Theme) []layout.Widget {
return []layout.Widget{
func(gtx C) D {
text := th.Body1("After you or your counterparty has genrated a signature, you can use this form to verify the" +
" validity of the signature. \n \nOnce you have entered the address, the message and the corresponding " +
"signature, you will see VALID if the signature appropriately matches the address and message, otherwise INVALID.")
text.Color = th.Color.Gray
return text.Layout(gtx)
text := `<span style="text-color: gray">
After you or your counterparty has genrated a signature, you can use this form to verify the
validity of the signature.
<br /> Once you have entered the address, the message and the corresponding signature, you will see <font color="success">VALID</font>
if the signature appropriately matches the address and message, otherwise <font color="danger">INVALID</font>.
</span>`

return renderers.RenderHTML(text, th).Layout(gtx)
},
}
}

func signMessageInfo(th *decredmaterial.Theme) []layout.Widget {
text := `<span style="text-color: gray">
Signing a message with an address' private key allows you to prove that
you are the owner of a given address to a possible counterparty.
</span>`

return []layout.Widget{
func(gtx C) D {
text := th.Body1("Signing a message with an address' private key allows you to prove that you are the owner of a given address" +
" to a possible counterparty.")
text.Color = th.Color.Gray
return text.Layout(gtx)
},
renderers.RenderHTML(text, th).Layout,
}
}

Expand Down Expand Up @@ -81,45 +85,20 @@ func privacyInfo(th *decredmaterial.Theme) []layout.Widget {
}

func setupMixerInfo(th *decredmaterial.Theme) []layout.Widget {
text := `<span style="text-color: gray">
Two dedicated accounts (“mixed” & “unmixed”) will be created in order to use the mixer.
<b>This action cannot be undone.</b>
</span>`

return []layout.Widget{
func(gtx C) D {
txt := th.Body1("Two dedicated accounts (“mixed” & “unmixed”) will be created in order to use the mixer.")
txt.Color = th.Color.Gray
return layout.Inset{Left: values.MarginPadding10}.Layout(gtx, txt.Layout)
},
func(gtx C) D {
txt := th.Label(values.TextSize18, "This action cannot be undone.")
return txt.Layout(gtx)
},
renderers.RenderHTML(text, th).Layout,
}
}

func transactionDetailsInfo(th *decredmaterial.Theme) []layout.Widget {
text := `<span style="text-color: gray">Tap on <span style="text-color: primary">blue text</span> to copy the item</span>`

return []layout.Widget{
func(gtx C) D {
return layout.Flex{}.Layout(gtx,
layout.Rigid(func(gtx C) D {
t := th.Body1("Tap on")
t.Color = th.Color.Gray
return t.Layout(gtx)
}),
layout.Rigid(func(gtx C) D {
t := th.Body1("blue text")
t.Color = th.Color.Primary
m := values.MarginPadding2
return layout.Inset{
Left: m,
Right: m,
}.Layout(gtx, func(gtx C) D {
return t.Layout(gtx)
})
}),
layout.Rigid(func(gtx C) D {
t := th.Body1("to copy the item.")
t.Color = th.Color.Gray
return t.Layout(gtx)
}),
)
},
renderers.RenderHTML(text, th).Layout,
}
}
3 changes: 2 additions & 1 deletion ui/proposal_details_page.go
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/planetdecred/dcrlibwallet"
"github.com/planetdecred/godcr/ui/decredmaterial"
"github.com/planetdecred/godcr/ui/renderers"
"github.com/planetdecred/godcr/ui/values"
)

Expand Down Expand Up @@ -423,7 +424,7 @@ func (pg *proposalDetails) Layout(gtx C) D {
}
}

r := RenderMarkdown(gtx, pg.theme, proposalDescription)
r := renderers.RenderMarkdown(gtx, pg.theme, proposalDescription)
proposalWidgets, proposalClickables := r.Layout()
pg.proposalItems[proposal.Token] = proposalItemWidgets{
widgets: proposalWidgets,
Expand Down
94 changes: 94 additions & 0 deletions ui/renderers/color.go
@@ -0,0 +1,94 @@
package renderers

import (
"errors"
"fmt"
"image/color"
"regexp"
"strconv"
"strings"
)

const (
hexRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
hexFormat = "#%02x%02x%02x"
hexShortFormat = "#%1x%1x%1x"
hexToRGBFactor = 17

rgbString = "rgb(%d,%d,%d)"
rgbRegexString = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$"
rgbaString = "rgba(%d,%d,%d,%g)"
rgbaRegexString = "^rgba\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0\\.[0-9]*|[01])\\s*\\)$"
)

var (
hexRegex = regexp.MustCompile(hexRegexString)
rgbRegex = regexp.MustCompile(rgbRegexString)
rgbaRegex = regexp.MustCompile(rgbaRegexString)

errBadHexCode = errors.New("Bad hex color code")
errBadRGBCode = errors.New("Bad rgb color code")
)

func parseColorCode(colorCode string) (color.NRGBA, bool) {
colorCode = strings.ToLower(colorCode)

if col, ok := parseHex(colorCode); ok {
return col, ok
}

if col, ok := parseRGB(colorCode); ok {
return col, ok
}

if col, ok := parseRGBA(colorCode); ok {
return col, ok
}

return color.NRGBA{}, false
}

func parseHex(colorCode string) (color.NRGBA, bool) {
if !hexRegex.MatchString(colorCode) {
return color.NRGBA{}, false
}

var r, g, b uint8
if len(colorCode) == 4 {
fmt.Sscanf(colorCode, hexShortFormat, &r, &g, &b)
r *= hexToRGBFactor
g *= hexToRGBFactor
b *= hexToRGBFactor
} else {
fmt.Sscanf(colorCode, hexFormat, &r, &g, &b)
}

return color.NRGBA{R: r, G: g, B: b, A: 255}, true
}

func parseRGB(colorCode string) (color.NRGBA, bool) {
parts := rgbRegex.FindAllStringSubmatch(colorCode, -1)
if len(parts) == 0 || len(parts[0]) == 0 {
return color.NRGBA{}, false
}

r, _ := strconv.ParseUint(parts[0][1], 10, 8)
g, _ := strconv.ParseUint(parts[0][2], 10, 8)
b, _ := strconv.ParseUint(parts[0][3], 10, 8)

return color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255}, true
}

func parseRGBA(colorCode string) (color.NRGBA, bool) {
parts := rgbaRegex.FindAllStringSubmatch(colorCode, -1)
if len(parts) == 0 || len(parts[0]) == 0 {
return color.NRGBA{}, false
}

r, _ := strconv.ParseUint(parts[0][1], 10, 8)
g, _ := strconv.ParseUint(parts[0][2], 10, 8)
b, _ := strconv.ParseUint(parts[0][3], 10, 8)
a, _ := strconv.ParseFloat(parts[0][4], 64)

return color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: uint8(a)}, true
}

0 comments on commit 1e4bb07

Please sign in to comment.