Skip to content

Commit b2f2aa4

Browse files
authored
Merge pull request #311 from hotwired/back-button-visibility
Fix `Toolbar` back button visibility without having a separate start destination `Fragment` instance
2 parents 262fef1 + 403e1e6 commit b2f2aa4

File tree

9 files changed

+53
-23
lines changed

9 files changed

+53
-23
lines changed

demo/src/main/kotlin/dev/hotwire/turbo/demo/features/imageviewer/ImageViewerFragment.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import dev.hotwire.turbo.demo.R
1010
import dev.hotwire.turbo.fragments.TurboFragment
1111
import dev.hotwire.turbo.nav.TurboNavGraphDestination
1212
import com.bumptech.glide.Glide
13-
import dev.hotwire.turbo.demo.util.displayBackButtonAsCloseIcon
13+
import dev.hotwire.turbo.util.displayBackButtonAsCloseIcon
1414

1515
@TurboNavGraphDestination(uri = "turbo://fragment/image_viewer")
1616
class ImageViewerFragment : TurboFragment(), NavDestination {
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,6 @@
11
package dev.hotwire.turbo.demo.features.web
22

3-
import android.os.Bundle
4-
import android.view.View
5-
import dev.hotwire.turbo.demo.util.displayBackButtonAsCloseIcon
63
import dev.hotwire.turbo.nav.TurboNavGraphDestination
74

85
@TurboNavGraphDestination(uri = "turbo://fragment/web/modal")
9-
class WebModalFragment : WebFragment() {
10-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
11-
super.onViewCreated(view, savedInstanceState)
12-
initToolbar()
13-
}
14-
15-
private fun initToolbar() {
16-
toolbarForNavigation()?.displayBackButtonAsCloseIcon()
17-
}
18-
}
6+
class WebModalFragment : WebFragment()

demo/src/main/kotlin/dev/hotwire/turbo/demo/util/Extensions.kt

-4
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ import dev.hotwire.turbo.demo.strada.bridgeComponentFactories
1717
val TurboPathConfigurationProperties.description: String?
1818
get() = get("description")
1919

20-
fun Toolbar.displayBackButtonAsCloseIcon() {
21-
navigationIcon = ContextCompat.getDrawable(context, R.drawable.ic_close)
22-
}
23-
2420
@Suppress("DEPRECATION")
2521
fun WebView.initDayNightTheme() {
2622
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {

turbo/src/main/kotlin/dev/hotwire/turbo/delegates/TurboFragmentDelegate.kt

+10-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import dev.hotwire.turbo.nav.TurboNavDestination
88
import dev.hotwire.turbo.nav.TurboNavigator
99
import dev.hotwire.turbo.session.TurboSessionModalResult
1010
import dev.hotwire.turbo.session.TurboSessionViewModel
11+
import dev.hotwire.turbo.util.displayBackButton
12+
import dev.hotwire.turbo.util.displayBackButtonAsCloseIcon
1113
import dev.hotwire.turbo.util.logEvent
1214

1315
/**
@@ -95,7 +97,14 @@ class TurboFragmentDelegate(private val navDestination: TurboNavDestination) {
9597

9698
private fun initToolbar() {
9799
navDestination.toolbarForNavigation()?.let {
98-
NavigationUI.setupWithNavController(it, fragment.findNavController())
100+
if (!navigator.isAtStartDestination()) {
101+
if (navDestination.isModal) {
102+
it.displayBackButtonAsCloseIcon()
103+
} else {
104+
it.displayBackButton()
105+
}
106+
}
107+
99108
it.setNavigationOnClickListener {
100109
navDestination.navigateUp()
101110
}

turbo/src/main/kotlin/dev/hotwire/turbo/nav/TurboNavDestination.kt

+7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import androidx.navigation.navOptions
1515
import androidx.navigation.ui.R
1616
import dev.hotwire.turbo.config.TurboPathConfiguration
1717
import dev.hotwire.turbo.config.TurboPathConfigurationProperties
18+
import dev.hotwire.turbo.config.context
1819
import dev.hotwire.turbo.delegates.TurboFragmentDelegate
1920
import dev.hotwire.turbo.delegates.TurboNestedFragmentDelegate
2021
import dev.hotwire.turbo.fragments.TurboFragment
@@ -81,6 +82,12 @@ interface TurboNavDestination {
8182
val isActive: Boolean
8283
get() = fragment.isAdded && !fragment.isDetached
8384

85+
/**
86+
* Specifies whether the destination was presented in a modal context.
87+
*/
88+
val isModal: Boolean
89+
get() = pathProperties.context == TurboNavPresentationContext.MODAL
90+
8491
/**
8592
* Gets the delegate instance that handles the Fragment's lifecycle events.
8693
*/

turbo/src/main/kotlin/dev/hotwire/turbo/nav/TurboNavigator.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ internal class TurboNavigator(private val navDestination: TurboNavDestination) {
2020
onReady()
2121
}
2222

23+
fun isAtStartDestination(): Boolean {
24+
return currentController().previousBackStackEntry == null
25+
}
26+
2327
fun navigateUp() {
2428
onNavigationVisit {
2529
if (fragment is DialogFragment) {
@@ -267,10 +271,6 @@ internal class TurboNavigator(private val navDestination: TurboNavDestination) {
267271
return navDestination.navHostForNavigation(location).navController
268272
}
269273

270-
private fun isAtStartDestination(): Boolean {
271-
return currentController().previousBackStackEntry == null
272-
}
273-
274274
private fun shouldNavigate(location: String): Boolean {
275275
val shouldNavigate = navDestination.shouldNavigateTo(location)
276276

turbo/src/main/kotlin/dev/hotwire/turbo/util/TurboExtensions.kt

+12
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,26 @@ import android.animation.ValueAnimator
55
import android.content.Context
66
import android.os.Handler
77
import android.webkit.WebResourceRequest
8+
import androidx.appcompat.widget.Toolbar
9+
import androidx.core.content.ContextCompat
810
import androidx.navigation.NavBackStackEntry
911
import com.google.gson.Gson
1012
import com.google.gson.GsonBuilder
1113
import com.google.gson.reflect.TypeToken
14+
import dev.hotwire.turbo.R
1215
import dev.hotwire.turbo.visit.TurboVisitAction
1316
import dev.hotwire.turbo.visit.TurboVisitActionAdapter
1417
import java.io.File
1518

19+
fun Toolbar.displayBackButton() {
20+
navigationIcon = ContextCompat.getDrawable(context, R.drawable.ic_back)
21+
}
22+
23+
fun Toolbar.displayBackButtonAsCloseIcon() {
24+
navigationIcon = ContextCompat.getDrawable(context, R.drawable.ic_close)
25+
}
26+
27+
1628
internal fun Context.runOnUiThread(func: () -> Unit) {
1729
when (mainLooper.isCurrentThread) {
1830
true -> func()
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
9+
</vector>
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12 19,6.41z"/>
9+
</vector>

0 commit comments

Comments
 (0)