Reverse Lookup Enums with Kotlin

Kotlin has a lot of super cool things, and Enum Classes are one of them.

We initialize our enums with a string value. Yet a problem arose when we wanted to find the enum using that string value. What’s the best way to find an enum when you have it’s value?

enum class TransmissionType(val dataKey: String) {
    MANUAL_TRANSMISSION("MT"),
    AUTOMATIC_TRANSMISSION("AT")
}

val myValue = "MT"
// how do I use "MT" to get MANUAL_TRANSMISSION ?

It turns out there is a idiomatic way to achieve this using associateBy and the get operator. This technique works really well.

Instead of writing a function to find your enum: MyEnumClass.findMyEnum("AT")
You have code like this: MyEnumClass["AT"]

Instead of explaining it, I’ll just show you an example with some tests.


import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals

enum class TransmissionType(val dataKey: String) {
    MANUAL_TRANSMISSION("MT"),
    AUTOMATIC_TRANSMISSION("AT");

    companion object {
        private val map = TransmissionType.values().associateBy(TransmissionType::dataKey)
        operator fun get(value: String) = map[value]
    }
}

class EnumAssociateByTest {
    @Test
    fun getDataKey() {
        val equipmentType = TransmissionType.MANUAL_TRANSMISSION
        assertEquals(equipmentType.dataKey, "MT")
    }

    @Test
    fun getTypeFromDataKey() {
        // WHEN I try to get an transmission type based on its `dataKey`
        val equipment = TransmissionType["AT"]

        // THEN I get the expected result
        assertNotNull(equipment)
        assertEquals(TransmissionType.AUTOMATIC_TRANSMISSION, equipment!!)
    }

    @Test
    fun getNullFromNonExistentType() {
        // WHEN I try to get an equipment type using a non-existing `dataKey`
        val equipment = TransmissionType["nope"]
        // THEN I get the expected null value
        assertNull(equipment)
    }
}

When learning new techniques, I like to build little examples in IntelliJ with tests.
I’ve found it makes it lot faster to play around than in Android Studio.

Enjoy!

Using ConstraintLayout with Circular Positioning on Android

I was working on a feature for a client that involved custom views with Android. While researching ConstraintLayout, I saw that it had a circular positioning feature. It seemed pretty neat, so I thought I would circle around when finished and build a demo.

The basics of Circular Positioning are fairly straight forward:

  1. You define a view as the center
  2. You create a circular constraint for each view you want to surround it

I learned a lot from the following article:
https://www.journaldev.com/21366/android-constraint-layout-circular-positioning

Features

You can build a circular restraint in a layout file. It’s a great first exercise. Yet, I wanted to be able to change the number of views that circled the center. To do that I needed to create a custom view.

It seemed like it would be a good learning experience. I have never had to create constraints in code before. Judging by what I saw on the internet, few others do either.

My demo lays out my items in a circular layout and gives the option to the user to change the number of items. When changed, the view re-constrains everything in a balanced circle.

For example:
2 items = 50%, 3 items = 33.3%, 4 items = 25%, and so on

circular layout with faces
My custom view – with 8 images surrounding the center

The Custom View

My custom view is called CircularIconLayout

  • It extends ConstraintLayout – simply because I am building a ConstraintLayout!
  • I base the views in the circle on a section count
  • I pass in a layout file that is used for the views in the circle. This allows me to use any type of view I want

When putting everything together, I follow these general steps:

  1. I create a TextView and constrain it to the center (centerView)
  2. Create a separate view for each section of the circle
  3. I calculate where to place the views around the circle:
    1. divide the number of sections by 360
      • example: 360 / 4 = 25 degrees for each section
    2. determine the center of each section
      • example: 25 / 2 = 12.5 degrees is the middle of each section
  4. Create a constraint for each view using constrainCircle()

I keep a list of the views for reference (sectionList). When the user changes the number of sections, I update the list and re-constrain everything to the centerView again.

Here is some code showing how to setup the constraints:

// constrain sections to the centerView
val constraintSet = ConstraintSet()
constraintSet.clone(this)

// constrain centerView to the middle of our (parent) view
constraintSet.connect(centerView.id, ConstraintSet.TOP, this.id, ConstraintSet.TOP)
constraintSet.connect(centerView.id, ConstraintSet.BOTTOM, this.id, ConstraintSet.BOTTOM)
constraintSet.connect(centerView.id, ConstraintSet.START, this.id, ConstraintSet.START)
constraintSet.connect(centerView.id, ConstraintSet.END, this.id, ConstraintSet.END)

// calculate where to place each view surrounding the center
val distanceFromCenter = circleRadius.toDensityPixels()
val segmentDegrees: Float = 360.0f / sectionCount.toFloat()
var angle: Float = segmentDegrees / 2.0f

// constrain each section to the centerView
sectionList.forEach { section ->
    constraintSet.constrainCircle(section.id, centerView.id, distanceFromCenter, angle)
    angle += segmentDegrees
}

constraintSet.applyTo(this)

Formatting the views in the circle is left up to the Activity or Fragment that calls it. For example, the activity could use the sectionList to load images into the ImageViews that are in the circle.

Extra features

I tried to make the demo simple, but I got a little carried away in the Activity:

  • The user can change the number of items displayed in the circle
  • The user ALSO can change the type of views used in the circle. You can switch between images and text

I also added a couple other features:

icu4j or RuleBasedNumberFormat – a library for spelling out numbers. i.e. 1 = “one”, 12 = “twelve”, and so forth.

RandomColors
I found an example for creating random colors from a pool of acceptable colors on Stack Overflow. I made some improvements and used it to generate random colors.

The Demo

For me, code speaks louder than words. Checkout the demo at my github repo:
https://github.com/jjerome00/CircleLayout

demo video gif

Lego Saturn V Rocket

Picture of reading Lego instructions

We finished our Lego Saturn V! Just in time to celebrate the 50th anniversary of the moon landing.

I like to pick projects to do with my kids. Sometimes it’s just a puzzle, and other times it has been Lego. This was one of those projects.

You can find a ton of reviews for this set online, and it seems like I am the last person to complete the set. The reviews are true – it’s a great set, well thought out, and very large. You can even add some lights and sound if you want.

Motivating your family

I have found my kids don’t necessarily want to do something if I ask them. Instead, I have had a lot of luck just starting a project in a common room, and they kind of gather on their own. For instance, I’ll start a puzzle and pretty soon someone shows up. They usually start by asking me what I’m doing. They might make fun of it. Soon they start watching. Then they start helping me. Coincidentally, this also works on my significant other 🙂

How to find one

These sets used to be hard to find, but that doesn’t seem to be the case anymore. If you are having a hard time find this set or another set like it, there are some websites that will alert you when a set is back in stock. In hindsight, I probably could have waited longer for a used set to show up online.

If you are looking to save a little money, you might do well to find a used set. For me, I was only interested in the rocket – I did not care too much about the lunar lander and stand. If I would have waited an extra year I could have saved a lot of money. You might do well to find a set that is missing some of these accessories. At least for me, tracking down missing parts can be part of the fun of constructing a set.

Here are some other Lego projects I have worked on: