Repository: corona-warn-app/cwa-app-android
File: Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/dialog/CwaDialog.kt (Kotlin)

Code before:

    fun configureOptions(lambda: CwaDialogOptionsBuilder.() -> Unit) {
        options = CwaDialogOptionsBuilder().apply(lambda).build()
    }

    fun build() = CwaDialog(config, actions, options)
}

@Parcelize
data class CwaDialogTexts(
    val title: @RawValue IntOrString? = null,
    val message: @RawValue IntOrString? = null,
    val positiveButton: @RawValue IntOrString? = null,
    val negativeButton: @RawValue IntOrString? = null,
    val neutralButton: @RawValue IntOrString? = null,
) : Parcelable

@CwaDialogDsl
class CwaDialogTextsBuilder {
    private var title = IntOrString()
    private var message = IntOrString()
    private var positiveButton = IntOrString()
    private var negativeButton = IntOrString()
    private var neutralButton = IntOrString()

    @OptIn(ExperimentalTypeInference::class)
    @OverloadResolutionByLambdaReturnType
    @JvmName("titleInt")
    fun title(lambda: () -> Int) {
        title = IntOrString.IntRes(lambda())
    }

    @OptIn(ExperimentalTypeInference::class)
    @OverloadResolutionByLambdaReturnType
    @JvmName("titleString")
    fun title(lambda: () -> String) {
        title = IntOrString.StringRes(lambda())
    }

    @OptIn(ExperimentalTypeInference::class)
    @OverloadResolutionByLambdaReturnType
    @JvmName("messageInt")
    fun message(lambda: () -> Int) {
        message = IntOrString.IntRes(lambda())
    }

    @OptIn(ExperimentalTypeInference::class)
    @OverloadResolutionByLambdaReturnType
    @JvmName("messageString")
    fun message(lambda: () -> String) {
        message = IntOrString.StringRes(lambda())

Review comment (suggestion):
Unfotunately you can't overload functions with lambda params of different types in Kotlin by default. I had to opt in to use this annotation. https://youtrack.jetbrains.com/issue/KT-11265/Overload-resolution-by-lambda-return-type#focus=Comments-27-4303340.0-0

I understand if you don't want to include experimental features in. I can make the DSL usable without it, but it won't look as nice and tidy :/

Code after:
    private var neutralButtonAction: DialogAction = { }
    private var dismissAction: DialogAction = { }
    private var isCancelable: Boolean = true
    private var isDeleteDialog: Boolean = false
    private var customView: Int? = null

    fun title(@StringRes resource: Int) {
        title = IntOrString.IntResource(resource)
    }

    fun title(text: String) {
        title = IntOrString.StringResource(text)
    }

    fun message(@StringRes resource: Int) {
        message = IntOrString.IntResource(resource)
    }

    fun message(text: String) {
        message = IntOrString.StringResource(text)
    }

    fun positiveButton(@StringRes resource: Int, lambda: () -> Unit = { }) {
        positiveButtonText = IntOrString.IntResource(resource)
        positiveButtonAction = lambda
    }

    fun positiveButton(text: String, lambda: () -> Unit = { }) {
        positiveButtonText = IntOrString.StringResource(text)
        positiveButtonAction = lambda
    }

    fun negativeButton(@StringRes resource: Int, lambda: () -> Unit = { }) {
        negativeButtonText = IntOrString.IntResource(resource)
        negativeButtonAction = lambda
    }

    fun negativeButton(text: String, lambda: () -> Unit = { }) {
        negativeButtonText = IntOrString.StringResource(text)
        negativeButtonAction = lambda
    }

    fun neutralButton(@StringRes resource: Int, lambda: () -> Unit = { }) {
        neutralButtonText = IntOrString.IntResource(resource)
        neutralButtonAction = lambda
    }

    fun neutralButton(text: String, lambda: () -> Unit = { }) {
        neutralButtonText = IntOrString.StringResource(text)
        neutralButtonAction = lambda
    }