hotwired/turbo-android

Provide an example of using multiple activities

kyrylo opened this issue · 1 comments

kyrylo commented

I can see two slighty contradicting statements in the documentation. The first link heavily discourages me from using multiple activities, but the second one says it's possible and provides guidance.

## Create an Activity
It's strongly recommended to use a single-Activity architecture in your app. Generally, you'll have one `TurboActivity` and many `TurboFragments`.

## Using Multiple Activities
You may encounter situations where a truly single-`Activity` app may not be feasible. For example, you may need an `Activity` for logged-out state and a separate `Activity` for logged-in state.
In such cases, you need to create an additional `Activity` that also implements the `TurboActivity` interface. You will need to be sure to register each `Activity` by calling [`TurboSessionNavHostFragment.registeredActivities()`](../turbo/src/main/kotlin/dev/hotwire/turbo/session/TurboSessionNavHostFragment.kt) so that you can navigate between them.


However, for someone who is new to Android development, the documentation lacks examples.

I am trying to display bottom navigation for my app, everywhere but on certain pages. For example, I want to hide it on the login screen of my app, which is a page served by Rails.

I followed the multiple activities doc, but after annotating them, I got an error:

Caused by: java.lang.IllegalArgumentException:
A start Fragment destination was not found for uri: turbo://activity/login
@TurboNavGraphDestination(uri = "turbo://activity/main")
class MainActivity : AppCompatActivity(), TurboActivity {
@TurboNavGraphDestination(uri = "turbo://activity/login")
class LoginActivity : AppCompatActivity(), TurboActivity {
{
  "patterns": [
    "^/sign_in$",
    "^/sign_up$"
  ],
  "properties": {
    "uri": "turbo://activity/login",
    "pull_to_refresh_enabled": false
  }
},

If my uri is an activity, am I expected to have res/navigation file? Any additional examples are appreciated.

P.S. I have figured out a way to hide the bottom navigation dynamically, inside a fragment, but I am wondering whether the activity approach is cleaner (since I wouldn't need to manage the bottom navigation state).

@kyrylo my guess is that the Activity is not registered in your TurboSessionNavHostFragment.registeredActivities.

I would recommend against using multiple Activity instances at this point. It represents an architecture that Android has been moving away from for a long time. In fact, turbo-android may drop explicit support eventually. That being said, an app can always create and finish() its own Activity instances and within each Activity, you can have a Turbo nav graph.

I'd recommend leveraging your path configuration file and using a custom property to determine when to show/hide your bottom tabs. It'd look like something like this:

{
  "rules": [
    {
      "patterns": [
        ".*"
      ],
      "properties": {
        "context": "default",
        "presentation": "default",
        "uri": "turbo://fragment/web",
        "pull_to_refresh_enabled": true,
        "displays_bottom_tabs": true
      }
    },
    {
      "patterns": [
        "^/sign_in$",
        "^/sign_up$"
      ],
      "properties": {
        "uri": "turbo://fragment/login",
        "pull_to_refresh_enabled": false,
        "displays_bottom_tabs": false
      }
    }
  ]
}

You can create your own extension function to easily read this from any fragment destination:

// Extension function
val TurboPathConfigurationProperties.displayBottomTabs: Boolean
    get() = get("displays_bottom_tabs")?.toBoolean() ?: false

// Use
if (pathProperties.displayBottomTabs) {
  // Display bottom tabs
} else {
  // Hide bottom tabs
}