hotwired / turbo-android

Android framework for making Turbo native apps
MIT License
423 stars 51 forks source link

Multiple TurboWebView issue and sheet modal problem #189

Closed shkim closed 2 years ago

shkim commented 2 years ago

My app's main activity has 4 tabs, like:

<ViewFlipper>
  <androidx.fragment.app.FragmentContainerView />
  <androidx.fragment.app.FragmentContainerView />
  <androidx.fragment.app.FragmentContainerView />
  <androidx.fragment.app.FragmentContainerView />
</ViewFlipper>

There are four sets of [NavHostFragment, NavDestination, WebFragment]s (Same class, different instances) and only one Turbo WebView is visible at a time.

In Tab 3, I clicked a link to visit a new route whose path-config context is "modal". Then a new page is presented in a popup fragment. ( at this time, path-config uri = "turbo://fragment/web/modal") And submitted a form on that popup fragment, then popup dismissed and underlying page is just refreshed. Wierd thing is.. the page after the form (3rd) is pushed on Tab 1's history. I cannot see the third page on Tab 3, and if I switch to Tab 1 then I can see the page. After clicking Back on Tab 1, the original Tab 1 page is displayed.

And another issue is.. dismissing "turbo://fragment/web/modal" fragment has no problem but, After "turbo://fragment/web/modal/sheet" fragment is dismissed, underlying webpage is not restored. It still shows the screenshot (non-interactive state). (Very similar to #184 , but it was normal webview, not native view)

jayohms commented 2 years ago

If you have more than one FragmentContainerView (and TurboSessionNavHostFragment) in your Activity, you need to make sure you:

  1. Register each nav host fragment in your Activity though the TurboActivityDelegate like:
    
    delegate = TurboActivityDelegate(this, R.id.first_nav_host)

val firstNavHost = delegate.registerNavHostFragment(R.id.first_nav_host) val secondNavHost = delegate.registerNavHostFragment(R.id.second_nav_host) val thirdNavHost = delegate.registerNavHostFragment(R.id.third_nav_host) val fourthNavHost = delegate.registerNavHostFragment(R.id.fourth_nav_host)

2. Each time the active nav host fragment changes, you need to update the `delegate` to specify the currently active nav host fragment:
```kotiln
delegate.currentNavHostFragmentId = secondNavHost.id

Make sense?

shkim commented 2 years ago

It did not work. Even if I click a simple href link on page which is modal, the next page will be pushed to the first tab's history and then the dialog dismissed, I can see the existing tab2's page.

jayohms commented 2 years ago

Please provide sample code that demonstrates the issue you're describing. We use multiple tabs, each with its own session, in some of our apps so there shouldn't be an issue with the library itself to prevent this from working properly.

shkim commented 2 years ago

Thank you for your attention. I pushed the sample code: https://github.com/shkim/turbo-android

https://user-images.githubusercontent.com/1094548/135659910-6870bf6b-1ba9-4364-8e12-4066ad7289fd.mov

jayohms commented 2 years ago

This the core of the issue:

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/tab1"
    android:name="dev.hotwire.turbo.demo.main.MainSessionNavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="tab1"
    />
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/tab2"
    android:name="dev.hotwire.turbo.demo.main.MainSessionNavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="tab2"
    />

You should not share the same MainSessionNavHostFragment class between tabs. You'll want a separate NavHostFragment for each tab like:

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/tab1"
    android:name="dev.hotwire.turbo.demo.main.FirstTabNavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/tab2"
    android:name="dev.hotwire.turbo.demo.main.SecondTabNavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

This will allow you to easily specify a separate startLocation for each instance and keep the sessions isolated.

If this doesn't resolve everything, let me know!

shkim commented 2 years ago

Thanks for your hint. I could not achieve the goal by just using different classes, but specifying different "sessionName" value was the key solution, even with one class.

jayohms commented 2 years ago

Good catch, yes the session name must be unique across sessions. I just realized that the TurboSessionNavHostFragment class needs API documentation. I've created an issue to track that here: https://github.com/hotwired/turbo-android/issues/194

MichalSznajder commented 1 year ago

Please provide sample code that demonstrates the issue you're describing. We use multiple tabs, each with its own session, in some of our apps so there shouldn't be an issue with the library itself to prevent this from working properly.

Are you using ViewFlipper to group NavHostFragments? Do you make any kind of delayed loading to improve startup times?