From 7c0d86e0a6c90f9fc7a9cc3584a50b28dea70b21 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Fri, 15 Nov 2019 18:15:42 +0300 Subject: [PATCH 01/10] 4.2.1-SNAPSHOT --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b1d69d1b..f0fee2c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ android.enableJetifier=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache -VERSION_NAME=4.2.0 +VERSION_NAME=4.2.1-SNAPSHOT GROUP=io.noties.markwon POM_DESCRIPTION=Markwon markdown for Android From 70113b7b1651094b2435941c1010fe00eecb41df Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 19 Dec 2019 18:09:21 +0300 Subject: [PATCH 02/10] Update index page for documentation --- docs/.vuepress/public/assets/apps/cinopsys.png | Bin 0 -> 7776 bytes docs/.vuepress/public/assets/apps/habitica.webp | Bin 0 -> 3694 bytes docs/.vuepress/public/assets/apps/nextcloud.png | Bin 0 -> 9315 bytes docs/README.md | 5 ++++- 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 docs/.vuepress/public/assets/apps/cinopsys.png create mode 100644 docs/.vuepress/public/assets/apps/habitica.webp create mode 100644 docs/.vuepress/public/assets/apps/nextcloud.png diff --git a/docs/.vuepress/public/assets/apps/cinopsys.png b/docs/.vuepress/public/assets/apps/cinopsys.png new file mode 100644 index 0000000000000000000000000000000000000000..e5630510d25f2bf862ede61a270319313c55153b GIT binary patch literal 7776 zcmc(Ec{G&o`~N-m7)v2#*J7LOB!mfx2-$ZcvMWoZhUp!$g%q-c5(*TJC2ai56z3IN1f+0RWuF zMh2DuFkrX;*cjo67O%!`_+Ywl;>-yEYSK7p=a>Ot1Qw>&C)L!{jvYHDFE1}ACkJUr zC@3iC>+2i*eL)t|M~)nU#18!rp{1n-RUiumAptKvJ-r<*r~((+Vd3~cGCPtdPo9Lc zJA?2JS$H=xGJ;xA7_vKyKp9BDDY!eF+L7N`?f++$l$3Vl;R-v#J6e$5xgfivWoT#! zX{f8HsJNrDBY?$XcZeOwp)j-@j{GA7RUi%3cg&WRm4z$>4c>RepbA9e9~zBDL)ym1 z1`23vYs<*U>_}>8XzW+9>|u*!_Lm`)TvWbQ&Tr?+{nz#G%+zLDJe-zOe`uYvb3~pXlQ_eXlrY0ZEe-m)Fcv# zX=!Oce*92ZSFf$Dt*EF-PELk^|N8Z-y1E)-2=R%Ch-hzb4+sdbwzfWc^k`vWp|`hp zQ&STLgL(V*ZA(jwuC6Xb$-~3L-roN7>C@16h&Bx3+}zxW6DL$vRh5;MAwKWlzt79d zJ9FmDr%#_;TwGvc;PLqT_wV1md$+ExZg6n0xw#nzv7@77etsTe2myrXiQzT#A%fXq zmS$GJ=)T4)XFM#DuX@G_7@6fcq@%;?txAsFSI(?4@lktToZ^0uSmhrb+DR;`-R*ow zEB(h6l8c<^#DIj*%-+wFd=xDIb?KgY?YZ7B13?nO!m{K2t=h!GIa z?ye4ippUV^3G2u&zrJ31WxaBx{Zd2enSKK++zY=v)ia*FV?lk6x7zL*neI+Gi?&vj zJ&=?%zK8jwMLqUF6JAr2(#(;>k?>4f>wvWXc`~2;vq;9j{<=7)7(Oc3X=4Nl51kIK-9YR)|+5BgA*94;Btd$n}uE0;3j_!8XGR@!u*Sqc@36 zOzuCi6bSa1lb$MJU z_m$U|ihzy_GgVHskl)I{*i&ytnX}+1ICOnynd$wOtisOYH1Mlh}Qb@q6<`4?{%2F2A6zBLLef~Z);w2})()sea5HAuOn z>h!a->jX&gFUJWG+D1Z@foD$l7rE7mNmJ0KV6*jQBt6y0><2sX-UO>oBiy(Gq*!U@ z_~6+yiow1@Jm=M{Cv8gOQK0SMuLE|_MJ_OwE=q^1ru^V<0bzxya#5wlc?4#6yl2e^ zS)*o7B3rv9jMk-Bdi$`mmb@zvt6d<)XW>VB>PePCpqNB@YOX22pNW_-v7w^%$n$O^ zVqZyEvO%#;k>}edAjNE@8c9T9QJZ07h8f5%l_n zIsUBc63H5~BTyN|Ko4tC$22m8{-%X_<*IT|Pu@Kk2nD#dzf{-yUv67MbL)smX>jXg z8HxVBDcSAluy#{&5QZ1XmDC$9RQNm61XVr_)=8WKy{4MwVL8o&;Dt`_$8}G~q8NIO ztQ$<1_z3}7o11zsSpnyGSP50VQ75<*L*b^>!O+2d!u_*wJ|CwDk`2l_ml;n$^9=4^z?#{zF;*Kb zSnVIDy-SU9*t@Yhbv{A>ER{75q@jKovTxz&HzKg|P)gCwaqBC|v2bS31HwiI%U$dVBvv*eOTrz*F##Aleu5voW^zulc1S{y>E?2%1 z^X2dvHwsP?j54Ed)*rEh$hqgeV{Hg4>m~oxAR&fkKOKCw4N1HK_Ib;H-zqkJ@KWr?(dbMbinj_~&rKr#JXS3(sc=AP{0g+~ z`DGB_q<5?y#Pn?nyAC z-OG@ty**viS8O2ZOeqj$CMNYgAH)rM88}R>?o&SP2;9^s6vp{mj2YMU9Uu~cWn$xZ z`XUsC0ujiFxQh>g?OH=PS`wWfy~ta_eDS4H%(p5YGah1S5ItPd-Px?=-eKmKt%5`g zJ2v&=_1_xtuM{w>Dj)L+a6pRDeRC}Oz6@$MRl@TT^Zd!H;El6HKET>+!tzh7^?dun zS1(3~)q}rl7q}}xXxeTpE_Pzy1bq?CzP)buP_bj2)mF@;o?mqm`f>DYoQD-|p8#R5 zw2(`xJimN>5yJj`ZV9MZPmXF65=mh#Fd;8Bw#E|c6u|H^R1+jmKEpWu3>48H#T;yy za}UwjgN?gGAT@U#`+f9$2_96{uq)#ETNW6leesL5z_+FRdNFBLb$<^kG1^y>M!S{9 zPr_Y12i$z1ElkytKdDpS_bH#64sOf4jCe82Ml6*Xg3Unhk8xF`_&_E88y*xbQKzPd zc^1%>j-9ZADFt}VvC)(_vDc78(pyTCcYOO{XTLQg8C0Vlg51sBD(EFdc>qkA18USS zZSxzCyN?nt+OnMzbRT@yV5%*q-^y4cYAn>Vdl##{VRF-TPow)`;#qMI#!3Au9iSo; zc5ex@3TKoY_D=s~|G^rda26H)KurIrNleP`0t|NR&aP_Ne8UQ~$gT(XS>a+?Lu&%> z*uT9+Ad5Rcjwu-&=lPMz22B5W^?}QM3eoki1pA~`SN$Fkn8VM4&yo%xJc*o3);b=a z!0K_!?9_q4JB-!Irx)@Xw%%kf(OJJOmwddH&UKi~$BAt}#7xnR9q@2FG^brVhKrBy z;1VjXGYk{AeNB61wFg8KN-P)r*HyVcX&#R^y}kN6Acc+i&W>%Eb-MaPx$#0Cx%Zw7 zSDM80K8E#3Ynn~7-sfY)#)BK8Y))uwJo+v4*|0kH6*p z9#`5?)o+9Ir*4wBUBj)5>w*4=HXcez)0~ZTbYt1^!Rlbwh+{a*<2?SZcWE{adY?tn zYjUeYrsSvVUQ5onH>H)veb?=u8g`J?+CR3k7a1mFBx}`Rlkg7x@W;kW6gI)XkETn5i z%qp%)Ei%^RPG&W-#y!KmW+(cUP}c(VZy$*`rs@VQy27`<^}XN^`^=3x#QYvO=cp9T zxx#gGGDch^LG3+V>z+;ochaYn>GEbNSw2D{3AWp%)2@$bo<_nf9vD}eJoi%n8ka>` zXV{fQYW91^ei8c7?PS;*=hJ1}Hl^;aeDn|!ZWrTsgvEoCt8V=Y>tidLV52E>eM~vU zV?tD4(%_o(?=s)7gqs{pqu}z{4a^5B%elP?ZLN1BkPcEX;SW{Ny5}P92(cD`a{Om? z@0-2k_%efRRIm^Il@Isf2y5D_ZB+hLj=4AUP=s0vA7?Kil3=D)AG=Enup{;GqB9LE zv~vz@aU5^^hJQ!uV|dx?`tJ(#L_+S5m{K%JeMx*2fk!pB<}-)1TUkj#@jlH&PVzkDhoa} zbqI^ANtn?iclQ#FPdpW->^mTuuyQHC!E}qEQuE8z1^+Hs?7tgtxM~o$yMccooWd}? z>h0v)yrz31V=s~a^;0<=1z00j1W(UCU)KQBfk~KxuGB|0$B zYqxC6!HVP0xEwmRm;C1WgtKcT@-|ni<8siRWH%o$ydM=kR0%!sns9Lo`@3<9*2-Ji zV50?br@b;^d|obADabn1J_6aTWhB@AMVFJCR6F6BWl$f%V_Jb%=lM}}=L>8<2z$@k zb+1}9`^8Ie2Kiph(_gyYEV)S(Ehe|xcjPvG-%^AZ`QfsXf#%(7t2fvgYmTcrYB2k} zgeCtH51L)++NYcAo#ZzpMn>dhNpoc~#lE(#3!5j~Lj1(`Ztx;oW$$Gaw=%;P-?ojXJK|qb6^qol9==$LcPB^^)zV)r$!}gBzDWoGL+r zsp$B^(38(E?@qbplXdX(OQ&J6O=7GTPsO~_qv=zGOJ_e&>rewOr9q&8HxA|mn+$Ox z^K03(()ofZ>Qn`3l%M$B2j*~_G5K|6`Me=1RU(g_v-L}jaTC^v%WqZ>x!md(W+m&N9$6|eM6RD3JbAP5n)m?67^=zUo2Sv}b^C*R{Q|BF z3FlCySk|BBNS}ncqDQKeg#|J~N3ls&x|lDZxG5jbE=q|eg#YQ!Bv(@W$J^Jo8Unv* zv6JR#(IQr7lbPJt#tt%Fgqfd;{N^2J?UnoLMvjtg@%r-@13vsziSd_g2tMxCDA|-o ze(du#bmi@2waJ2l!17Mj0IUF4LJ9!~dv1k(y-T!{$r`dX_d%aO&j+diMXf9GHbPo7 z;kn}7;lLxBJpSXf%H zV%ksK7QWx3hB8kjtCixuhF`Fe&1AwpiAi~@wQmMpIrt(ryz_W_x|f!XAPyOk6VF|Z zQ3VY`3H+3O&#cGDw19{lO&`PcH6tJ_iD9i(!#f2nE7?qcvF9V8!KUHsLRcf+Ji+BU zpAH`-Dew^G?F<3M#1fkp8`&R$Pj;KK&OZ=j)bzfYKsI6Zz^uC_M7Wf_borK*5SG&b z*3DP9d*T_cl^4PO3&{q_O)A(Yg$`@#bmj+yn|}IDbB6qw5B_*|Aqv5P6=JY*{;m4x zqq8v7B$W`Xx=Wxi<-i5~4wG?AQXvcR<66KbFN9ci*-1+~9+?`rz`;ImKMcNdw=P~p z*4M-=+>%Rk@w7K-MjFHP*>q;#OL(Wg(1Lqe-U)WlPhSJdUFz2JnF-*Lrg|; zAI_!c_mV@ObIpp<>m)9mYUup9oA{AD%)A|tA=1~uxZ&Fu&nPFkUBtT8aah3U(Dz8y zao29*FIa95s(DXYHcQK4Yrl@@;gg+n5e9V-`{drgx4d0~%M6}Vz+SBdT9P5G4 z%0A`pEsKyfa=i2ILV2qTz^ZPTX}tyyx8 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 M;fX66$ZNU?05_r{`v3p{ literal 0 HcmV?d00001 diff --git a/docs/.vuepress/public/assets/apps/nextcloud.png b/docs/.vuepress/public/assets/apps/nextcloud.png new file mode 100644 index 0000000000000000000000000000000000000000..3664da8af27f5348234e674a70caa83d0634cf02 GIT binary patch literal 9315 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 literal 0 HcmV?d00001 diff --git a/docs/README.md b/docs/README.md index 9f53dca3..cb387837 100644 --- a/docs/README.md +++ b/docs/README.md @@ -88,9 +88,12 @@ and 2 themes included: Light & Dark. It can be downloaded from [releases](ht * [Boxcryptor](https://www.boxcryptor.com) - A software that adds AES-256 and RSA encryption to Dropbox, Google Drive, OneDrive and many other clouds. + Extension/plugins: * [MarkwonCodeEx](https://github.com/kingideayou/MarkwonCodeEx) - Markwon extension support elegant code background. From 17756a11370a94a1303a24f0cb5422d85afda38d Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Fri, 20 Dec 2019 12:46:41 +0300 Subject: [PATCH 03/10] Update documentation index page --- docs/.vuepress/components/AwesomeGroup.vue | 2 +- .../.vuepress/public/assets/apps/habitica.png | Bin 0 -> 3542 bytes .../public/assets/apps/habitica.webp | Bin 3694 -> 0 bytes docs/README.md | 25 +++++++++++++++--- 4 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 docs/.vuepress/public/assets/apps/habitica.png delete mode 100644 docs/.vuepress/public/assets/apps/habitica.webp diff --git a/docs/.vuepress/components/AwesomeGroup.vue b/docs/.vuepress/components/AwesomeGroup.vue index 1399ffaf..b047580c 100644 --- a/docs/.vuepress/components/AwesomeGroup.vue +++ b/docs/.vuepress/components/AwesomeGroup.vue @@ -32,7 +32,7 @@ export default { margin: 0.25em; border-radius: 0.25em; box-shadow: 0 0 0.1em 0.1em #eee; - max-width: 30%; + max-width: 25%; min-width: 100px; display: flex; align-items: center; diff --git a/docs/.vuepress/public/assets/apps/habitica.png b/docs/.vuepress/public/assets/apps/habitica.png new file mode 100644 index 0000000000000000000000000000000000000000..797b452cd2da9dd6b5e3ca928f11b3a60d264693 GIT binary patch literal 3542 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 Lf=T5uV#5CbBX}qc literal 0 HcmV?d00001 diff --git a/docs/.vuepress/public/assets/apps/habitica.webp b/docs/.vuepress/public/assets/apps/habitica.webp deleted file mode 100644 index afcc165804cc6475f3ea449867867541c4a91dca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3694 zcmV-!4w3OvNk&Fy4gdgGMM6+kP&iCk4gdfzzrZgLRfpoXZ5(O;u~V+!J0d24t2+%; z=QLdiFlRY&%4hSVbh7_{WhvhUHcvQ{&tDz>t^DqD{^jnk+@K%{A%lP`0ReOvINf!y zdACBq2)QCo$w(jw$O>?P1Qd*j5kkhms<_oiAe?T42FjfOCD+3ULBt5T&ofhP$#Ydu zt%xx}hlrfPzYNJE_x| zmF@fi^>&qXwry2*{rujZ04vh=ueKe{Bh1Xq%*@Qp%*@Qp%*@Qp%*@P;YOl4|f3JQ2 z{|sTts0@NR6JSo(b#YPKrQ#CDxwTbh5Er#45XsCOd)1Y3nE*2$ml=HFSaeJ-^2{Qh zWU7vhjAWR>@v#{I4}j)C6F3t{byzpUvAbOyxklHL8K#f{+_+p9wVO$`Vun*af=r?_ zfaY#{b|K*<#pxd z`B(kJ%sduyU?=G?S6_!?keevk`hYFC@JmnH6X{}XKPDwZ&R3Ut~+qKrZpn6(T4JZ3kuf zA>j@g>BwbPNrevwT6xYit~^RH@0X5H8H?+SSZhBVXy!S#;xm*|n50Hz{7)x1_WbH-zF=NXTq3l5VI z^M)%quw5;2!=u>j1wh>x3WozHoQ;ya=}A|GN6EU+R1Vw&JPJ7l{B0F)6x{`?P)bv5 zxeY1j3gX_t?@CGG0e~XkTv*L27hXp;+LDjh>=`77_?)Q3bn+lTm2WoOeOWTPQuGm< zIfK*~uU3r&KrLrYq`qX%-}D}dh5b3Jqx2 z#IgxpgtE8dn10o%PXLN5;khCgp=>QX2Iw8YLRuPH;KG-^VH5%M2H^SO$u4f;%28v~ z0HAjT7FLt6{~>J7l1pF!SJ5@Hh#F-#8VUH6TKw?-A!>=8j}-a0q*=Sj?{F)zpfuSk%7np&d1b5iulc~k|oG^bG|M861RH;DYLugqkf^J`g_vyFvE zjcY~KxF2Y=k@~z8kV`KMY-y#*YQ}M0YZTDi zv{X9#7WV)1EcyL%GXmWM{9}KUX)*IyO7=T3I2d-Ju_WljGg}*$G6tS?p_~AB7Lz#r z^KN-Z1_#@kgL)Xp=(^jD0lGA3el3qgR(6^rvw3dOv0&Z3M&hTAXEEKW3xgR4wC?Ck z=UG$c2wRTBqP|Of^viHw%E(^3hJ*=o7&XtR!t5wP-|Ey5imC2LxUwrKv?jeN(9P9{ z0{T?IH(=7zvd^{T&#QY4D*<{1@D+akMy0kNy#NH$SCtH|c~un+Wq@0&mM*j<@t>b2 z=T%_KT&Al$nOvjz>DQhm8326)(5bp)ADJ#odtmT>PIP~ zd5Q8a5)_sk$(;8@y#izkH_!Rb%^AFnqIm1_i~##9(%v_R0g)r4b@_Y826r*Jy;a8) zQ=&`1llHo$c%F}W9F2T6E8uC>CgYXi$YDUF#l}PCvu)Dz4Eh0}9+acM6RA87(F_W0 zDGT(Z;c~MZElJB|9)g2bTC{hXy~zI5h3Jn0O?j0$Rofcy^w>uyHA3+465$2{ruJzlyH0zY@cP zqqxh9;-r4aA>-se#Pf_p4N?0oQLdw8h2sma$zeQ-=FaUH5-ujDZ?;NSD zHjOBpfBdljFh!SWJ_UNUQGZ=zvIb!WpWJ)7nIQc5=yojCC~PA4f)D`nZ2+a|#9+e*nvZKG{zUw?z(urVqm7DeaV5#DCh7wYIAC1V z%Z08J74t#;C~w9c$%th;69AGvZ#hcoJbM7xe0E5XJ2ALq67#t|uo%#+Cz%au35p;% z)7m=w)7h27wdw>(-AIA*)QovMFbWLf+_carr^ww1r zC}1jQ5&XT#mJABjUd6LehsxILrJewS?_x$p_SPzs z5e(|xjb}zW&Uzj?*VreG@Tw{qw?n-bWI04@>IJ8iN3)(&)qB4~Vi2-RjbfQ3&xfSFU8*Xz1e=LLyr)|L-*DGt zvKb9jtXGyy4-$g7xc`B!*Ai5Jk}V_qY6@~P3Bl_Q($R<)W8r~hgVr2XHO)#wu);WV zV$uJTyrTgW)ijN;Vs!OMxJ7$A>>2%Xb{ERMtKdd=$b6%`4j;9J)Ic*>Q(AMr6H8o z?%ZJW%?ZXnf0)k>!?rASGZ8&9-kedpinL#e(XoA9rB_kzf)m=gWO(rrj$0bkt61N!cfGa=OsEAt8bE zrqgn2Rp?4!Rd_)^RES_p=8(F-t6R8VbSX&U0}KJS6&s#BU3pzG+jL{wsftfgNZBpG zp&uneAn0MgHU?N_@33g!rj44h?bxPbZIHUZYns@uOnL!{7@!AEtpHBBT#S_a2(Cof zxJ@UvsZf5VWEQzAn5{qCjw!GS0ouTr1MC5wxsorI+7REKn%TBZ54LTaIdx=@lftE! zt^lVNjnI$)$o)R%6MKLQz&o4LsXdiG!KP!!j!kX!{Hdv9$Ly!YTEn@5d4SKCxA*-w z3=@HWRQN%2x4=g);&{g;cSi{`jO?^uuju4I-eSp8o} z*|U?P<<#-fvJ`?Bf4%1Qt^ON^NlH)!XtkOEXAFIx50--8Qt&?q!d5Ql1?lynXx08y znpz)9J$}{xSe9OIi|+X4bnS!N0M5^R09Sw)hC^Qr#vg+Tz+eJB{>le19Qs`Sa{cIZzY!;f z42wysQ5#_V2fzkkH&;K;^XqeWe*eey?Wmd|AbBIKR%4H^R>L=vz=-e!6fwpG8fc6W M;fX66$ZNU?05_r{`v3p{ diff --git a/docs/README.md b/docs/README.md index cb387837..68364ed7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,7 +6,7 @@ title: 'Introduction'

[![markwon](https://img.shields.io/maven-central/v/io.noties.markwon/core.svg?label=markwon)](http://search.maven.org/#search|ga|1|g%3A%22io.noties.markwon%22%20) -[![Build Status](https://travis-ci.org/noties/Markwon.svg?branch=master)](https://travis-ci.org/noties/Markwon) +[![Build](https://github.com/noties/Markwon/workflows/Build/badge.svg)](https://github.com/noties/Markwon/actions) **Markwon** is a markdown library for Android. It parses markdown following with the help of amazing library @@ -79,7 +79,26 @@ and 2 themes included: Light & Dark. It can be downloaded from [releases](ht ::: -## Awesome Markwon + + + +
+ +## \# Awesome Markwon + +
Applications using Markwon: @@ -89,7 +108,7 @@ and 2 themes included: Light & Dark. It can be downloaded from [releases](ht From 2e7d0aa46b4199b0445667c66d7ebc76ab7aea0a Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 23 Dec 2019 17:31:27 +0300 Subject: [PATCH 04/10] Sample handling of details HTML tag --- CHANGELOG.md | 5 + .../io/noties/markwon/SpannableBuilder.java | 2 +- .../core/spans/BulletListItemSpan.java | 57 ++- sample/src/main/AndroidManifest.xml | 1 + .../noties/markwon/sample/MainActivity.java | 5 + .../java/io/noties/markwon/sample/Sample.java | 4 +- .../htmldetails/HtmlDetailsActivity.java | 410 ++++++++++++++++++ .../main/res/layout/activity_html_details.xml | 12 + .../layout/view_html_details_text_view.xml | 8 + .../src/main/res/values/strings-samples.xml | 2 + 10 files changed, 486 insertions(+), 20 deletions(-) create mode 100644 sample/src/main/java/io/noties/markwon/sample/htmldetails/HtmlDetailsActivity.java create mode 100644 sample/src/main/res/layout/activity_html_details.xml create mode 100644 sample/src/main/res/layout/view_html_details_text_view.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 1910f583..2445fff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +# 4.2.1-SNAPSHOT +* Fix SpannableBuilder `subSequence` method +* Introduce Nougat check in `BulletListItemSpan` to position bullet (for bullets to be +positioned correctly when nested inside other `LeadingMarginSpan`s) + # 4.2.0 * `MarkwonEditor` to highlight markdown input whilst editing (new module: `markwon-editor`) * `CoilImagesPlugin` image loader based on [Coil] library (new module: `markwon-image-coil`) ([#166], [#174]) diff --git a/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java b/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java index 6a15a9a8..8d4568d2 100644 --- a/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java +++ b/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java @@ -187,7 +187,7 @@ public CharSequence subSequence(int start, int end) { // if a span was fully including resulting subSequence it's start and // end must be within 0..length bounds s = Math.max(0, span.start - start); - e = Math.max(length, s + (span.end - span.start)); + e = Math.min(length, s + (span.end - span.start)); builder.setSpan( span.what, diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java index 6d8da746..fa366b53 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java @@ -4,6 +4,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; +import android.os.Build; import android.text.Layout; import android.text.style.LeadingMarginSpan; @@ -15,6 +16,13 @@ public class BulletListItemSpan implements LeadingMarginSpan { + private static final boolean IS_NOUGAT; + + static { + final int sdk = Build.VERSION.SDK_INT; + IS_NOUGAT = Build.VERSION_CODES.N == sdk || Build.VERSION_CODES.N_MR1 == sdk; + } + private MarkwonTheme theme; private final Paint paint = ObjectsPool.paint(); @@ -62,28 +70,41 @@ public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int ba final int marginLeft = (width - side) / 2; - // @since 2.0.2 - // There is a bug in Android Nougat, when this span receives an `x` that - // doesn't correspond to what it should be (text is placed correctly though). - // Let's make this a general rule -> manually calculate difference between expected/actual - // and add this difference to resulting left/right values. If everything goes well - // we do not encounter a bug -> this `diff` value will be 0 - final int diff; - if (dir < 0) { - // rtl - diff = x - (layout.getWidth() - (width * level)); - } else { - diff = (width * level) - x; - } - // in order to support RTL final int l; final int r; { - final int left = x + (dir * marginLeft); - final int right = left + (dir * side); - l = Math.min(left, right) + (dir * diff); - r = Math.max(left, right) + (dir * diff); + // @since 4.2.1-SNAPSHOT to correctly position bullet + // when nested inside other LeadingMarginSpans (sorry, Nougat) + if (IS_NOUGAT) { + + // @since 2.0.2 + // There is a bug in Android Nougat, when this span receives an `x` that + // doesn't correspond to what it should be (text is placed correctly though). + // Let's make this a general rule -> manually calculate difference between expected/actual + // and add this difference to resulting left/right values. If everything goes well + // we do not encounter a bug -> this `diff` value will be 0 + final int diff; + if (dir < 0) { + // rtl + diff = x - (layout.getWidth() - (width * level)); + } else { + diff = (width * level) - x; + } + + final int left = x + (dir * marginLeft); + final int right = left + (dir * side); + l = Math.min(left, right) + (dir * diff); + r = Math.max(left, right) + (dir * diff); + + } else { + if (dir > 0) { + l = x + marginLeft; + } else { + l = x - width + marginLeft; + } + r = l + side; + } } final int t = baseline + (int) ((paint.descent() + paint.ascent()) / 2.F + .5F) - (side / 2); diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index ee887f8c..5e0ae714 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -34,6 +34,7 @@ android:windowSoftInputMode="adjustResize" /> + diff --git a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java index db937d19..4cdd6d73 100644 --- a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java @@ -24,6 +24,7 @@ import io.noties.markwon.sample.customextension2.CustomExtensionActivity2; import io.noties.markwon.sample.editor.EditorActivity; import io.noties.markwon.sample.html.HtmlActivity; +import io.noties.markwon.sample.htmldetails.HtmlDetailsActivity; import io.noties.markwon.sample.inlineparser.InlineParserActivity; import io.noties.markwon.sample.latex.LatexActivity; import io.noties.markwon.sample.precomputed.PrecomputedActivity; @@ -127,6 +128,10 @@ static Intent sampleItemIntent(@NonNull Context context, @NonNull Sample item) { activity = InlineParserActivity.class; break; + case HTML_DETAILS: + activity = HtmlDetailsActivity.class; + break; + default: throw new IllegalStateException("No Activity is associated with sample-item: " + item); } diff --git a/sample/src/main/java/io/noties/markwon/sample/Sample.java b/sample/src/main/java/io/noties/markwon/sample/Sample.java index 221ee0bc..36b13cd2 100644 --- a/sample/src/main/java/io/noties/markwon/sample/Sample.java +++ b/sample/src/main/java/io/noties/markwon/sample/Sample.java @@ -25,7 +25,9 @@ public enum Sample { EDITOR(R.string.sample_editor), - INLINE_PARSER(R.string.sample_inline_parser); + INLINE_PARSER(R.string.sample_inline_parser), + + HTML_DETAILS(R.string.sample_html_details); private final int textResId; diff --git a/sample/src/main/java/io/noties/markwon/sample/htmldetails/HtmlDetailsActivity.java b/sample/src/main/java/io/noties/markwon/sample/htmldetails/HtmlDetailsActivity.java new file mode 100644 index 00000000..8c668cf4 --- /dev/null +++ b/sample/src/main/java/io/noties/markwon/sample/htmldetails/HtmlDetailsActivity.java @@ -0,0 +1,410 @@ +package io.noties.markwon.sample.htmldetails; + +import android.app.Activity; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.Bundle; +import android.text.Layout; +import android.text.Spanned; +import android.text.style.ClickableSpan; +import android.text.style.LeadingMarginSpan; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; +import io.noties.markwon.image.ImagesPlugin; +import io.noties.markwon.sample.R; +import io.noties.markwon.utils.LeadingMarginUtils; +import io.noties.markwon.utils.NoCopySpannableFactory; + +public class HtmlDetailsActivity extends Activity { + + private ViewGroup content; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_html_details); + + content = findViewById(R.id.content); + + sample_details(); + } + + private void sample_details() { + + final String md = "# Hello\n\n
\n" + + " stuff with \n\n*mark* **down**\n\n\n" + + "

\n\n" + + "\n" + + "## *formatted* **heading** with [a](link)\n" + + "```java\n" + + "code block\n" + + "```\n" + + "\n" + + "

\n" + + " nested stuff

\n" + + "\n" + + "\n" + + "* list\n" + + "* with\n" + + "\n\n" + + "![img](https://raw.githubusercontent.com/noties/Markwon/master/art/markwon_logo.png)\n\n" + + " 1. nested\n" + + " 1. items\n" + + "\n" + + " ```java\n" + + " // including code\n" + + " ```\n" + + " 1. blocks\n" + + "\n" + + "

The 3rd!\n\n" + + "**bold** _em_\n
" + + "

\n" + + "

\n\n" + + "and **this** *is* how..."; + + final Markwon markwon = Markwon.builder(this) + .usePlugin(HtmlPlugin.create(plugin -> + plugin.addHandler(new DetailsTagHandler()))) + .usePlugin(ImagesPlugin.create()) + .build(); + + final Spanned spanned = markwon.toMarkdown(md); + final DetailsParsingSpan[] spans = spanned.getSpans(0, spanned.length(), DetailsParsingSpan.class); + + // if we have no details, proceed as usual (single text-view) + if (spans == null || spans.length == 0) { + // no details + final TextView textView = appendTextView(); + markwon.setParsedMarkdown(textView, spanned); + return; + } + + final List list = new ArrayList<>(); + + for (DetailsParsingSpan span : spans) { + final DetailsElement e = settle(new DetailsElement(spanned.getSpanStart(span), spanned.getSpanEnd(span), span.summary), list); + if (e != null) { + list.add(e); + } + } + + for (DetailsElement element : list) { + initDetails(element, spanned); + } + + sort(list); + + + TextView textView; + int start = 0; + + for (DetailsElement element : list) { + + if (element.start != start) { + // subSequence and add new TextView + textView = appendTextView(); + textView.setText(subSequenceTrimmed(spanned, start, element.start)); + } + + // now add details TextView + textView = appendTextView(); + initDetailsTextView(markwon, textView, element); + + start = element.end; + } + + if (start != spanned.length()) { + // another textView with rest content + textView = appendTextView(); + textView.setText(subSequenceTrimmed(spanned, start, spanned.length())); + } + } + + @NonNull + private TextView appendTextView() { + final View view = getLayoutInflater().inflate(R.layout.view_html_details_text_view, content, false); + final TextView textView = view.findViewById(R.id.text); + content.addView(view); + return textView; + } + + private void initDetailsTextView( + @NonNull Markwon markwon, + @NonNull TextView textView, + @NonNull DetailsElement element) { + + // minor optimization + textView.setSpannableFactory(NoCopySpannableFactory.getInstance()); + + // so, each element with children is a details tag + // there is a reason why we needed the SpannableBuilder in the first place -> we must revert spans +// final SpannableStringBuilder builder = new SpannableStringBuilder(); + final SpannableBuilder builder = new SpannableBuilder(); + append(builder, markwon, textView, element, element); + markwon.setParsedMarkdown(textView, builder.spannableStringBuilder()); + } + + private void append( + @NonNull SpannableBuilder builder, + @NonNull Markwon markwon, + @NonNull TextView textView, + @NonNull DetailsElement root, + @NonNull DetailsElement element) { + if (!element.children.isEmpty()) { + + final int start = builder.length(); + +// builder.append(element.content); + builder.append(subSequenceTrimmed(element.content, 0, element.content.length())); + + builder.setSpan(new ClickableSpan() { + @Override + public void onClick(@NonNull View widget) { + element.expanded = !element.expanded; + + initDetailsTextView(markwon, textView, root); + } + }, start, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + if (element.expanded) { + for (DetailsElement child : element.children) { + append(builder, markwon, textView, root, child); + } + } + + builder.setSpan(new DetailsSpan(markwon.configuration().theme(), element), start); + + } else { + builder.append(element.content); + } + } + + // if null -> remove from where it was processed, + // else replace from where it was processed with a new one (can become expandable) + @Nullable + private static DetailsElement settle( + @NonNull DetailsElement element, + @NonNull List elements) { + for (DetailsElement e : elements) { + if (element.start > e.start && element.end <= e.end) { + final DetailsElement settled = settle(element, e.children); + if (settled != null) { + + // the thing is we must balance children if done like this + // let's just create a tree actually, so we are easier to modify + final Iterator iterator = e.children.iterator(); + while (iterator.hasNext()) { + final DetailsElement balanced = settle(iterator.next(), Collections.singletonList(element)); + if (balanced == null) { + iterator.remove(); + } + } + + // add to our children + e.children.add(element); + } + return null; + } + } + return element; + } + + private static void initDetails(@NonNull DetailsElement element, @NonNull Spanned spanned) { + int end = element.end; + for (int i = element.children.size() - 1; i >= 0; i--) { + final DetailsElement child = element.children.get(i); + if (child.end < end) { + element.children.add(new DetailsElement(child.end, end, spanned.subSequence(child.end, end))); + } + initDetails(child, spanned); + end = child.start; + } + + final int start = (element.start + element.content.length()); + if (end != start) { + element.children.add(new DetailsElement(start, end, spanned.subSequence(start, end))); + } + } + + private static void sort(@NonNull List elements) { + Collections.sort(elements, (o1, o2) -> Integer.compare(o1.start, o2.start)); + for (DetailsElement element : elements) { + sort(element.children); + } + } + + @NonNull + private static CharSequence subSequenceTrimmed(@NonNull CharSequence cs, int start, int end) { + + while (start < end) { + + final boolean isStartEmpty = Character.isWhitespace(cs.charAt(start)); + final boolean isEndEmpty = Character.isWhitespace(cs.charAt(end - 1)); + + if (!isStartEmpty && !isEndEmpty) { + break; + } + + if (isStartEmpty) { + start += 1; + } + if (isEndEmpty) { + end -= 1; + } + } + + return cs.subSequence(start, end); + } + + private static class DetailsElement { + + final int start; + final int end; + final CharSequence content; + final List children = new ArrayList<>(0); + + boolean expanded; + + DetailsElement(int start, int end, @NonNull CharSequence content) { + this.start = start; + this.end = end; + this.content = content; + } + + @Override + public String toString() { + return "DetailsElement{" + + "start=" + start + + ", end=" + end + + ", content=" + toStringContent(content) + + ", children=" + children + + ", expanded=" + expanded + + '}'; + } + + @NonNull + private static String toStringContent(@NonNull CharSequence cs) { + return cs.toString().replaceAll("\n", "\\n"); + } + } + + private static class DetailsTagHandler extends TagHandler { + + @Override + public void handle( + @NonNull MarkwonVisitor visitor, + @NonNull MarkwonHtmlRenderer renderer, + @NonNull HtmlTag tag) { + + int summaryEnd = -1; + + for (HtmlTag child : tag.getAsBlock().children()) { + + if (!child.isClosed()) { + continue; + } + + if ("summary".equals(child.name())) { + summaryEnd = child.end(); + } + + final TagHandler tagHandler = renderer.tagHandler(child.name()); + if (tagHandler != null) { + tagHandler.handle(visitor, renderer, child); + } else if (child.isBlock()) { + visitChildren(visitor, renderer, child.getAsBlock()); + } + } + + if (summaryEnd > -1) { + visitor.builder().setSpan(new DetailsParsingSpan( + subSequenceTrimmed(visitor.builder(), tag.start(), summaryEnd) + ), tag.start(), tag.end()); + } + } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("details"); + } + } + + private static class DetailsParsingSpan { + + final CharSequence summary; + + DetailsParsingSpan(@NonNull CharSequence summary) { + this.summary = summary; + } + } + + private static class DetailsSpan implements LeadingMarginSpan { + + private final DetailsElement element; + private final int blockMargin; + private final int blockQuoteWidth; + + private final Rect rect = new Rect(); + private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + DetailsSpan(@NonNull MarkwonTheme theme, @NonNull DetailsElement element) { + this.element = element; + this.blockMargin = theme.getBlockMargin(); + this.blockQuoteWidth = theme.getBlockQuoteWidth(); + this.paint.setStyle(Paint.Style.FILL); + } + + @Override + public int getLeadingMargin(boolean first) { + return blockMargin; + } + + @Override + public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) { + + if (LeadingMarginUtils.selfStart(start, text, this)) { + rect.set(x, top, x + blockMargin, bottom); + if (element.expanded) { + paint.setColor(Color.GREEN); + } else { + paint.setColor(Color.RED); + } + paint.setStyle(Paint.Style.FILL); + c.drawRect(rect, paint); + + } else { + + if (element.expanded) { + final int l = (blockMargin - blockQuoteWidth) / 2; + rect.set(x + l, top, x + l + blockQuoteWidth, bottom); + paint.setStyle(Paint.Style.FILL); + paint.setColor(Color.GRAY); + c.drawRect(rect, paint); + } + } + } + } +} diff --git a/sample/src/main/res/layout/activity_html_details.xml b/sample/src/main/res/layout/activity_html_details.xml new file mode 100644 index 00000000..7a61f5d8 --- /dev/null +++ b/sample/src/main/res/layout/activity_html_details.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/sample/src/main/res/layout/view_html_details_text_view.xml b/sample/src/main/res/layout/view_html_details_text_view.xml new file mode 100644 index 00000000..36775ea9 --- /dev/null +++ b/sample/src/main/res/layout/view_html_details_text_view.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/sample/src/main/res/values/strings-samples.xml b/sample/src/main/res/values/strings-samples.xml index a26f62c5..d87585fd 100644 --- a/sample/src/main/res/values/strings-samples.xml +++ b/sample/src/main/res/values/strings-samples.xml @@ -29,4 +29,6 @@ # \# Inline Parser\n\nUsage of custom inline parser + # \# HTML <details> tag\n\n<details> tag parsed and rendered + \ No newline at end of file From b55b1f0dccd595a553d9c6cc56ef6e25eff5d99f Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 14 Jan 2020 16:05:28 +0300 Subject: [PATCH 05/10] Reduce number of invalidations in AsyncDrawable --- CHANGELOG.md | 2 + app/src/main/AndroidManifest.xml | 1 - .../noties/markwon/app/MarkdownRenderer.java | 4 +- .../noties/markwon/image/AsyncDrawable.java | 68 +++++++++++++++++-- .../markwon/image/AsyncDrawableSpan.java | 8 +-- 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2445fff3..ecce3fae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * Fix SpannableBuilder `subSequence` method * Introduce Nougat check in `BulletListItemSpan` to position bullet (for bullets to be positioned correctly when nested inside other `LeadingMarginSpan`s) +* Reduced number of invalidations in AsyncDrawable when result is ready +* AsyncDrawable#hasKnownDimentions -> AsyncDrawable#hasKnownDimensions typo fix # 4.2.0 * `MarkwonEditor` to highlight markdown input whilst editing (new module: `markwon-editor`) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9e5a6805..311a39e2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,7 +4,6 @@ package="io.noties.markwon.app"> - 0; } /** - * @see #hasKnownDimentions() + * @since 4.2.1-SNAPSHOT + */ + @SuppressWarnings({"unused", "WeakerAccess"}) + public boolean hasKnownDimensions() { + return canvasWidth > 0; + } + + /** + * @see #hasKnownDimensions() * @since 4.0.0 */ public int getLastKnownCanvasWidth() { @@ -84,9 +98,10 @@ public int getLastKnownCanvasWidth() { } /** - * @see #hasKnownDimentions() + * @see #hasKnownDimensions() * @since 4.0.0 */ + @SuppressWarnings("WeakerAccess") public float getLastKnowTextSize() { return textSize; } @@ -95,6 +110,7 @@ public Drawable getResult() { return result; } + @SuppressWarnings("WeakerAccess") public boolean hasResult() { return result != null; } @@ -104,10 +120,17 @@ public boolean isAttached() { } // yeah - public void setCallback2(@Nullable Callback callback) { + @SuppressWarnings("WeakerAccess") + public void setCallback2(@Nullable Callback cb) { - this.callback = callback; - super.setCallback(callback); + // @since 4.2.1-SNAPSHOT + // wrap callback so invalidation happens to this AsyncDrawable instance + // and not for wrapped result/placeholder + this.callback = cb == null + ? null + : new WrappedCallback(cb); + + super.setCallback(cb); // if not null -> means we are attached if (callback != null) { @@ -138,6 +161,7 @@ public void setCallback2(@Nullable Callback callback) { /** * @since 3.0.1 */ + @SuppressWarnings("WeakerAccess") protected void setPlaceholderResult(@NonNull Drawable placeholder) { // okay, if placeholder has bounds -> use it, otherwise use original imageSize @@ -175,7 +199,6 @@ public void setResult(@NonNull Drawable result) { } this.result = result; - this.result.setCallback(callback); initBounds(); } @@ -210,6 +233,12 @@ private void initBounds() { final Rect bounds = resolveBounds(); result.setBounds(bounds); + // @since 4.2.1-SNAPSHOT, we set callback after bounds are resolved + // to reduce number of invalidations + result.setCallback(callback); + + // so, this method will check if there is previous bounds and call invalidate _BEFORE_ + // applying new bounds. This is why it is important to have initial bounds empty. setBounds(bounds); invalidateSelf(); @@ -291,6 +320,7 @@ private Rect resolveBounds() { return imageSizeResolver.resolveImageSize(this); } + @NonNull @Override public String toString() { return "AsyncDrawable{" + @@ -302,4 +332,30 @@ public String toString() { ", waitingForDimensions=" + waitingForDimensions + '}'; } + + // @since 4.2.1-SNAPSHOT + // Wrapped callback to trigger invalidation for this AsyncDrawable instance (and not result/placeholder) + private class WrappedCallback implements Callback { + + private final Callback callback; + + WrappedCallback(@NonNull Callback callback) { + this.callback = callback; + } + + @Override + public void invalidateDrawable(@NonNull Drawable who) { + callback.invalidateDrawable(AsyncDrawable.this); + } + + @Override + public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { + callback.scheduleDrawable(AsyncDrawable.this, what, when); + } + + @Override + public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { + callback.unscheduleDrawable(AsyncDrawable.this, what); + } + } } diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java index 0d70b62a..7c979e23 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java @@ -42,11 +42,9 @@ public AsyncDrawableSpan( this.alignment = alignment; this.replacementTextIsLink = replacementTextIsLink; - // additionally set intrinsic bounds if empty - final Rect rect = drawable.getBounds(); - if (rect.isEmpty()) { - drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); - } + // @since 4.2.1-SNAPSHOT we do not set intrinsic bounds + // at this point they will always be 0,0-1,1, but this + // will trigger another invalidation when we will have bounds } @Override From 6d9121b54d6971c4da89d9c263f03626e37eb069 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 14 Jan 2020 16:33:08 +0300 Subject: [PATCH 06/10] Update images plugin documentation page --- docs/docs/v4/image/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/docs/v4/image/README.md b/docs/docs/v4/image/README.md index 62cb8e77..efd3b867 100644 --- a/docs/docs/v4/image/README.md +++ b/docs/docs/v4/image/README.md @@ -184,11 +184,12 @@ imagesPlugin.addSchemeHandler(new SchemeHandler() { :::warning If you wish to add support for **SVG** or **GIF** you must explicitly add these dependencies to your project: -* for `SVG`: `com.caverock:androidsvg:1.4` -* for `GIF`: `pl.droidsonroids.gif:android-gif-drawable:1.2.14` +* to support `SVG`: [com.caverock:androidsvg](https://github.com/BigBadaboom/androidsvg) +* to support `GIF`: [pl.droidsonroids.gif:android-gif-drawable](https://github.com/koral--/android-gif-drawable) -You can try more recent versions of these libraries, but make sure that they doesn't -introduce any unexpected behavior. +For [security reasons](https://github.com/noties/Markwon/issues/186) it's advisable to use latest +versions of these libraries. If you notice compilation and/or runtime issues when used with Markwon, +please [create an issue](https://github.com/noties/Markwon/issues/new) specifying library and library version used. ::: From 130a60265b9f7591126c0aa94f6a0542e64747b3 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 14 Jan 2020 16:40:42 +0300 Subject: [PATCH 07/10] Update android-gif-drawable compileOnly dependency version --- build.gradle | 2 +- docs/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 4bb3392e..881b5c2b 100644 --- a/build.gradle +++ b/build.gradle @@ -63,7 +63,7 @@ ext { 'commonmark-strikethrough': "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:$commonMarkVersion", 'commonmark-table' : "com.atlassian.commonmark:commonmark-ext-gfm-tables:$commonMarkVersion", 'android-svg' : 'com.caverock:androidsvg:1.4', - 'android-gif' : 'pl.droidsonroids.gif:android-gif-drawable:1.2.14', + 'android-gif' : 'pl.droidsonroids.gif:android-gif-drawable:1.2.19', 'jlatexmath-android' : 'ru.noties:jlatexmath-android:0.1.0', 'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0', 'prism4j' : 'io.noties:prism4j:2.0.0', diff --git a/docs/README.md b/docs/README.md index 68364ed7..82143911 100644 --- a/docs/README.md +++ b/docs/README.md @@ -96,7 +96,7 @@ and 2 themes included: Light & Dark. It can be downloaded from [releases](ht
-## \# Awesome Markwon +## # Awesome Markwon
From d8b3d0236828ec52a12e89c2ad242264cc0a9178 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 14 Jan 2020 16:43:58 +0300 Subject: [PATCH 08/10] Update android gradle plugin 3.5.3 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 881b5c2b..98c57018 100644 --- a/build.gradle +++ b/build.gradle @@ -4,8 +4,8 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.2' - classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0' + classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.github.ben-manes:gradle-versions-plugin:0.27.0' } } From ef97b0bc25d1e30f0b3e35cd193fe8de21d1c58d Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 14 Jan 2020 16:58:01 +0300 Subject: [PATCH 09/10] Revert android-gif-drawable version --- build.gradle | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 98c57018..41a8b70b 100644 --- a/build.gradle +++ b/build.gradle @@ -55,6 +55,11 @@ ext { final def commonMarkVersion = '0.13.0' final def daggerVersion = '2.10' + // please note that `pl.droidsonroids.gif:android-gif-drawable:1.2.15` is used due to the minimum + // api level mismatch that Markwon supports (16) and later versions of AndroidGifDrawable (17). + // It should not be a problem as this dependency is used as `compileOnly` and users + // must specify version explicitly (until library's API changes...) + deps = [ 'x-annotations' : 'androidx.annotation:annotation:1.1.0', 'x-recycler-view' : 'androidx.recyclerview:recyclerview:1.0.0', @@ -63,7 +68,7 @@ ext { 'commonmark-strikethrough': "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:$commonMarkVersion", 'commonmark-table' : "com.atlassian.commonmark:commonmark-ext-gfm-tables:$commonMarkVersion", 'android-svg' : 'com.caverock:androidsvg:1.4', - 'android-gif' : 'pl.droidsonroids.gif:android-gif-drawable:1.2.19', + 'android-gif' : 'pl.droidsonroids.gif:android-gif-drawable:1.2.15', 'jlatexmath-android' : 'ru.noties:jlatexmath-android:0.1.0', 'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0', 'prism4j' : 'io.noties:prism4j:2.0.0', From 34f71f13d2ab579437fb5ea861abed0af2f76ff3 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sun, 2 Feb 2020 17:51:11 +0300 Subject: [PATCH 10/10] Prepare 4.2.1 release --- CHANGELOG.md | 2 +- gradle.properties | 2 +- .../noties/markwon/core/spans/BulletListItemSpan.java | 2 +- .../java/io/noties/markwon/image/AsyncDrawable.java | 10 +++++----- .../io/noties/markwon/image/AsyncDrawableSpan.java | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecce3fae..405beaaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -# 4.2.1-SNAPSHOT +# 4.2.1 * Fix SpannableBuilder `subSequence` method * Introduce Nougat check in `BulletListItemSpan` to position bullet (for bullets to be positioned correctly when nested inside other `LeadingMarginSpan`s) diff --git a/gradle.properties b/gradle.properties index f0fee2c1..b0b8871f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ android.enableJetifier=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache -VERSION_NAME=4.2.1-SNAPSHOT +VERSION_NAME=4.2.1 GROUP=io.noties.markwon POM_DESCRIPTION=Markwon markdown for Android diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java index fa366b53..c548ab66 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java @@ -74,7 +74,7 @@ public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int ba final int l; final int r; { - // @since 4.2.1-SNAPSHOT to correctly position bullet + // @since 4.2.1 to correctly position bullet // when nested inside other LeadingMarginSpans (sorry, Nougat) if (IS_NOUGAT) { diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java index 291b77c9..ce6f92d5 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java @@ -73,7 +73,7 @@ public ImageSizeResolver getImageSizeResolver() { /** * @see #hasKnownDimensions() * @since 4.0.0 - * @deprecated 4.2.1-SNAPSHOT + * @deprecated 4.2.1 */ @SuppressWarnings({"unused", "WeakerAccess"}) @Deprecated @@ -82,7 +82,7 @@ public boolean hasKnownDimentions() { } /** - * @since 4.2.1-SNAPSHOT + * @since 4.2.1 */ @SuppressWarnings({"unused", "WeakerAccess"}) public boolean hasKnownDimensions() { @@ -123,7 +123,7 @@ public boolean isAttached() { @SuppressWarnings("WeakerAccess") public void setCallback2(@Nullable Callback cb) { - // @since 4.2.1-SNAPSHOT + // @since 4.2.1 // wrap callback so invalidation happens to this AsyncDrawable instance // and not for wrapped result/placeholder this.callback = cb == null @@ -233,7 +233,7 @@ private void initBounds() { final Rect bounds = resolveBounds(); result.setBounds(bounds); - // @since 4.2.1-SNAPSHOT, we set callback after bounds are resolved + // @since 4.2.1, we set callback after bounds are resolved // to reduce number of invalidations result.setCallback(callback); @@ -333,7 +333,7 @@ public String toString() { '}'; } - // @since 4.2.1-SNAPSHOT + // @since 4.2.1 // Wrapped callback to trigger invalidation for this AsyncDrawable instance (and not result/placeholder) private class WrappedCallback implements Callback { diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java index 7c979e23..915adf8d 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java @@ -42,7 +42,7 @@ public AsyncDrawableSpan( this.alignment = alignment; this.replacementTextIsLink = replacementTextIsLink; - // @since 4.2.1-SNAPSHOT we do not set intrinsic bounds + // @since 4.2.1 we do not set intrinsic bounds // at this point they will always be 0,0-1,1, but this // will trigger another invalidation when we will have bounds }