Last active
April 29, 2024 21:56
-
-
Save ElianFabian/19205699597b279e63266a5b05632236 to your computer and use it in GitHub Desktop.
An interface that allows to work with Fragment arguments and events in a type-safe and process-death-safe way using extension functions.
This file contains 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
<?xml version="1.0" encoding="utf-8"?> | |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:gravity="center"> | |
<FrameLayout | |
android:id="@+id/fragmentContainer" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" /> | |
</LinearLayout> |
This file contains 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
<?xml version="1.0" encoding="utf-8"?> | |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:gravity="center|top" | |
android:orientation="vertical" | |
android:paddingTop="50dp"> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginHorizontal="20dp" | |
android:orientation="horizontal"> | |
<com.google.android.material.textview.MaterialTextView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_marginEnd="5dp" | |
android:text="Title:" | |
android:textStyle="bold" /> | |
<com.google.android.material.textview.MaterialTextView | |
android:id="@+id/tvTitle" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
tools:text="A regular title" /> | |
</LinearLayout> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginHorizontal="20dp" | |
android:orientation="horizontal"> | |
<com.google.android.material.textview.MaterialTextView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_marginEnd="5dp" | |
android:text="Message:" | |
android:textStyle="bold" /> | |
<com.google.android.material.textview.MaterialTextView | |
android:id="@+id/tvMessage" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
tools:text="A regular message" /> | |
</LinearLayout> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="0dp" | |
android:layout_marginHorizontal="50dp" | |
android:layout_weight="1" | |
android:gravity="center" | |
android:orientation="vertical"> | |
<com.google.android.material.button.MaterialButton | |
android:id="@+id/btnAccept" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:backgroundTint="#00C853" | |
android:text="Accept" /> | |
<com.google.android.material.button.MaterialButton | |
android:id="@+id/btnReject" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:backgroundTint="#FF1744" | |
android:text="Reject" /> | |
</LinearLayout> | |
</LinearLayout> |
This file contains 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.os.Bundle | |
import android.widget.Toast | |
import androidx.appcompat.app.AppCompatActivity | |
class MainActivity : AppCompatActivity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContentView(R.layout.activity_main) | |
val sampleFragment = SampleFragment.newInstance( | |
args = SampleFragment.Args( | |
title = "A regular title", | |
message = "A regular message", | |
) | |
) | |
sampleFragment.setFragmentEventListener(this@MainActivity) { event -> | |
when (event) { | |
is SampleFragment.Event.OnAccept -> { | |
Toast.makeText(applicationContext, "Accepted! Data = ${event.data}", Toast.LENGTH_SHORT).show() | |
} | |
is SampleFragment.Event.OnReject -> { | |
Toast.makeText(applicationContext, "Rejected!", Toast.LENGTH_SHORT).show() | |
} | |
} | |
} | |
supportFragmentManager.beginTransaction() | |
.add(R.id.fragmentContainer, sampleFragment, sampleFragment.typedInstanceId) | |
.commit() | |
} | |
} |
This file contains 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.os.Bundle | |
import android.os.Parcelable | |
import android.view.LayoutInflater | |
import android.view.View | |
import android.view.ViewGroup | |
import androidx.fragment.app.Fragment | |
import com.elian.typedfragment.databinding.LayoutSampleBinding | |
import kotlinx.parcelize.Parcelize | |
class SampleFragment : Fragment(), | |
TypedArgEvent<SampleFragment.Args, SampleFragment.Event> { | |
private lateinit var binding: LayoutSampleBinding | |
override var typedInstanceId: String? = null | |
private set | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
typedInstanceId = typedInstanceId ?: savedInstanceState?.getString(EXTRA_FRAGMENT_ID) ?: this::class.qualifiedName | |
} | |
override fun onSaveInstanceState(outState: Bundle) { | |
super.onSaveInstanceState(outState) | |
outState.putString(EXTRA_FRAGMENT_ID, typedInstanceId) | |
} | |
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { | |
binding = LayoutSampleBinding.inflate(layoutInflater) | |
return binding.root | |
} | |
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
super.onViewCreated(view, savedInstanceState) | |
val args = getFragmentArgs() ?: return | |
binding.apply { | |
tvTitle.text = args.title | |
tvMessage.text = args.message | |
btnAccept.setOnClickListener { | |
sendFragmentEvent( | |
Event.OnAccept( | |
data = "This is your title: ${args.title} and this is your message = ${args.message}" | |
) | |
) | |
} | |
btnReject.setOnClickListener { | |
sendFragmentEvent(Event.OnReject) | |
} | |
} | |
} | |
@Parcelize | |
data class Args( | |
val title: String, | |
val message: String, | |
) : Parcelable | |
sealed interface Event : Parcelable { | |
@Parcelize | |
class OnAccept(val data: String) : Event | |
@Parcelize | |
object OnReject : Event | |
} | |
companion object { | |
private const val EXTRA_FRAGMENT_ID = "EXTRA_FRAGMENT_ID" | |
fun newInstance(id: String? = null, args: Args? = null) = SampleFragment().apply { | |
if (args != null) { | |
arguments = createArgsBundle(args) | |
} | |
this.typedInstanceId = id ?: SampleFragment::class.qualifiedName | |
} | |
} | |
} |
This file contains 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
/** | |
* Interface mostly meant for Fragment classes to provide a type-safe and process-death-safe way of receiving arguments and sending events. | |
* | |
* The interface requires indicating the types of arguments [TArgs] and events [TEvent] needed, as well as an ID to identify the fragment. | |
* | |
* This interface is intended to be extended with extension functions to fit specific needs. | |
* Refer to the TypedArgEventExt file for some base functions that extends this interface. | |
* | |
* | |
* Example usage: | |
* | |
* ``` | |
* class MyFragment : TypedArgEvent<MyFragment.Args, MyFragment.Event>() { | |
* | |
* [...] | |
* | |
* override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
* | |
* val args = getFragmentArgs() ?: return | |
* | |
* tvTitle.text = args.title | |
* tvMessage.text = args.message | |
* | |
* btnAccept.setOnClickListener { | |
* sendFragmentEvent(Event.OnAccept(data = "important data")) | |
* } | |
* btnReject.setOnClickListener { | |
* sendFragmentEvent(Event.OnReject) | |
* } | |
* } | |
* | |
* | |
* @Parcelize | |
* data class Args( | |
* val title: String, | |
* val message: Int, | |
* ) : Parcelable | |
* | |
* sealed interface Event : Parcelable { | |
* @Parcelize | |
* class OnAccept(val data: String) : Event | |
* | |
* @Parcelize | |
* object OnReject : Event | |
* } | |
* | |
* | |
* companion object { | |
* fun newInstance(id: String? = null, args: Args? = null) = MyFragment().apply { | |
* if (args != null) { | |
* arguments = createArgsBundle(args) | |
* } | |
* | |
* typedInstanceId = id ?: MyFragment::class.qualifiedName | |
* } | |
* } | |
* } | |
* | |
* | |
* // In another fragment or activity create a new instance | |
* val myFragment = MyFragment.newInstance( | |
* args = MyFragment.Args( | |
* firstArg = "some data", | |
* secondArg = "more data", | |
* ) | |
* ) | |
* | |
* // Set the listener | |
* myFragment.setFragmentEventListener(this@SomeFragment) { event -> | |
* when (event) { | |
* is MyFragment.Event.OnAccept -> { | |
* // Do something | |
* } | |
* is MyFragment.Event.OnReject -> { | |
* // Do something | |
* } | |
* } | |
* } | |
* ``` | |
*/ | |
interface TypedArgEvent<TArgs, TEvent> { | |
/** | |
* An ID that identifies a single instance. | |
* | |
* For fragments if there is only one instance, it's fine to use "this::class.qualifiedName" as the ID value. For multiple instances, | |
* provide different keys for each instance. | |
* | |
* To persist this ID after process death, you need to manually save and restore it. Example: | |
* | |
* ``` | |
* override var typedInstanceId: String? = null | |
* private set | |
* | |
* override fun onCreate(savedInstanceState: Bundle?) { | |
* super.onCreate(savedInstanceState) | |
* | |
* typedInstanceId = typedInstanceId ?: savedInstanceState?.getString("id") ?: this::class.qualifiedName | |
* } | |
* | |
* @CallSuper | |
* override fun onSaveInstanceState(outState: Bundle) { | |
* super.onSaveInstanceState(outState) | |
* | |
* outState.putString("id", typedInstanceId) | |
* } | |
* ``` | |
*/ | |
val typedInstanceId: String? | |
companion object { | |
const val EXTRA_ARGS = "TypedArgEvent.EXTRA_ARGS" | |
const val EXTRA_EVENT = "TypedArgEvent.EXTRA_EVENT" | |
} | |
} |
This file contains 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
@file:Suppress("NOTHING_TO_INLINE") | |
import android.os.Bundle | |
import android.os.Parcelable | |
import androidx.core.os.bundleOf | |
import androidx.fragment.app.DialogFragment | |
import androidx.fragment.app.Fragment | |
import androidx.fragment.app.FragmentActivity | |
import androidx.fragment.app.FragmentManager | |
import androidx.lifecycle.LifecycleOwner | |
/** | |
* Retrieves the fragment arguments casted to the specified type [TArgs]. | |
* | |
* @return The fragment arguments, or null if not found. | |
*/ | |
@Suppress("Deprecation") | |
inline fun <T, TArgs : Parcelable> T.getFragmentArgs(): TArgs? | |
where T : Fragment, T : TypedArgEvent<TArgs, *> { | |
return arguments?.getParcelable(TypedArgEvent.EXTRA_ARGS) | |
} | |
/** | |
* Null implementation of the [getFragmentArgs] function. | |
* | |
* @return Always returns null. | |
*/ | |
inline fun <T> T.getFragmentArgs(): Nothing? | |
where T : Fragment, T : TypedArgEvent<Nothing?, *> { | |
return null | |
} | |
/** | |
* Creates a bundle containing the fragment arguments. | |
* | |
* @param args The arguments to be put in the bundle. | |
* @return The created bundle. | |
*/ | |
inline fun <T, TArgs : Parcelable> T.createArgsBundle(args: TArgs): Bundle | |
where T : Fragment, T : TypedArgEvent<TArgs, *> { | |
return bundleOf(TypedArgEvent.EXTRA_ARGS to args) | |
} | |
/** | |
* Sends a fragment event to the parent fragment or activity. | |
* | |
* @param event The event to send. | |
*/ | |
inline fun <T, TEvent : Parcelable> T.sendFragmentEvent(event: TEvent) | |
where T : Fragment, T : TypedArgEvent<*, TEvent> { | |
val argEventId = typedInstanceId | |
check(argEventId != null) { | |
"Cannot send event without a argEventId. Please set the argEventId property." | |
} | |
parentFragmentManager.setFragmentResult(argEventId, bundleOf(TypedArgEvent.EXTRA_EVENT to event)) | |
} | |
/** | |
* Sets the event listener for the specified fragment manager and lifecycle owner, using a lambda to handle events. | |
* | |
* @param fragmentManager The fragment manager to set the event listener on. | |
* @param lifecycleOwner The lifecycle owner (fragment or activity) associated with the event listener. | |
* @param onEvent The lambda function to handle events. | |
* | |
* @throws IllegalArgumentException if the argEventId is not set. | |
*/ | |
@Suppress("Deprecation") | |
inline fun <T, TEvent : Parcelable> T.setFragmentEventListener( | |
fragmentManager: FragmentManager, | |
lifecycleOwner: LifecycleOwner, | |
crossinline onEvent: (event: TEvent) -> Unit, | |
) where T : Fragment, T : TypedArgEvent<*, TEvent> { | |
fragmentManager.setFragmentResultListener( | |
typedInstanceId ?: return, | |
lifecycleOwner | |
) { _, bundle -> | |
val event = bundle.getParcelable<TEvent>(TypedArgEvent.EXTRA_EVENT) | |
check(event != null) { | |
"Couldn't retrieve the event from bundle. Please check the sendFragmentEvent() function." | |
} | |
onEvent(event) | |
} | |
} | |
/** | |
* Sets the event listener for the specified fragment, using a lambda to handle events. | |
* | |
* @param fragment The fragment to set the event listener on. | |
* @param onEvent The lambda function to handle events. | |
* | |
* @throws IllegalArgumentException if the argEventId is not set or if the provided fragment is the same as the current fragment. | |
*/ | |
inline fun <T, TEvent : Parcelable> T.setFragmentEventListener( | |
fragment: Fragment, | |
crossinline onEvent: (event: TEvent) -> Unit, | |
) where T : Fragment, T : TypedArgEvent<*, TEvent> { | |
require(fragment != this) { | |
"Cannot set the event listener on the same fragment instance: ${fragment::class.qualifiedName}." | |
} | |
setFragmentEventListener(fragment.childFragmentManager, fragment.viewLifecycleOwner, onEvent) | |
} | |
/** | |
* Sets the event listener for the specified activity, using a lambda to handle events. | |
* | |
* @param activity The activity to set the event listener on. | |
* @param onEvent The lambda function to handle events. | |
* | |
* @throws IllegalArgumentException if the argEventId is not set. | |
*/ | |
inline fun <T, TEvent : Parcelable> T.setFragmentEventListener( | |
activity: FragmentActivity, | |
crossinline onEvent: (event: TEvent) -> Unit, | |
) where T : Fragment, T : TypedArgEvent<*, TEvent> { | |
setFragmentEventListener(activity.supportFragmentManager, activity, onEvent) | |
} | |
/** | |
* Clears the stored event. | |
*/ | |
inline fun <T> T.clearFragmentEvent() where T : Fragment, T : TypedArgEvent<*, *> { | |
parentFragmentManager.clearFragmentResult(typedInstanceId ?: return) | |
} | |
/** | |
* Clears the fragment stored event listener. | |
*/ | |
inline fun <T> T.clearFragmentEventListener() where T : Fragment, T : TypedArgEvent<*, *> { | |
val argEventId = typedInstanceId | |
check(argEventId != null) { | |
"Cannot clear event listener without a argEventId. Please set the argEventId property." | |
} | |
parentFragmentManager.clearFragmentResultListener(argEventId) | |
} | |
/** | |
* Shows the dialog fragment. | |
* | |
* @param fragmentManager The FragmentManager this fragment will be added to. | |
* @param tag The tag for this fragment, as per [androidx.fragment.app.FragmentTransaction.add]. | |
*/ | |
inline fun <T> T.showDialog( | |
fragmentManager: FragmentManager, | |
tag: String?, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
show(fragmentManager, tag) | |
} | |
/** | |
* Shows the dialog fragments. | |
* | |
* @param fragmentManager The FragmentManager this fragment will be added to. | |
*/ | |
inline fun <T> T.showDialog( | |
fragmentManager: FragmentManager, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
val argEventId = typedInstanceId | |
check(argEventId != null) { | |
"Cannot show dialog without a argEventId. Please set the argEventId property." | |
} | |
showDialog(fragmentManager, argEventId) | |
} | |
/** | |
* Shows the dialog fragment. | |
* | |
* @param fragment The fragment from which the dialog fragment it's going to be shown. | |
*/ | |
inline fun <T> T.showDialog( | |
fragment: Fragment, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
require(fragment != this) { | |
"Cannot set event listener on the same dialog fragment instance: ${fragment::class.qualifiedName}." | |
} | |
showDialog(fragment.childFragmentManager) | |
} | |
/** | |
* Shows the dialog fragment. | |
* | |
* @param activity The activity from which the dialog fragment it's going to be shown. | |
*/ | |
inline fun <T> T.showDialog( | |
activity: FragmentActivity, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
showDialog(activity.supportFragmentManager) | |
} | |
/** | |
* Shows the dialog fragment with arguments. | |
* | |
* @param fragmentManager The FragmentManager this fragment will be added to. | |
* @param tag The tag for this fragment, as per [androidx.fragment.app.FragmentTransaction.add]. | |
* @param args The arguments that can passed to the dialog fragment. | |
*/ | |
inline fun <T, TArgs : Parcelable> T.showDialog( | |
fragmentManager: FragmentManager, | |
tag: String?, | |
args: TArgs, | |
) where T : DialogFragment, T : TypedArgEvent<TArgs, *> { | |
arguments = createArgsBundle(args) | |
show(fragmentManager, tag) | |
} | |
/** | |
* Shows the dialog fragment with arguments. | |
* | |
* @param fragmentManager The FragmentManager this fragment will be added to. | |
* @param args The arguments that can passed to the dialog fragment. | |
*/ | |
inline fun <T, TArgs : Parcelable> T.showDialog( | |
fragmentManager: FragmentManager, | |
args: TArgs, | |
) where T : DialogFragment, T : TypedArgEvent<TArgs, *> { | |
val argEventId = typedInstanceId | |
check(argEventId != null) { | |
"Cannot show dialog without a argEventId. Please set the argEventId property." | |
} | |
showDialog(fragmentManager, argEventId, args) | |
} | |
/** | |
* Shows the dialog fragment with arguments. | |
* | |
* @param fragment The fragment from which the dialog fragment it's going to be shown. | |
* @param args The arguments that can passed to the dialog fragment. | |
*/ | |
inline fun <T, TArgs : Parcelable> T.showDialog( | |
fragment: Fragment, | |
args: TArgs, | |
) where T : DialogFragment, T : TypedArgEvent<TArgs, *> { | |
require(fragment != this) { | |
"Cannot set event listener on the same dialog fragment instance: ${fragment::class.qualifiedName}." | |
} | |
showDialog(fragment.childFragmentManager, args) | |
} | |
/** | |
* Shows the dialog fragment with arguments. | |
* | |
* @param activity The activity from which the dialog fragment it's going to be shown. | |
* @param args The arguments that can passed to the dialog fragment. | |
*/ | |
inline fun <T, TArgs : Parcelable> T.showDialog( | |
activity: FragmentActivity, | |
args: TArgs, | |
) where T : DialogFragment, T : TypedArgEvent<TArgs, *> { | |
showDialog(activity.supportFragmentManager, args) | |
} | |
/** | |
* Ensures the dialog fragment is shown only once. | |
* | |
* @param fragmentManager The FragmentManager this fragment will be added to. | |
* @param tag The tag for this fragment, as per [androidx.fragment.app.FragmentTransaction.add]. | |
*/ | |
inline fun <T> T.showDialogOnce( | |
fragmentManager: FragmentManager, | |
tag: String, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
val self = fragmentManager.findFragmentByTag(typedInstanceId) as? DialogFragment | |
if (self == null || dialog?.isShowing == false) { | |
showDialog(fragmentManager, tag) | |
} | |
} | |
/** | |
* Ensures the dialog fragment is shown only once. | |
* | |
* @param fragmentManager The FragmentManager this fragment will be added to. | |
*/ | |
inline fun <T> T.showDialogOnce( | |
fragmentManager: FragmentManager, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
val argEventId = typedInstanceId | |
check(argEventId != null) { | |
"Cannot show dialog without a argEventId. Please set the argEventId property." | |
} | |
showDialogOnce(fragmentManager, argEventId) | |
} | |
/** | |
* Ensures the dialog fragment is shown only once. | |
* | |
* @param fragment The fragment from which the dialog fragment it's going to be shown. | |
*/ | |
inline fun <T> T.showDialogOnce( | |
fragment: Fragment, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
require(fragment != this) { | |
"Cannot set event listener on the same dialog fragment instance: ${fragment::class.qualifiedName}." | |
} | |
showDialogOnce(fragment.childFragmentManager) | |
} | |
/** | |
* Ensures the dialog fragment is shown only once. | |
* | |
* @param activity The activity from which the dialog fragment it's going to be shown. | |
*/ | |
inline fun <T> T.showDialogOnce( | |
activity: FragmentActivity, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
showDialogOnce(activity.supportFragmentManager) | |
} | |
/** | |
* Ensures the dialog fragment is shown only once with arguments. | |
* | |
* @param fragmentManager The FragmentManager this fragment will be added to. | |
* @param tag The tag for this fragment, as per [androidx.fragment.app.FragmentTransaction.add]. | |
* @param args The arguments that can passed to the dialog fragment. | |
*/ | |
inline fun <T, TArgs : Parcelable> T.showDialogOnce( | |
fragmentManager: FragmentManager, | |
tag: String, | |
args: TArgs, | |
) where T : DialogFragment, T : TypedArgEvent<TArgs, *> { | |
val self = fragmentManager.findFragmentByTag(typedInstanceId) as? DialogFragment | |
if (self == null || dialog?.isShowing == false) { | |
showDialog(fragmentManager, tag, args) | |
} | |
} | |
/** | |
* Ensures the dialog fragment is shown only once with arguments. | |
* | |
* @param fragmentManager The FragmentManager this fragment will be added to. | |
* @param args The arguments that can passed to the dialog fragment. | |
*/ | |
inline fun <T, TArgs : Parcelable> T.showDialogOnce( | |
fragmentManager: FragmentManager, | |
args: TArgs, | |
) where T : DialogFragment, T : TypedArgEvent<TArgs, *> { | |
val argEventId = typedInstanceId | |
check(argEventId != null) { | |
"Cannot show dialog without a argEventId. Please set the argEventId property." | |
} | |
showDialogOnce(fragmentManager, argEventId, args) | |
} | |
/** | |
* Ensures the dialog fragment is shown only once with arguments. | |
* | |
* @param fragment The fragment from which the dialog fragment it's going to be shown. | |
* @param args The arguments that can passed to the dialog fragment. | |
*/ | |
inline fun <T, TArgs : Parcelable> T.showDialogOnce( | |
fragment: Fragment, | |
args: TArgs, | |
) where T : DialogFragment, T : TypedArgEvent<TArgs, *> { | |
require(fragment != this) { | |
"Cannot set event listener on the same dialog fragment instance: ${fragment::class.qualifiedName}." | |
} | |
showDialogOnce(fragment.childFragmentManager, args) | |
} | |
/** | |
* Ensures the dialog fragment is shown only once with arguments. | |
* | |
* @param activity The activity from which the dialog fragment it's going to be shown. | |
* @param args The arguments that can passed to the dialog fragment. | |
*/ | |
inline fun <T, TArgs : Parcelable> T.showDialogOnce( | |
activity: FragmentActivity, | |
args: TArgs, | |
) where T : DialogFragment, T : TypedArgEvent<TArgs, *> { | |
showDialogOnce(activity.supportFragmentManager, args) | |
} | |
/** | |
* Dismisses the dialog fragment safely, even outside the dialog fragment itself. | |
* | |
* @param fragmentManager The fragment manager associated with the dialog fragment. | |
*/ | |
inline fun <T> T.dismissDialog( | |
fragmentManager: FragmentManager, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
val self = fragmentManager.findFragmentByTag(typedInstanceId) as? DialogFragment | |
if (self?.isStateSaved == true) { | |
self.dismissAllowingStateLoss() | |
} | |
else self?.dismiss() | |
} | |
/** | |
* Dismisses the dialog fragment safely, even outside the dialog fragment itself. | |
* | |
* @param fragment The fragment associated with the dialog fragment. | |
*/ | |
inline fun <T> T.dismissDialog( | |
fragment: Fragment, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
dismissDialog(fragment.childFragmentManager) | |
} | |
/** | |
* Dismisses the dialog fragment safely, even outside the dialog fragment itself. | |
* | |
* @param activity The activity associated with the dialog fragment. | |
*/ | |
inline fun <T> T.dismissDialog( | |
activity: FragmentActivity, | |
) where T : DialogFragment, T : TypedArgEvent<*, *> { | |
dismissDialog(activity.supportFragmentManager) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment