jetc.dev Newsletter Issue #57

Published: 2021-03-23

This week, we spend a chunk of time thinking about testing, both for getting our code right now and to be able to adapt to the inevitable changes that are going to come about for how we do Compose UI development.

In addition, we explore animations and the Canvas(), adapting our legacy Compose code to the effect system, utility composables for design grids and zooming, and more!

Plus, we see what goes on inside Adam Powell’s head!

One Off the Stack, One Off the Slack

You’ve got questions. That’s understandable!

Testing Text Entry

Espresso’s Compose UI support is powerful, but sometimes it is not obvious how to set up certain types of tests. Simulating text entry into a TextField() is one example, and we see the solution for conducting that test in this week’s highlighted Stack Overflow question.

The Phases of Compose UI Rendering

Ever wonder how the Compose team remembers all of the various ways of solving Compose UI problems? Well… you will still wonder how they remember all that stuff, but at least you will get a better idea of the thought process, in this week’s highlighted Kotlinlang #compose Slack thread.

Composable Commentary

Posts, videos, and other new information related to Jetpack Compose!

Build an Android Chat app with Jetpack Compose

Márton Braun went beyond Google’s Jetchat sample app and wrote a full-fledged chat app, complete with server support through Stream. This post walks through every step of the process, from creating the initial project in Android Studio through the final results.

Dealing with Flaky Tests in Jetpack Compose

Igor Escodro identifies a scenario where your Compose UI testing might wind up with flaky tests — tests that may succeed or fail based on timing issues. Igor walks through how to deal with such tests, using Barista and a slightly different structure for the test cases.

Test Jetpack Compose UI Easily with the Role SemanticProperty

Yasin Kaçmaz walks us through using the role property on the selectable() modifier to be able to group widgets together, not only for UI and accessibility purposes, but also for simplified testing.

Jetpack Compose — Curtain Effect

Paulo Pereira demonstrates a “curtain” animation, where a column of composables can fold out from an initial row, in a variation on the “accordion” animation. This GitHub repository contains the final result, in the form of a sample app.

A Quick Guide to the animate…AsState Animation API in Jetpack Compose

Pranav Jayaraj gives us an overview of the various animate-as-state top-level functions in Compose UI, such as animateFloatAsState() and animateColorAsState(). Pranav demonstrates both simple value animations and ones with a custom specification, such as repeat rules or spring stiffness.

Exploring Jetpack Compose Canvas: the power of drawing

Julien Salvi takes a tour of the Canvas() composable, showing how to draw shapes, lines, and text on one, and comparing and contrasting it with the Canvas object from the classic View system. Julien also ties the Canvas() DSL into the animate-as-state functions from above, showing how they let you recompose your Canvas() and affect the elements that you draw.

Flexbox Layout Behavior in Jetpack Compose

Andy Dyer compares and contrasts “flexbox” from CSS and Web development with the container composables and modifiers that we work with in Compose UI. While there is no single Flexbox() composable, you can get a lot of flexbox-style results from the roster of standard composables.

How to Replace onCommit, onActive, and onDispose in Jetpack Compose

One challenge that we have with Compose and Compose UI is how much the API has shifted from the early developer previews to the now-current beta.

Tiger Oakes feels our pain.

In this post, Tiger reviews what onCommit, onActive, and onDispose were in earlier versions of Compose, then shows us how to replace them with SideEffect, LaunchedEffect, and DisposableEffect.

Scrollable TopAppBar with Jetpack Compose

Max Hübscher wanted a TopAppBar() that would slide away as the user scrolls the content down, then slide back into position when the user scrolls the content up. Alas, TopAppBar() does not appear to offer that, so Max wrote one using a Surface(), rememberLazyListState(), animateFloatAsState(), and related composables.

Resource Roundup

100% pure code!

Gist: opatry/GridLayer.kt

Olivier Patry posted a simple composable for rendering a grid of squares. That may not seem like much, but if you place it at the bottom of your screen composable, it overlays that grid on what the rest of the composable renders, for helping you visualize how well you are matching requested designs in terms of size and position of the widgets.

GitHub: Tlaster/Zoomable

GitHub user Tlaster published a small library that contains a Zoomable() composable that can wrap another composable and offer pinch-to-zoom on its contents.

GitHub: fvalela1/CalendarJetpackCompose

Francesco Valela offers a CalendarJetpackCompose() composable for rendering a calendar, with the option of highlighting dates, optional month navigation, etc.

GitHub: dbaroncelli/D-KMP-sample

Daniele Baroncelli published a sample app for his D-KMP architecture, demonstrating how to use Kotlin/Multiplatform with mostly shared code, except for using platform-specific declarative UIs (Compose UI for Android, Swift UI for iOS).

GitHub: Badranh/sniff

Hasan Badran offers another image-loading library for Compose UI. This one uses Ktor for the network I/O and supports Compose for Desktop.

GitHub: Elbehiry/Delish

Mohamed Elbehiry published Delish, a gorgeous Compose UI app for browsing and searching recipes published by Spoonacular through their Web service API.

GitHub: manueldidonna/godot-trains

Manuel Di Donna released a nicely designed app for displaying Trenitalia train schedules. The name, though, suggests that there may be long waits for Italian trains… 😁

Gist: EugeneTheDev/DotsLoaders.kt

GitHub user EugeneTheDev created a suite of composables demonstrating a variety of loading animations, all using dots. Rolling dots, flashing dots, stretching dots…

…And One More Thing

The next year or two is going to be a period of experimentation, as we strive to find the best patterns for applying Compose UI, both for new projects and for revamping existing projects.

Just do not get too married to your solutions.

In Android app development, “change is the only constant”. The recommended app development patterns change extremely rapidly, even when the platform itself has slowed its rate of change from the wild early days. Public Android app development is barely 12 years old, yet we have gone through a variety of revolutions:

  • Use Java. Actually, use Kotlin.

  • Use activities. No, use fragments, but only for tablets. Wait, instead, use fragments for everything, with one activity. Actually, dump the fragments and use composables!

  • Use AsyncTask. No, use loaders. Hang on, switch to RxJava. Oh, can we interest you in coroutines?

  • Just write code. No, use MVP. Sorry, that was a typo: use MVVM. Hey, MVI looks cute!

  • And so on.

It is almost assured that we will go through a few generations of approaches for how to apply Compose UI. Perhaps they will not be as fundamental as some of the other Android app development changes, but they may be more numerous:

  • Do we stick with top-level functions everywhere, or do something else (e.g., one object per screen)?

  • How do we handle theme-like concerns, particularly if we are implementing our own design system and therefore may not be using MaterialTheme or Compose Material?

  • How do we decide what gets locally remember-ed, what gets handled by a Jetpack ViewModel, and what gets handled by something else (e.g., non-Jetpack viewmodel)?

  • How do we handle navigation, now that we are navigating between functions? Is Navigation for Compose the “one true” navigation solution, or will we wind up switching to something else?

  • How do we organize our composables into modules, both for stacks that rely upon modules (e.g., Kotlin/Multiplatform) and for basic Android apps?

  • …and those are just a few that I thought of off the top of my (balding) head.

Tastes will change. The solutions that we use today will look dated tomorrow.

So, in many ways, the biggest thing that you can do is to try to be less opinionated about your own opinions. “Future you” may disagree with your opinions from today, and those opinions will drive a lot of your implementation decisions.

We have no way of predicting the exact nature of the changes that will happen. We can predict that the changes will happen. The more you can do to be able to adapt to those changes — such as writing good tests — the better off you will be when those changes come about.

And now, if you will excuse me, I need to go see what patterns changed while I was writing this newsletter issue… 😁