livefront / sealed-enum

A Kotlin annotation processor that makes writing normal enum classes obsolete.
Apache License 2.0
149 stars 7 forks source link

different sealed class with data class + data object cannot compile [Question] #138

Closed thomas200593 closed 2 months ago

thomas200593 commented 2 months ago
@Serializable sealed class ScrGraphs(
    val route: String,
    @DrawableRes val iconRes: Int? = null,
    @StringRes val title: Int? = null,
    @StringRes val description: Int? = null,
    val usesAuth: Boolean,
    val usesTopBar: Boolean
) {
    /**
     * Companion Object
     */
    @GenSealedEnum(generateEnum = true)
    companion object {
        fun screenWithTopAppBar() = ScrGraphs.sealedEnum.values.filter { it.usesTopBar }
        .map { it.route }.toSet()
    }

    @Serializable data class A(val id: Int = 1): ScrGraphs(
        route = "",
        usesAuth = true,
        usesTopBar = false
    )

    /**
     * Initial
     */
    @Serializable data object Initial: ScrGraphs(
        route = "r_initial",
        usesAuth = false,
        usesTopBar = false
    )
    @Serializable data object Initialization: ScrGraphs(
        route = "r_initialization",
        usesAuth = false,
        usesTopBar = false
    )
}

returned error during compile time: ScrGraphs.kt:26: Annotated sealed class has a non-object subclass

I need those sealed class structure for Screen Graph (navigation compose) but it won't compile, am I doing it wrong?

alexvanyo commented 2 months ago

The compiler error is expected due to the data class A, since there can be many different instances of A with different arguments. For that reason, it would be confusing to have one specific instance of A in the values list from an enum perspective.

For your use case, it looks like you're trying to infer something about the "type" of screen, of which there would only be 3 distinct types, but there can be an arbitrary number of different instances of some type of screen.

You could try something along the lines of this:

sealed class ScrGraphsType(
    val route: String,
    val usesAuth: Boolean,
    val usesTopBar: Boolean
) {
    @GenSealedEnum(generateEnum = true)
    companion object {
        fun screenTypeWithTopAppBar() = ScrGraphsType.sealedEnum.values.filter { it.usesTopBar }
        .map { it.route }.toSet()
    }

    data object A: ScrGraphsType(
        route = "",
        usesAuth = true,
        usesTopBar = false
    )
    data object Initial: ScrGraphsType(
        route = "r_initial",
        usesAuth = false,
        usesTopBar = false
    )
    data object Initialization: ScrGraphsType(
        route = "r_initialization",
        usesAuth = false,
        usesTopBar = false
    )
}
@Serializable
sealed class ScrGraphs(
    val type: SrcGraphsType,
) {
    @Serializable data class A(val id: Int = 1): ScrGraphs(
        ScrGraphsType.A
    )
    @Serializable data object Initial: ScrGraphs(
        ScrGraphsType.Initial
    )
    @Serializable data object Initialization: ScrGraphs(
        ScrGraphsType.Initialization
    )
}

By making a explicit SrcGraphsType, you can create a enumeration of all different types of screens, and then your specific screen instances have a reference to what Type they represent.