Errata for Kotlin Multiplatform by Tutorials 1st Edition

Creating this topic to catch any typos and bugs in the 1st Edition of Kotlin Multiplatform by Tutorials.

Chapter 2. Getting started.
There is a mistake in function:

fun formatDateTime(dateTime: LocalDateTime): String {
    var hour = dateTime.hour
    var amPm = " am"
    // 3
    // For 12
    if (hour > 12) {
        amPm = " pm"
        hour -= 12

When the 24-hour input value of hours is 0, this fun returns 0 am, but it is expected to be 12 am.
When the 24-hour input value of hours is 12, this fun returns 12 am, but it is expected to be 12 pm.

I can suggest this code:

var hour = dateTime.hour % 12
if (hour == 0) hour = 12
val amPm = if (dateTime.hour < 12) " am" else " pm"

Great catch. Will update

In section 3 (Developing UI using Compose) the composable AnimatedSwipeDismiss is used. I can’t seem to find that anywhere. It does not get suggested in Android Studio and Google also doesn’t yield any results. Link to the exact location: Kotlin Multiplatform by Tutorials, Chapter 3: Developing UI: Android Jetpack Compose |

It seems like AnimatedSwipeDismiss is from this gist but this should be linked to from the book or the source code should be included I think: AnimatedSwipeDismiss.kt · GitHub

The code from the gist also doesn’t seem to work completely since import androidx.compose.runtime.onCommit does not exist for some reason.

This class is found in the starter project for this chapter.

Oh - I totally missed there being a starter project! Must have skipped the first page of the chapter. Thanks though.

Hey @kevindmoore , the book is great and provides great knowledge, but I found a few issues in the Compose chapter. Please don’t be mad at me ;], i am just a pointing out customer. :upside_down_face:

First of all composable functions should follow PascalCased naming, which is recommended in the official guidelines (androidx/ at androidx-main · androidx/androidx · GitHub). In chapter 3 there is a composable function with wrong naming:

fun emptyComposable() {

The next thing that got my attention was LaunchedEffect. You passed 0 as a key, but this variable is initialized in the LaunchedEffect constructor. In the ray’s compose book and official guidelines it was mentioned to pass never-changing constant like Unit or true. Most often I see Unit in examples.

To create an effect that matches the lifecycle of the call site, a never-changing constant like Unit or true is passed as a parameter. In the code above, LaunchedEffect(true) is used. ~ Side-effects in Compose  |  Jetpack Compose  |  Android Developers

LaunchedEffect(0) {
    while (true) {
        time = timezoneHelper.currentTime()
        delay(timeMillis) // Every minute

The last thing I would change is AppTheme.kt class. It is a composable function, which role is to pass down to the other composable information about colors/typography … etc. Here is the theme composable used in the project.

fun AppTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
    val colors = if (darkTheme) {
                primary = primaryDarkColor,
                primaryVariant = primaryLightColor,
                secondary = secondaryDarkColor,
                secondaryVariant = secondaryLightColor,
                onPrimary = Color.White,
    } else {
                primary = primaryColor,
                primaryVariant = primaryLightColor,
                secondary = secondaryColor,
                secondaryVariant = secondaryLightColor,
                onPrimary = Color.Black,
        colors = colors,
        typography = typography,
        content = content

Normally when you create an empty project in android for compose application you will have theme class generated for you. In my opinion it look’s more clear and easier to read because all of your AppTheme variables could be read from the object class which has read only composables.

 * Contains functions to access the current theme values provided at the call site's position in
 * the hierarchy.
object MaterialTheme {
     * Retrieves the current [ColorScheme] at the call site's position in the hierarchy.
    val colorScheme: ColorScheme
        get() = LocalColorScheme.current

     * Retrieves the current [Typography] at the call site's position in the hierarchy.
    val typography: Typography
        get() = LocalTypography.current

This is very useful, because in some cases you have to pass another Theme in your composables. This will only search the closest composable in your tree hierarchy, so you can have many themes in your apps! So to read those values you can do this:

                text = text,
                style = MaterialTheme.typography.labelLarge,

One more thing :sweat_smile:
View is usually avoided as a naming scheme in Compose. In chapter 3 there is a MainView composable.
I hope you can fix all the things i have mentioned in the next release. :rocket: 🧑‍💻

Thanks so much for the feedback. I will definitely implement these in the next version.

1 Like

Newer M1 Macs need to run $ brew install cocoapods instead of sudo gem install cocoapods in order to build the project due to a bug with encoding.

When I’m trying to run the startup project I got this error
10:54 Gradle sync failed: ‘pod install’ command failed with code 1.
Error message:
Please, check that podfile contains following lines in header:
source ‘
Please, check that each target depended on shared contains following dependencies:
(2 s 248 ms)

Hello trainingtamkin,

Can you please give us a bit more information about your development environment?

For instance:

  • The Operating System of the computer where you’re running the project
  • From which chapter are you running the project
  • Which version of Android Studio are you using?

Thank you