Automatically translating Android XML layouts to Jetpack Compose Kotlin code - CheckBox

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello to whoever is watching this i want to work a little bit on recompose and recompose you can find in this uh repository pockmo slash recompose it's a little tool that can convert android layouts in xml to kotlin code using jetpack compose and i want to add a little bit a little bit more features i guess um it started as a kind of proof of concept a hacky project and there are a bunch of xml views that you need to support if you want to use this seriously and i want to see how far i can push it and what makes me super happy is that but you can see here a couple of people started contributing to this so that's fun and yeah so let me just show you what it does i guess so um this is android studio um i will work in android studio and intellij today and whenever you see the ide with the light theme that's android studio and if you see this ide with the dark theme that's actually intellij so in intellij we will write the code for recompose which is by the way a tool that you can install as a plugin in android studio or run on the command line and we are working on the code here in intellij and in android studio we will test it or write compose code just to test things out so yeah let's let's show it so you can see this test function here it's composable currently it's just displaying this image and i already installed the plugin here and i open this layout it's um a constraint layout rendering this face here i just copy all of that code go back to my test method and paste it and you can see here now it's all kotlin code i refresh view here on the the right should show a preview um let me make it smaller it looks exactly like this constraint layout we had here so that's a feature and right now it supports a limited set of views and a limited set of attributes for those views and the idea is to just extend it and on the way learn about compose and learn about the internals of some of the views we have been using all this time so um there's one issue i already looked at that i think is a great candidate for today that's adding support for checkbox a bunch of links here i'm going to open and this will touch all areas of the code base we will need to pass the xml for a checkbox we need to translate it into a data class that is holding all the data about the checkbox we care about and then we need to write the code that translates from this data class to the actual compose code and then since composer's quite new and i haven't worked that much with it actually i need to figure out how actually the checkboxing compose works and yeah so let's maybe start by going to android studio and actually adding a checkbox here and see how this works and if you have any questions just put them into the chat and i'm happy to answer them so apparently i imported the view which is not what i want here um let's quickly check the links link i opened uh so it's check box with a lowercase b and here it is let's see what do we need we seem to be required to provide a checked boolean and it looks like the unchecked change method is also let's create an empty lambda here it's not red refreshing the preview let's see yeah awesome there's a checkbox here see if we make this interactive we can click it but since we do not implement uncheck changed nothing it happens except for the highlighting all right looks good um first thing i'm wondering is is there a text property here it doesn't look like let me actually go into the code now it looks like this is only the checkbox which probably makes sense and composed but if we go back to the view the view usually comes with the text i think which um and xml also makes sense yeah it inherits text view since you i guess you want to click the text as well right and toggle the checkbox so we need to figure out how to do this if you translate a checkbox just into this snippet and the text is obviously missing so um maybe this year i saw this nice blog post which we could maybe quickly check out and maybe there are some examples that make sense so it's about the state handling um doesn't seem to mention text at all search text no so i assume we need to compose our own composable by combining maybe a row let's try this a row with a text hello world yeah i mean the text is not aligned perfectly so that's maybe something we should fix but it is a good starting point if we see a checkbox in xml we translate it into this snippet i see some people join so i'm working on recompose it's a tool that can translate android layouts in xml to kotlin code using jetpack compose and i want to add support for checkboxes and there's this issue and i i'm currently in android studio trying to figure out what is actually the equivalent um compose code that we would write if we want to have a checkbox that looks kind of like the checkbox we would see if we use the checkbox xml element and yeah since checkbox doesn't have a text i assume we need to combine checkbox and text in a row and maybe at some point also make text clickable but i'll leave this for later so let's look at um the recompose code so i guess we start by creating a test file since we do not want to run the plugin all the time and copy and paste code all the time this is super annoying so let's create a quick test case actually let's do this in android studio because here we have better support or layouts let's turn this whole thing into a checkbox and web content some text and then let's also make it checked and that's maybe a good starting point for us we want of course with an eight uh text and checked and the other attributes we look at later um the nice thing if some of the attributes from a view like layout width and height we do not need to care about this the code we will see this later will take care of those attributes that are in every view but that's our little test case and we want to translate this into compose code and yeah if you have any questions trump um drop them into the chat and i will stop and try to answer them all right so this is our test um there are two interesting tests i guess we could look at one is the parser test um if we look at some examples in here so from from xml we pass we create three of those of or we create this layout object which contains a tree of child nodes and they also can have childs again children and we'll get some examples they can be quite verbose if there are a lot of things in the xml like here this is probably a nice small example text view absolute dp sizes if i open this quickly but this is a little text view um with height and text we translate it into a layout that contains a list with only a textview node with the width and height and the text and the text color is null in this case since it's not specified and we can do the same now for our checkbox let's write test basic backbox and then let's pass the checkbox xml file and then we expect layout with a bunch of nodes that we do not have yet and there's no checkbox node yet so let's quickly run this um and we can see the output so of course it failed um we expected an empty layout but we got a layout that contains an unknown node um which is um maybe confusing at first we also pass notes we do not know what they are because we add them into the composable code as comments so if you have let's look at the test this year for example you have a custom view we can't translate this into compose because because we do not know what it is right we could in this case call an awesome view composable but there's no i'm guarantee that this actually exists so what we do right now is um for that we can look at the composer test [Music] the unknown yeah you just look at this snippet here we create a comment um maybe this one because that's the same file awesome view we create a comment that contains this awesome view composable that the user might or might not write for the custom view and then we create all the other things like the modifiers here that we got from the xml because we do understand width and height even for custom view so that's why this one gets passed into you can see here an unknown node so if we would look at the composable code there would be a check box composable but commented out so almost there so let's make sure we pass this so let's look at the parser and let's keep that um this code again so this is the one block that um maps uh xml element names to the parsing function and you can see that's the small subway subset we support so far so there's a bunch of code to write so let's add something for the checkbox if we are using xml pull parser in here and let's quickly check it's a capital b right here the viewer has a capital b the composer will not okay and those methods here that we are calling those are just extension methods on xml pull parser class so we have separate files for those so what we need to write now is function that takes in or that returns a checkbox node so the data classes holding the data for one of those elements they are always called like the view and note added to it note because they are like organized like a tree and before we can implement this let's actually create okay to check box node so this is in this ast for apps abstract syntax tree module and let's create a checkbox node here data class checkbox node if you look at some of the other notes let's open text view and you can see this this view attributes class and this is a class that um is a holder basically for all the attributes that every view has so or can have and currently those are in here and of course we need those in our checkbox too and the nice thing is as i mentioned before if we use this view attributes we have a generic way of passing those so we do not need to pass all those attributes for every node and we need to extend the node interface and the node interface requires us to implement one more method and maybe let's look at this method later so we have a checkbox node it can hold view attributes but we need to keep more right we decided if we go to our test example we want the text and the checked state at least for now so let's keep those two hey um anis i'm i'm not sure how to pronounce your name that's that's the awkward part of streaming whenever someone enters the chat i have no clue how to pronounce the names and yep thank you for contributing to this project i saw you uh also open prs that's awesome um text and checked state yeah so a string and a boolean now we can import this here so how do we pass this [Music] we can borrow code again if we um close this close this go back to our parsing method if we look at textview again like view attributes we only need to call the extension method for it so if we turn the checkbox note here this will already give us the view attributes so now we only need the text entered um boolean and those we can just get from the um xml pull browser so if we play the text and get attribute value um the personnel as a name is the namespace because we have set up the xml pool parser to ignore namespaces and not check them so we need to now define inside the name that we want to use android text this will give us the text it can mean ni so i think we didn't design for this here this needs to be nullable and the checked state is actually interesting because because the checkbox of course if we use it in xml cannot have a checked attribute but the checkbox itself still needs to have a default value check because it needs to render one of the two states so let's see if this is somewhere defined in the docs what the default is where okay this is not part of checkbox it's probably a compound button see checked okay no no dogs at all all right let's say somewhere over here compound button attributes checked indicates the initial checked state yeah i assume it's unchecked by default so i guess we go with that but we do this here on the puzzle so i'll um checked get a tribute value oh i did pronounce it correctly that's and that's great let's add the text here and checked we need to translate this into a boolean do this over here boolean [Music] stamp bars wouldn't there be a pass method on the we do this here two billion does this do if there's not a boolean yeah let's pass boolean on a boolean class seems to return far false everything that is not true let's let's verify this create a scratch file or button um so let's create value ah value 2 boolean so this should be false okay make this nullable and now if we set it to noise it's false okay that's great we used to boolean here past this in here and yeah should be everything we need for the checkbox over here let's copy the license header over and we go to the checkbox write a quick comment passes check box and let's throw in a link to the docs that my helpful times go back to checks here okay so that should be everything for the puzzle so let's pass on our test but still fail because we defined as an empty list here but we can see there's a checkbox node here so let's um write what we actually expect here we expect a checkbox node it should have view attributes and eight let's see what did we define here match paren on wrap content so it should be match paren this should be web content text should be said hello world here hello world and the checked state should be [Music] true yeah true okay let's run this right passes awesome so now we can pass a checkbox and we get a checkbox node now step two is translating a checkbox node into a composable code so let's again start with the test and this is the one of the only projects where i actually do kind of test driven development because it's so easy here to see okay those are my inputs and i exactly know what my outputs are so it's easy to write a test up front again we uses the file name our checkbox.xml and then here we define a composable code we expect so let's run this and we will see probably fail this time with an actual error because yeah we don't know what to do and this will bring us to the method that we ignored last time we are here also copy the license header into this new file that's it so um the composer that takes this tree of nodes and translated into composable code is implemented as a visitor using the visitor pattern so we need to tell or add to the interface a visit function for our new node with a checkbox and then in this accept method all this okay this is one step further now we will see another compile error and this is our composing visitor that is the class that actually translates the notes so let's add one for checkbox here and now let's tell our code how to translate this and there are two things that we are using here one is this writer that's a little helper that um writes kotlin code for us so for for example here above in the text view we say okay we want to write a coil a function coil to a function called name text and it needs a bunch of parameters and this writer will take care of okay how how do i actually write codeline code that does this the internals are not super nice right now i'm at some point this needs to be nicer but it works it is fine so let's start with modifiers this is modifier builder it will look at the node and we'll create all the modifiers for um for this um composable code like if we back to android studio like if we go to the checkbox here there might be there's always this modifier right and then you can do define with and this builder that we defined by default if you just pass in the node we'll do this for all the attributes that it detects that are common in all the views like the width and we know how to translate them to the modifiers what's a complicated thing so i show the example above here where we translate this into text which is quite straightforward write a text with a bunch of parameter we need to translate the checkbox into this which is a little bit more complicated but let's start with the row so we want to have a row and also need some parameters and first the modifiers that we found we need to translate them into the parameters for this row function since if we saw in the checkbox a width like we find here this of course needs to not be here on the actual checkbox it needs to be here we write a row with the modifiers we found then inside we write another call that is the check box box um as parameters it needs to check state and uncheck changed and this format is differently yes and checked and let's see we need a call parameter with name checked and the value will be in this case just so there are different types of parameters because sometimes they can be a little bit more complicated where we need to also translate the parameters but here we can just use a raw value because we only need to write true or false here and i think right now we only accept instant strings here so let's add another way of taking a boolean and turn it into a string here we do not actually care about the boolean value this point anymore as a note.checked then you need another one this is called unchecked change and the value for now will just be an empty uh empty lambda i have a type yeah okay this should give us the row and the checkbox now let's add the text as well another call inside the row name as text parameters restore and this is just a text and this time i think we will leave skipped the named argument so we will not write text equals hello world because that is i think obvious in a text note what this is so we skipped it so we create a call parameter and just ignore the name and set the value immediately and this is a string value it's not a raw value because um if he if he would use a raw value it would look like this we need to actually write it as a string which means like put it into quotation marks and we use note text now there's a problem here no text is nullable and we we wouldn't want to write something like this right this is like super weird and it even explodes here so we only should do this if the node is not actually add a texas number and oh yeah now it's complaining because the smart cast is not possible here since the node is not defined in this grading module it can't trust it that it might not have changed in between write it as this um because if the text is empty you can skip the whole note it doesn't make sense like this and it doesn't even compile and it would also not make sense as this and this does also not so in this case we just um edit as this checkbox you could leave out the row in this case i guess um but i don't i don't think that makes sense does it maybe not for now i think in most situations we actually expected text [Music] in situations where we have a bunch of parameters we can also make this nullable so we could have written something like this and the right call code is smart enough to know okay if this is actually a null parameter i will just skip this but in this case we skip the whole right call code let's um run our test and see what it does of course it fails because we we say it should translate to an empty string right now now what happens so this is what our code wrote a row with the modifier fill marks with because um and and the xml was match parent so that makes sense let's check through uncheck changes in empty lambda for now and it has text hello world so this looks good so let's copy this and drop this into our test function here see how this looks like in android studio yeah i think that is actually nice we could maybe try fixing the alignment here we want this text to i guess be vertic right centered we look at this example it's um definitely centered also has an interesting heading you might want to emulate at some point but now let's maybe center the text also different size but i don't think we care about this detail let's maybe center it at least so that it doesn't look so weird um let's see can we do this with the modifier as well gravity gravity some deprecated has been renamed to a line okay align vertically no alignment particular enter no center vertical does this look like yeah i think that looks better compare this just like here kind of margin of heading um but that's something for the next a new issue to file i think this is already a nice translation definitely better than not translating the checkboxes let's do this as well switch to intellij back to our composer we'll just drop it into the editor as a comment so that we see it [Music] let's see i think we did this before right um oh here we use text align all right text align there's also an option here i guess this is only aligning it inside its own box but let's test um no okay so back let's see how do we do this we have a parameter value that could implement this and we need to create a modifier for this and this is probably the first time we actually need the first time we actually need to do something with the builder not only take the defaults so let's first rename this end this is the row modifier and then inside here text modifier and let's see i guess we need to change how we do this right now this always takes a nodem in this case we do not actually want to pass in the node so may we make this nullable see and we only add the view modifiers if a note if note 9. and let's see we can add a modifier we can add a size let's see don't remember the d okay modifier has a name and also can have a list of parameters and an optional lambda here makes sense okay so the name is a line and then we need a parameter alignment center vertically you can guess again use a raw value here because we exactly know the string that needs to be inserted here yes oh yeah a coil parameter um without a name and yeah write exactly this code in a test again um didn't add anything to the text because we created text modifier but we do not actually use it um need to add it as a parameter to text as well you can now take the text modifier and say translate this into a call parameter lots of inch words if you say them okay so this looks like this now we have a text and it has a modifier and modifier line synthetically it is in here see our preview looks like yeah now the text is centered vertically i think that makes sense let's yeah let's copy this into our test expect this code to come out of it we already know it does so the test should pass here all right so let's make sure we didn't break anything and let's run all the composer tests okay i passed so the same with the parser on all the tests okay all green awesome so let's switch to a share okay and this here okay let's look at the code we wrote control files well actually before we look at the code let's let katie lynn format it okay now let's run kt lend and detect to see if there's any they don't like in our code uh yeah composing visitor too many functions that is definitely true um but this is um kind of expected with the visitor pattern so for now kind of ignore it here um there's definitely an opportunity to make this here nicer but i don't think we will reduce the number of functions so let's run this again okay they are happy one more time run all the tests all right and now let's take one last look at the code um the checkbox node class looks like we could a quick comment bye okay i can't search okay and i need to open the file by hand st check box node data class holding the ad passed checkbox and then let's also drop in the link it's easy to get to the docs if we need to add more things here hey let's look at this again mr visitor we added the visit function for the checkbox and the composing visitor where we do the translation and modifier builder yeah modifier builder we needed to change because we want to use it without a node as well the new boolean raw value the test for our composer plus checkbox now this is the function that actually does the parsing this is the test for the parser and this is our test case great commit this take another look at the number it's issue number 63 issue 3 add basic support 4 check box push this oh i almost pushed to the main branch first we want to do this on a branch open a pull request this will run all the ci and yeah i expect it to be green because we run the test detect kt limit so then we can match it so um 57 minutes um i think that's good so if anyone is now interested in contributing go ahead either file issues pick one of the issues um i labeled one with good first issue or help wanted um big thank you again and to those people that already contributed that's pretty awesome it's a fun little project to learn about compose or view xml without writing a bunch of ui and yeah if another thing that would be awesome is if you have layout files that you want to share um i'm interested in getting more real-life test cases um then i can drop them into the repo and figure out what's missing all issues for that and slowly make the tests pass for this for those um during my heated layouts basically um yeah so thank you to everyone who watched and if you like this please hello and i hope to do this again yeah let me know if there are things you want to see thank you very much bye bye you
Info
Channel: Dev Stories
Views: 880
Rating: 5 out of 5
Keywords: android, jetpack compose, compose, recompose, android layout, layout xml, android views, view to compose, translating, AST, jetpack compose ui, android compose
Id: vVrIXnGIdso
Channel Id: undefined
Length: 52min 5sec (3125 seconds)
Published: Thu Oct 01 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.