From 240ce59cf81cad0a812f85f09002912da2b163bb Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Fri, 11 Feb 2022 13:11:39 +0530 Subject: [PATCH] Added support for layer list drawables --- .idea/misc.xml | 1 + .../main/assets/data/common/gradle-plugin.zip | Bin 37280 -> 37274 bytes .../drawable/DrawableParserFactory.java | 52 ++++--- .../inflater/drawable/IDrawableParser.java | 65 ++++++++- .../drawable/InsetDrawableParser.java | 4 +- .../inflater/drawable/LayerListParser.java | 131 ++++++++++++++++++ .../drawable/ShapeDrawableParser.java | 56 ++++---- .../itsaky/inflater/util/TextDrawable.java | 66 +++++++++ 8 files changed, 318 insertions(+), 57 deletions(-) create mode 100644 xml-inflater/src/main/java/com/itsaky/inflater/drawable/LayerListParser.java create mode 100644 xml-inflater/src/main/java/com/itsaky/inflater/util/TextDrawable.java diff --git a/.idea/misc.xml b/.idea/misc.xml index f788d142e..c381c73e5 100755 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -57,6 +57,7 @@ + diff --git a/app/src/main/assets/data/common/gradle-plugin.zip b/app/src/main/assets/data/common/gradle-plugin.zip index 9d3c2ddd6f4311ea7ab863d7c4e61469658d3d4c..d009af1d1dd5c79210cb95946a752a4cf8c60485 100644 GIT binary patch delta 2236 zcmZWp2UL?+6i)smB%lm|fRQRe#lbR!1Vo4sDI+AZ1dAR8t%D^;3CIo*AcO!a`ozH~ zD{4_uW+|=OL|aG2Z2_y`D2m4g3f3x8`tn$Y=A3)JKlgq2``>@x_ijZsR$PtM@$dw< zFn*%|UyB~VXY8aZ0ZtH_W^w%YG5E|aA=DzbOW>zm}(9^1E@N4pw;HErc1$3(R5 z<(@^Ho692N%8aw0(q42^YNX5hPW8GKwOmWPc^x$RE5q`!Hf%TPyLwRjEf_@d65lbvq~4aw6ShgbB*#a?jm;}eKl zI2?t7Q*{ATkdpzIypF@SXV=#?c?sAK-aNLKt%J9{w>QhTS+G*z?IW=F5)g3eg%*bE zlnY^V7Qyg`%~|DSOH#^a;ONt_x*{uz=cTu)f14^d`#&hHo{@2;#<=XK9p=0DbnWZM ztLqH$pOv#f1SQ0iq}0SK7!-mlKkBNbl-R#yV?xi6{f>_o)Va;cuk=b1z^SvBbB@pK z5M2ylIr|;DAN_fX*3#Iuv>>3X85(%`5}v@N5bF*Y%?xnNt{&0f#vxffY`xxlKkBIX zPI%a2vlrE~X9#+u=B#)s<=<-^u}CF49&-OQw9ZMFdiKP1NvDnIFt<_=_-d=AM(pB; ztcuslae2)h!B z5hf>|Q(>c1(q}wHbs$B>W!<1Z#v8~|>=5IZ6se|a;Z#>FlMV2(JTS6b3sj}LpsZJp zv?>^spez|I6Kz4x{jkd~Q~?j>Tj*SScsMlBAFl(-3iZ?1LkDNkp@UZ@lm80g8rM$y zbv=0V62E}SmQyt9BDRM{(*Imw_0Pa^yYvlRQ33Z1YJo>fQqXN@H_lA6_nps%Uk9*~ zF6|-PSCa8_&U3DIhF@cbl1$qIz55=$wc$>Sk{4n$UgG=A_wRJFbd#IthDMERJ!)w8 z_WnWJl)dWK2^}hFPFb(nY938y!OYiEZp`F)%t~qfzQz09LfUXoA9v>KR2ONHe}8fN z<3K8>Lz^SY+O}<_Pg<2-!%(fRx_j=Dqm|%Hnx}Ie!&e~S+u7E$poLit3^tp|W3FWJ zSWQg=K9fzJ;@)TB){*1xb^4+~#w$olyfzNHkiidgBJ}79Kl2m$X3yKJVqR{2GJo1~ zMf~gP9$#Bi^=%w6eL%H?{dR@H`9jXfpUJj|*8-1Y5DAJRiu=XN8~@H5ydER&sYz|i zbN0XL5qgUnv#GL!lCY`p*o7eG125$dTSe;Xb6O6%1VQDDsp`ROTc-9^B_3x>B;7io zmo3abJ)$3fV?d)e@ zv`pu>;<*k+Mbst_VPEO*U$Z#3UA8of_T_%nAl^ATHxn}tAs-rKl_G4&Dnl5MU5;=t zyBrx;H7!AjM2P;Nu|my>M;=9^0_@L;r>lI7E8sK>DbhOjfTocS^JUtuG zWYf`J2TYH+0mUvO?0(Exi5V!6jh2+iOt1|?lxD=5ff1QDQqs*c!CsE1=Ue*m@t7fD za;UP}b!^8E%xnDnAj-uOP?`4)k{E&#u5n1YE}srU@<(47oo|A*#*d{Lr~y9trRU9I zwQADx)YP~MV?;CHS)hkx*A|#y*Cx~F3iOeNi%q9A7}jRM;HzmwCQfMFOw<6JU8DOD z>@vYDlhD$Rq}kx)So&v}wn&*smuHQ>)n>N|c6u`Xh)A@yo!S&Mzu>D~VW>C7F?B-l z5s?fu_lzDq8f}oA@xOw*lLZ+P1N4Dv6Au=Q|K#F*BB;L9YU*}WlVdJq(P1nbXG4^W zkEQ`-x+6%<(M9e>qXKLwq+;}RxZn(ibF|Sb)h@l7LWPRxGT~sg`>RH@$v}$Iy#^ZH I8LE~40GMqU?f?J) delta 2264 zcmZWq2~<-@6#YL55~6@qfwHtfMeqn{5)vW`3JC~g0Ua9a?)|%S|MJI9>652ikJYE*x&vhxGCz}12-Dh`J1O)69n~{4XCLVO0jxvyV7pQ*zPMUUs^Zv9@nb$Z{PUM zdql1BO4c1U#ht41xU>k?J%LHpLC)j1mzJ10QZpigURblsiYIGAt$IlvrOjS)pGQfu z`8s8R-tDE_=)xPeWfl)4fv3QM0A~M_cJ7<*vF$XaM^j}fErhjk?I(lJ$u-F{UEgve z<6@gRs{~{U4a2BZjHt%K$$`hfQ+JKKa|6AG#ilcuBEB<=uJ{xn_W%<*kt z`OUzz1D&#rpDcg{A}sLV0&#e;o7XdRn&dcUO`$aAKYy~(^76ZRagP>7c9^U#ZmssD zcn^i8JNX5=`o%}0;3!PtF39e3~p};J!fP2Y5xfyd$CDzRGUKT>A!BRf&F`%NRq+bmcb&y!}5Js!4BJc z?v+wuqq$m{yoNc^IVm=Je==(H9R?cp3X#^rXjzd+J&$8jk&lw>MgEQCpgvJ$)@=hu z2t1q&bV$9y{VW<7j9rI9MR8IRg0@IAkoQl>M7}$r2>FD>p9x>PBxw?-5?uL3ht=Tk z7(Sqz=hx(9PCR&>3o*2rCguK6hJ1!LFFcM74Nb2xZgb>13D1gp1e z=I!gtRLeK7mpeFas;5?%_2hM#ZAcI9tTZsz`SkEG*D;7`9ui?w|b!q zpG^;NaTbW!92UEQe%iNzUN2;D{A+}Md_F!c?$+w>!Zd1L1}n4FhfuP!$e-!U;&4PY zLT3^AR)4EqOQv6|qV=1Vih}-@3cneCn^v}%D5i169KEqi(_q{QF3?D&ddZ=fi92!i zudSAzP|FGP|1c`Vn=azZAN=Ro{?q4IOzME^`@e3~5)sAZu$`V)W7lc*q1| zAH30niqQp6ZFCJr7MHZG7{pUb?u_0w6-34*-wM}16F~hcZ)dA`|J*u?rTcaJrB4&% z@d6dsjNaPP;3!I=o}C|YvTs?{#4!7N(-hlk^(!3AmRr`2%i^aRrX&@q8tA7TLh7kX zJB++A{Rr|y=|_+di53a+GbHE*^$|mb6sZvP2Cz>dwI($A-_3@~6GPLCa(O5f#85*( zl5!RTqU#D*Wze*NlLRmbj4GW-&3d3D)(!~wE+pyF;G?7CDgjQKOa8y5HD$h;u_zM5 z0^%^tQ?nWL}Wm(`u@XZ%QWf`KGJy{l{y|Iv!?=YS4BNi{-l!ReYT@3TmBIE(1 zY%wa(NcZwwO`^V9m*@qLzYRv1oR4!0 z?O+-o*0Ba+yn$=_Y?RWWeHJ9QU5Flbw*5JVs35)yW$70%S_VzKAa^ua8c52Sl9yKZ zg8`aRF3(Q^F}X`XPtGi)WzIUR_b7u6(h?Rc;FbN^q diff --git a/xml-inflater/src/main/java/com/itsaky/inflater/drawable/DrawableParserFactory.java b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/DrawableParserFactory.java index 588630820..e08ffcaf0 100644 --- a/xml-inflater/src/main/java/com/itsaky/inflater/drawable/DrawableParserFactory.java +++ b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/DrawableParserFactory.java @@ -55,13 +55,13 @@ public abstract class DrawableParserFactory { * is an XML document, then a suitable parser is determined by looking at the root tag of the * drawable. * - * @param context The context. This will be used for obtaining app resources. - * @param file The file to parse. + * @param context The context. This will be used for obtaining app resources. + * @param file The file to parse. * @param resourceFinder The resource finder. Used for finding references to another resources. * @return A new {@link IDrawableParser} instance if the inputs are valid, or {@code null} if there were any - * issues creating the parser. + * issues creating the parser. * @throws XmlPullParserException Thrown by the {@link XmlPullParser#setInput(Reader)}. - * @throws IOException Thrown by {@link XmlPullParser#next()} + * @throws IOException Thrown by {@link XmlPullParser#next()} */ @Nullable public static IDrawableParser newParser (@NonNull final Context context, @NonNull final File file, final IResourceTable resourceFinder) throws XmlPullParserException, IOException { @@ -86,13 +86,13 @@ public abstract class DrawableParserFactory { /** * Create a new drawable parser for the given xml code. * - * @param xmlDrawable The XML code. This must be valid. + * @param xmlDrawable The XML code. This must be valid. * @param resourceFinder The resource finder. Used for finding references to another resources. * @param displayMetrics This will be used by generated parsers to parse dimension vlaues. * @return A new {@link IDrawableParser} instance if the inputs are valid, or {@code null} if there were any - * issues creating the parser. + * issues creating the parser. * @throws XmlPullParserException Thrown by the {@link XmlPullParser#setInput(Reader)}. - * @throws IOException Thrown by {@link XmlPullParser#next()} + * @throws IOException Thrown by {@link XmlPullParser#next()} */ @Nullable public static IDrawableParser newXmlDrawableParser (String xmlDrawable, IResourceTable resourceFinder, DisplayMetrics displayMetrics) throws XmlPullParserException, IOException { @@ -106,33 +106,45 @@ public abstract class DrawableParserFactory { while (event != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { final var name = parser.getName (); - switch (name) { - case "shape" : - return new ShapeDrawableParser (parser, resourceFinder, displayMetrics); - case "vector" : - return new NoParser (VectorMasterDrawable.fromXML (xmlDrawable)); - default: - return null; - } + return parserForTag (xmlDrawable, resourceFinder, displayMetrics, parser, name); } event = parser.next (); } // TODO Implement parsers for these root tags if possible // 1. - // 2. + // 2. ------ DONE // 3. // 4. // 5. // 6. - // 7. + // 7. ----------- DONE // 8. // 9. - // We don't support parsing of this type of drawable + // Cannot parse this type of drawable return null; } + @Nullable + public static IDrawableParser parserForTag (String xmlDrawable, IResourceTable resourceFinder, DisplayMetrics displayMetrics, XmlPullParser parser, @NonNull String name) throws XmlPullParserException { + switch (name) { + case "shape": + return new ShapeDrawableParser (parser, resourceFinder, displayMetrics, IDrawableParser.ANY_DEPTH); + case "inset": + return new InsetDrawableParser (parser, resourceFinder, displayMetrics, IDrawableParser.ANY_DEPTH); + case "layer-list": + return new LayerListParser (parser, resourceFinder, displayMetrics, IDrawableParser.ANY_DEPTH); + case "vector": + if (xmlDrawable != null) { + return new NoParser (VectorMasterDrawable.fromXML (xmlDrawable)); + } + return null; + default: + return null; + } + } + /** * Instead of parsing anything, this returns the provided drawable. */ @@ -141,10 +153,10 @@ public abstract class DrawableParserFactory { private final Drawable parsed; protected NoParser (final Drawable parsed) { - super (null, null, null); + super (null, null, null, ANY_DEPTH); this.parsed = parsed; } - + @Override public Drawable parse () { return parsed; diff --git a/xml-inflater/src/main/java/com/itsaky/inflater/drawable/IDrawableParser.java b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/IDrawableParser.java index d6773e8ca..a57529c6d 100644 --- a/xml-inflater/src/main/java/com/itsaky/inflater/drawable/IDrawableParser.java +++ b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/IDrawableParser.java @@ -33,15 +33,44 @@ import org.xmlpull.v1.XmlPullParser; */ public abstract class IDrawableParser extends CommonParseUtils { - protected final XmlPullParser parser; + public static final int ANY_DEPTH = -1; - protected IDrawableParser (XmlPullParser parser, IResourceTable resourceFinder, DisplayMetrics displayMetrics) { - super(resourceFinder, displayMetrics); + protected final XmlPullParser parser; + protected int minDepth; + + protected IDrawableParser (XmlPullParser parser, IResourceTable resourceFinder, DisplayMetrics displayMetrics, int minDepth) { + super (resourceFinder, displayMetrics); this.parser = parser; + this.minDepth = minDepth; } + /** + * Parse the drawable using the already provided parser and data. + * + * @return The parsed {@link Drawable} or null if the parse was unsuccessful. + * @throws Exception If any fatal error occurred while parsing the drawable. + */ public abstract Drawable parse () throws Exception; + /** + * Set the minimum depth that this parser should keep parsing. + * Subclasses are expected to parse child tags with depths greater + * than this specified value. + * + * @param minDepth The minimum depth of this parser. + * @return this instance for chained method calls. + */ + public IDrawableParser setMinDepth (int minDepth) { + this.minDepth = minDepth; + return this; + } + + /** + * Find the index of the attribute with the given name. + * + * @param name The name of the attribute to look for. + * @return The index of the attribute or -1. + */ protected int attrIndex (final String name) { for (int i = 0; i < this.parser.getAttributeCount (); i++) { if (this.parser.getAttributeName (i).equals (name)) { @@ -52,23 +81,45 @@ public abstract class IDrawableParser extends CommonParseUtils { return -1; } + /** + * Get the value of the attribute at the given index. + * + * @param index The index of the attribute. + * @return The value of the attribute. + */ protected String value (int index) { return parser.getAttributeValue (index); } - protected boolean isApi26() { + /** + * Checks if the drawable parser is allowed to parse at the current depth. + * This must be checked if the drawable parser keeps looking for {@link XmlPullParser#START_TAG} + * or {@link XmlPullParser#END_TAG}. + *

+ * The {@link LayerListParser} can contain tags which are expected to be parsed by other parsers. So, + * if the nesting parser does not check if this method if true, it might consume all + * the events and the {@link LayerListParser} will have invalid data to parse. In some cases, the nested + * parser might consume all the events until {@link XmlPullParser#END_DOCUMENT}. + * + * @return true if the parser can keep parsing, false otherwise. + */ + protected boolean canParse () { + return this.parser.getDepth () >= minDepth; + } + + protected boolean isApi26 () { return Build.VERSION.SDK_INT >= 26; } - protected boolean isApi28() { + protected boolean isApi28 () { return Build.VERSION.SDK_INT >= 28; } - protected boolean isApi29() { + protected boolean isApi29 () { return Build.VERSION.SDK_INT >= 29; } - protected boolean isApi30() { + protected boolean isApi30 () { return Build.VERSION.SDK_INT >= 30; } } diff --git a/xml-inflater/src/main/java/com/itsaky/inflater/drawable/InsetDrawableParser.java b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/InsetDrawableParser.java index 6dbd32f68..3742cce10 100644 --- a/xml-inflater/src/main/java/com/itsaky/inflater/drawable/InsetDrawableParser.java +++ b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/InsetDrawableParser.java @@ -35,8 +35,8 @@ import org.xmlpull.v1.XmlPullParser; */ public class InsetDrawableParser extends IDrawableParser { - protected InsetDrawableParser (XmlPullParser parser, IResourceTable resourceFinder, DisplayMetrics displayMetrics) { - super (parser, resourceFinder, displayMetrics); + protected InsetDrawableParser (XmlPullParser parser, IResourceTable resourceFinder, DisplayMetrics displayMetrics, int minDepth) { + super (parser, resourceFinder, displayMetrics, minDepth); } @Override diff --git a/xml-inflater/src/main/java/com/itsaky/inflater/drawable/LayerListParser.java b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/LayerListParser.java new file mode 100644 index 000000000..907ef2382 --- /dev/null +++ b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/LayerListParser.java @@ -0,0 +1,131 @@ +/* + * This file is part of AndroidIDE. + * + * AndroidIDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AndroidIDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AndroidIDE. If not, see . + */ +package com.itsaky.inflater.drawable; + +import static com.itsaky.inflater.util.Preconditions.assertNotBlank; + +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.util.DisplayMetrics; + +import androidx.annotation.NonNull; + +import com.itsaky.androidide.app.BaseApplication; +import com.itsaky.inflater.IResourceTable; +import com.itsaky.inflater.util.TextDrawable; + +import org.jetbrains.annotations.Contract; +import org.xmlpull.v1.XmlPullParser; + +/** + * Parser for parsing <layer-list> drawables. + * + * @author Akash Yadav + */ +public class LayerListParser extends IDrawableParser { + + protected LayerListParser (XmlPullParser parser, IResourceTable resourceFinder, DisplayMetrics displayMetrics, int minDepth) { + super (parser, resourceFinder, displayMetrics, minDepth); + } + + @Override + public Drawable parse () throws Exception { + final var layer = new LayerDrawable (new Drawable[0]); + var index = -1; + var value = ""; + var event = parser.getEventType (); + int left = 0, top = 0, right = 0, bottom = 0; + var parseInner = true; + while (event != XmlPullParser.END_DOCUMENT && canParse ()) { + if (event == XmlPullParser.START_TAG) { + final var name = parser.getName (); + if ("item".equals (name)) { + index = attrIndex ("drawable"); + Drawable drawable = null; + if (index != -1) { + value = value (index); + assertNotBlank (value, "Invalid value for android:drawable attribute"); + drawable = parseDrawable (value, BaseApplication.getBaseInstance ()); + + // if the android:drawable is specified, we do not parse the inner elements of + parseInner = false; + } + + index = attrIndex ("left"); + left = index == -1 ? 0 : parseDimension (value (index), 0); + + index = attrIndex ("top"); + top = index == -1 ? 0 : parseDimension (value (index), 0); + + index = attrIndex ("right"); + right = index == -1 ? 0 : parseDimension (value (index), 0); + + index = attrIndex ("bottom"); + bottom = index == -1 ? 0 : parseDimension (value (index), 0); + + if (drawable == null) { + parseInner = true; + } else { + addLayer (layer, drawable, left, top, right, bottom); + } + + if (!parseInner) { + skipToEndTag (this.parser.getDepth ()); + } + } else if (parser.getDepth () > 2 && parseInner) { + // depth 1 = + // depth 2 = + // depth > 2 = child drawables inside tag + final var parser = DrawableParserFactory.parserForTag (null, resourceFinder, displayMetrics, this.parser, name); + if (parser != null) { + parser.setMinDepth (this.parser.getDepth ()); + var d = parser.parse (); + if (d == null) { + d = unsupported (); + } + + addLayer (layer, d, left, top, right, bottom); + } else { + addLayer (layer, unsupported (), left, top, right, bottom); + } + } + } + event = parser.next (); + } + + return layer; + } + + private void addLayer (LayerDrawable layer, Drawable drawable, int left, int top, int right, int bottom) { + final int index = layer.addLayer (drawable); + layer.setLayerInset (index, left, top, right, bottom); + } + + private void skipToEndTag (int depth) throws Exception { + for (var event = parser.getEventType (); event != XmlPullParser.END_DOCUMENT; event = parser.next ()) { + if (event == XmlPullParser.END_TAG && depth == parser.getDepth ()) { + break; + } + } + } + + @NonNull + @Contract(" -> new") + private Drawable unsupported () { + return new TextDrawable ("Unsupported drawable", displayMetrics); + } +} diff --git a/xml-inflater/src/main/java/com/itsaky/inflater/drawable/ShapeDrawableParser.java b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/ShapeDrawableParser.java index 561ecd2ee..db7e072a3 100644 --- a/xml-inflater/src/main/java/com/itsaky/inflater/drawable/ShapeDrawableParser.java +++ b/xml-inflater/src/main/java/com/itsaky/inflater/drawable/ShapeDrawableParser.java @@ -44,14 +44,14 @@ import java.util.Arrays; */ public class ShapeDrawableParser extends IDrawableParser { - protected ShapeDrawableParser (XmlPullParser parser, IResourceTable resourceFinder, DisplayMetrics displayMetrics) { - super (parser, resourceFinder, displayMetrics); + protected ShapeDrawableParser (XmlPullParser parser, IResourceTable resourceFinder, DisplayMetrics displayMetrics, int minDepth) { + super (parser, resourceFinder, displayMetrics, minDepth); } @Nullable @Override public Drawable parse () throws Exception { - + final var drawable = new GradientDrawable (); var index = attrIndex ("shape"); @@ -66,7 +66,7 @@ public class ShapeDrawableParser extends IDrawableParser { index = attrIndex ("thickness"); drawable.setThickness (index == -1 ? 0 : parseDimension (value (index), 0)); - + index = attrIndex ("thicknessRatio"); drawable.setThicknessRatio (index == -1 ? 1f : Float.parseFloat (value (index))); } @@ -75,7 +75,7 @@ public class ShapeDrawableParser extends IDrawableParser { drawable.setUseLevel (index != -1 && parseBoolean (value (index))); var event = parser.getEventType (); - while (event != XmlPullParser.END_DOCUMENT) { + while (event != XmlPullParser.END_DOCUMENT && canParse ()) { final var name = parser.getName (); if (event == XmlPullParser.START_TAG) { switch (name) { @@ -85,16 +85,16 @@ public class ShapeDrawableParser extends IDrawableParser { case "gradient": parseGradient (drawable); break; - case "padding" : + case "padding": parsePadding (drawable); break; - case "size" : + case "size": parseSize (drawable); break; - case "solid" : + case "solid": parseSolid (drawable); break; - case "stroke" : + case "stroke": parseStroke (drawable); break; } @@ -108,7 +108,7 @@ public class ShapeDrawableParser extends IDrawableParser { private void parseStroke (@NonNull final GradientDrawable drawable) { var index = attrIndex ("width"); var strokeWidth = 0; - if (index != - 1) { + if (index != -1) { drawable.setStroke (strokeWidth = parseDimension (value (index), 0), Color.TRANSPARENT); } @@ -158,7 +158,7 @@ public class ShapeDrawableParser extends IDrawableParser { final var rect = new Rect (); if (!drawable.getPadding (rect)) { - rect.set (0,0,0,0); + rect.set (0, 0, 0, 0); } var changed = false; @@ -167,19 +167,19 @@ public class ShapeDrawableParser extends IDrawableParser { rect.left = parseDimension (value (index), 0); changed = true; } - + index = attrIndex ("top"); if (index != -1) { rect.top = parseDimension (value (index), 0); changed = true; } - + index = attrIndex ("right"); if (index != -1) { rect.right = parseDimension (value (index), 0); changed = true; } - + index = attrIndex ("bottom"); if (index != -1) { rect.bottom = parseDimension (value (index), 0); @@ -196,26 +196,26 @@ public class ShapeDrawableParser extends IDrawableParser { drawable.setOrientation (index == -1 ? GradientDrawable.Orientation.LEFT_RIGHT : parseGradientOrientation (value (index))); index = attrIndex ("centerX"); - var center = index == - 1 ? drawable.getGradientCenterX () : Float.parseFloat (value (index)); + var center = index == -1 ? drawable.getGradientCenterX () : Float.parseFloat (value (index)); drawable.setGradientCenter (center, drawable.getGradientCenterY ()); - + index = attrIndex ("centerY"); - center = index == - 1 ? drawable.getGradientCenterX () : Float.parseFloat (value (index)); + center = index == -1 ? drawable.getGradientCenterX () : Float.parseFloat (value (index)); drawable.setGradientCenter (drawable.getGradientCenterX (), center); - final var colors = new int [3]; + final var colors = new int[3]; var changed = false; Arrays.fill (colors, -1); index = attrIndex ("centerColor"); if (index != -1) { - colors [1] = parseColor (value (index), appContext ()); + colors[1] = parseColor (value (index), appContext ()); changed = true; } index = attrIndex ("endColor"); if (index != -1) { - colors [2] = parseColor (value (index), appContext ()); + colors[2] = parseColor (value (index), appContext ()); changed = true; } @@ -241,11 +241,11 @@ public class ShapeDrawableParser extends IDrawableParser { private int parseGradientType (String value) { switch (value) { - case "radial" : + case "radial": return GradientDrawable.RADIAL_GRADIENT; - case "sweep" : + case "sweep": return GradientDrawable.SWEEP_GRADIENT; - case "linear" : + case "linear": default: return GradientDrawable.LINEAR_GRADIENT; } @@ -307,14 +307,14 @@ public class ShapeDrawableParser extends IDrawableParser { if (index != -1) { radii[2] = radii[3] = parseDimension (value (index), 0); changed = true; - + } index = attrIndex ("bottomLeftRadius"); if (index != -1) { radii[4] = radii[5] = parseDimension (value (index), 0); changed = true; - + } index = attrIndex ("bottomRightRadius"); @@ -331,13 +331,13 @@ public class ShapeDrawableParser extends IDrawableParser { @Contract(pure = true) private int parseShape (@NonNull String value) { switch (value) { - case "oval" : + case "oval": return GradientDrawable.OVAL; case "line": return GradientDrawable.LINE; - case "ring" : + case "ring": return GradientDrawable.RING; - case "rectangle" : + case "rectangle": default: return GradientDrawable.RECTANGLE; } diff --git a/xml-inflater/src/main/java/com/itsaky/inflater/util/TextDrawable.java b/xml-inflater/src/main/java/com/itsaky/inflater/util/TextDrawable.java new file mode 100644 index 000000000..2ba16713e --- /dev/null +++ b/xml-inflater/src/main/java/com/itsaky/inflater/util/TextDrawable.java @@ -0,0 +1,66 @@ +package com.itsaky.inflater.util; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.DisplayMetrics; +import android.util.TypedValue; + +import androidx.annotation.NonNull; + +public class TextDrawable extends Drawable { + private static final int DEFAULT_COLOR = Color.WHITE; + private static final int DEFAULT_TEXT_SIZE = 15; + private final Paint mPaint; + private final CharSequence mText; + private final int mIntrinsicWidth; + private final int mIntrinsicHeight; + + public TextDrawable (CharSequence text, @NonNull DisplayMetrics displayMetrics) { + mText = text; + mPaint = new Paint (Paint.ANTI_ALIAS_FLAG); + mPaint.setColor (DEFAULT_COLOR); + mPaint.setTextAlign (Align.CENTER); + float textSize = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_SP, + DEFAULT_TEXT_SIZE, displayMetrics); + mPaint.setTextSize (textSize); + mIntrinsicWidth = (int) (mPaint.measureText (mText, 0, mText.length ()) + .5); + mIntrinsicHeight = mPaint.getFontMetricsInt (null); + } + + @Override + public void draw (Canvas canvas) { + Rect bounds = getBounds (); + canvas.drawText (mText, 0, mText.length (), + bounds.centerX (), bounds.centerY (), mPaint); + } + + @Override + public int getOpacity () { + return mPaint.getAlpha (); + } + + @Override + public int getIntrinsicWidth () { + return mIntrinsicWidth; + } + + @Override + public int getIntrinsicHeight () { + return mIntrinsicHeight; + } + + @Override + public void setAlpha (int alpha) { + mPaint.setAlpha (alpha); + } + + @Override + public void setColorFilter (ColorFilter filter) { + mPaint.setColorFilter (filter); + } +} \ No newline at end of file