How to Get up and Running with Turbo Android Part 2 - Feel More Native

So far, we’ve covered getting up and running with Turbo Android. Now we can move on to the fun part of Turbo Android, which is about making it feel more native. Compared to Turbo-ios, Turbo Android has a lot built into the framework and can easily route different endpoints.

Getting Setup with Modals

You may have noticed that the Android app doesn’t feel very native. Instead, it feels like a webpage inside an app’s skin. Luckily, we can add some quick changes utilising Turbo Fragments found in the Turbo-Android library. By inheriting from these and updating out Path Configuration, we have routes display different Turbo Fragments.

For now, we will update our codebase so that every route that ends with new and edit will result in a modal popup like the one shown in this gif.

alt text

Update PathConfiguration

We created a path configuration file under assets/json in the previous tutorial. Let’s edit that and add a new rule.

{
  "patterns": [
    "/new$",
    "/edit$"
  ],
  "properties": {
    "context": "modal",
    "uri": "turbo://fragment/web/modal/sheet",
    "pull_to_refresh_enabled": false
  }
}

This is telling our Turbo Android app to use the class that’s annotated with @TurboNavGraphDestination(uri = "turbo://fragment/web/modal/sheet") for any route that ends in new or edit.

Create the Fragment and add it

Now we need to create the fragment. Add a new Kotlin class and call it WebBottomSheetFragment and make sure to inherit from TurboWebBottomSheetDialogFragment()


import dev.hotwire.turbo.fragments.TurboWebBottomSheetDialogFragment
import dev.hotwire.turbo.nav.TurboNavGraphDestination

@TurboNavGraphDestination(uri = "turbo://fragment/web/modal/sheet")
class WebBottomSheetFragment : TurboWebBottomSheetDialogFragment() {}

We’re not done yet. We’ve to add it to the list of registered fragments in our MainSessionNavHost

class MainSessionNavHost : TurboSessionNavHostFragment() {
  ...

    override val registeredFragments: List<KClass<out Fragment>>
    get() = listOf(
        WebFragment::class,
        WebBottomSheetFragment::class,
        )
    ...
}

When we run the app and navigate to any route that ends in new or edit, we display a modal.

Rendering a Native Screen

The exact process that we used to add a modal we can also use it to navigate to a native screen. Let’s navigate to a simple Hello World screen written with Jetpack Compose. Jetpack Compose is Google’s modern UI tool and is similar to SwiftUI.

There is a little setup involved if we use the modern approach to building Android tools. So let’s dive in step by step.

Update build.gradle

We have to add the compose libraries to our app and ensure that it will compile Jetpack Compose.

android {
  ...
    buildFeatures {
      compose true
    }
  ...
}

dependencies {

  implementation 'androidx.compose.ui:ui:1.4.2'
    implementation 'androidx.compose.material:material:1.2.0'
    def composeBom = platform("androidx.compose:compose-bom:2023.03.00")
    implementation(composeBom)
    ....
}

Make sure to sync your changes.

Next, we update our Path Configuration to render specific routes with a native screen.

{
  "patterns": [
    "/hello_world"
  ],
  "properties": {
    "context": "default",
    "uri": "turbo://fragment/hello_world"
  }
},

Now we create the HelloWorldFragment, which inherits from TurboFragment

  @TurboNavGraphDestination(uri = "turbo://fragment/hello_world")
  class HelloWorldFragment : TurboFragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
      return ComposeView(requireContext()).apply {
        setContent {
          Hello()
        }
      }
    }

    @Composable
      fun Hello() {
        Column(
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
            ) {
          Text("Hello World")
        }
      }
  }

Finally, we add this fragment to the list of registered fragments:

class MainSessionNavHost : TurboSessionNavHostFragment() {
  ...

    override val registeredFragments: List<KClass<out Fragment>>
    get() = listOf(
        WebFragment::class,
        WebBottomSheetFragment::class,
        HelloWorldFragment::class 
        )
    ...
}

*NOTE: You may have to change your Kotlin version to 1.7.0 to compile. This can be changed in build.grade(project)

Once we’ve run the app, we should be able to navigate to the /hello\_world route and voila:

alt text

It’s pretty basic, but it’s enough to build on. In the next blog post, we will talk about the JavaScript bridge, and then we will talk about little improvements we can make to our Turbo app to make it even better.

Learn to Build Android, iOS and Rails Apps using Hotwire

© 2024 William Kennedy, Inc. All rights reserved.