Last active
October 17, 2023 10:22
-
-
Save Andrew0000/401496c66b026b1dc6673449b8fe9603 to your computer and use it in GitHub Desktop.
Destination
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import android.app.Activity | |
| import android.content.Context | |
| import android.os.Bundle | |
| import android.os.Parcelable | |
| import androidx.annotation.IdRes | |
| import androidx.fragment.app.Fragment | |
| import androidx.lifecycle.LifecycleOwner | |
| import androidx.lifecycle.lifecycleScope | |
| import androidx.navigation.NavController | |
| import androidx.navigation.NavOptions | |
| import kotlinx.coroutines.delay | |
| import kotlinx.coroutines.launch | |
| import timber.log.Timber | |
| import java.io.Serializable | |
| sealed class Destination { | |
| data class Navigate( | |
| @IdRes | |
| val id: Int, | |
| val args: Map<String, Any>? = null, | |
| val clearStack: Boolean = false, | |
| ) : Destination() { | |
| fun plusArgs(argsNew: Map<String, Any>) = copy( | |
| id = id, | |
| args = (args ?: mapOf()) + argsNew | |
| ) | |
| } | |
| object Back : Destination() | |
| object BackCloseKeyboard : Destination() | |
| data class BackTo( | |
| @IdRes | |
| val id: Int, | |
| val closeKeyboard: Boolean = true, | |
| ) : Destination() | |
| data class Combined( | |
| val list: List<Destination>, | |
| ) : Destination() { | |
| constructor(vararg destinations: Destination) : this(destinations.toList()) | |
| } | |
| data class OpenBrowser( | |
| val url: String, | |
| ) : Destination() | |
| data class NavigateCustom( | |
| val id: Int, | |
| ) : Destination() | |
| } | |
| fun Destination.Navigate.getBundleFromDestination(): Bundle? { | |
| if (args.isNullOrEmpty()) { | |
| return null | |
| } | |
| val bundle = Bundle() | |
| args.entries.forEach { (key, value) -> | |
| when (value) { | |
| is String -> bundle.putString(key, value) | |
| is Boolean -> bundle.putBoolean(key, value) | |
| is Int -> bundle.putInt(key, value) | |
| is Long -> bundle.putLong(key, value) | |
| is Float -> bundle.putFloat(key, value) | |
| is Double -> bundle.putDouble(key, value) | |
| is Serializable -> bundle.putSerializable(key, value) | |
| is Parcelable -> bundle.putParcelable(key, value) | |
| else -> { | |
| Timber.w("Unhandled type: $value") | |
| if (BuildConfig.DEBUG) { | |
| throw IllegalArgumentException("Arg isn't handled: $value. Need to write handler code.") | |
| } | |
| } | |
| } | |
| } | |
| return bundle | |
| } | |
| fun NavController.navigate( | |
| dest: Destination, | |
| lifecycleOwner: LifecycleOwner? = null, | |
| context: Context? = null, | |
| customNavigation: ((Int) -> Unit)? = null, | |
| ) { | |
| when (dest) { | |
| is Destination.Navigate -> { | |
| val options = when { | |
| dest.clearStack -> NavOptions.Builder() | |
| .setPopUpTo(graph.startDestinationId, inclusive = true) | |
| .appendCommonAnimationOptions() | |
| .build() | |
| else -> null | |
| } | |
| navigate( | |
| dest.id, | |
| dest.getBundleFromDestination(), | |
| options, | |
| ) | |
| } | |
| is Destination.Combined -> { | |
| dest.list.forEach { | |
| navigate(it) | |
| } | |
| } | |
| Destination.Back -> { | |
| popBackStack() | |
| } | |
| is Destination.BackCloseKeyboard -> { | |
| if (lifecycleOwner != null) { | |
| lifecycleOwner.lifecycleScope.launch { | |
| lifecycleOwner.closeKeyboard() | |
| popBackStack() | |
| } | |
| } else { | |
| DebugAssert.fail("Can't close keyboard without lifecycle") | |
| popBackStack() | |
| } | |
| } | |
| is Destination.BackTo -> { | |
| if (dest.closeKeyboard && lifecycleOwner != null) { | |
| lifecycleOwner.lifecycleScope.launch { | |
| lifecycleOwner.closeKeyboard() | |
| popBackStack(dest.id, false) | |
| } | |
| } else { | |
| popBackStack(dest.id, false) | |
| } | |
| } | |
| is Destination.OpenBrowser -> { | |
| context?.openBrowser(dest.url) | |
| } | |
| is Destination.NavigateCustom -> { | |
| customNavigation?.invoke(dest.id) | |
| } | |
| } | |
| } | |
| private suspend fun LifecycleOwner.closeKeyboard() { | |
| if (this is Fragment) { | |
| closeKeyboard() | |
| delay(200) | |
| } | |
| if (this is Activity) { | |
| closeKeyboard() | |
| delay(200) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment