raamcosta / compose-destinations

Annotation processing library for type-safe Jetpack Compose navigation with no boilerplate.
https://composedestinations.rafaelcosta.xyz
Apache License 2.0
3.23k stars 134 forks source link

Send custom data though Navigating back with a result #678

Closed mohsen2986 closed 1 month ago

mohsen2986 commented 2 months ago

i got this issue Argument type mismatch: actual type is 'com.mohsen.habito.Day', but 'java.nio.charset.Charset' was expected. how i can solve it? here is full error Capture33

raamcosta commented 2 months ago

It's really difficult for me to understand the issue from this. Let me know what you are trying to do and the code you're using to do it. Use formatted code instead of images surrounding code with the button <> you have here on Github.

Thanks

mohsen2986 commented 2 months ago

Thanks for your attention I'm trying rend result back though navigation here is the screen that open dialogue

@Destination<RootGraph>
@Composable
fun AddTask(
    viewModel: MainViewModel ,
    navigator: DestinationsNavigator,
    resultRecipient: ResultRecipient<DialWithDialogExampleDestination, Day>,
){
    resultRecipient.onResult { resultValue ->
        println("got result $resultValue")
        Log.d("log" , "result $resultValue")
    }
    }

and here the dialogue implementation

@OptIn(ExperimentalMaterial3Api::class)
@Destination<RootGraph>(style = DestinationStyle.Dialog.Default::class)
@Composable
fun DialWithDialogExample(
    resultNavigator: ResultBackNavigator<Day>
) {
    TimePickerDialog(
        onDismiss = {
            resultNavigator.navigateBack()
                    },
        onConfirm = {
            resultNavigator.navigateBack(result = Day("sd"))
        }
    ) {
        TimePicker(
            state = timePickerState,
        )
    }
}

and Day data class is here

@Serializable
data class Day(
    val dayName: String,
)

and my library versions is here

 implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
    implementation ("io.github.raamcosta.compose-destinations:core:2.0.0-beta11")
    ksp ("io.github.raamcosta.compose-destinations:ksp:2.0.0-beta11")

I'm confusing what I'm missed? Thanks in advance

raamcosta commented 2 months ago

Can you show me how the generated DayNavType looks like?

mohsen2986 commented 2 months ago

yes


import android.os.Bundle
import androidx.lifecycle.SavedStateHandle
import com.mohsen.habito.Task
import com.ramcosta.composedestinations.generated.navargs.ktxserializable.DefaultKtxSerializableNavTypeSerializer
import com.ramcosta.composedestinations.navargs.DestinationsNavType
import com.ramcosta.composedestinations.navargs.primitives.DECODED_NULL
import com.ramcosta.composedestinations.navargs.primitives.ENCODED_NULL
import com.ramcosta.composedestinations.navargs.utils.encodeForRoute
import kotlinx.serialization.ExperimentalSerializationApi

@OptIn(ExperimentalSerializationApi::class)
public val taskNavType: TaskNavType = TaskNavType(
    DefaultKtxSerializableNavTypeSerializer(Task.serializer())
)

@OptIn(ExperimentalSerializationApi::class)
public class TaskNavType(
    private val serializer: DefaultKtxSerializableNavTypeSerializer<Task>
) : DestinationsNavType<Task?>() {

    override fun get(bundle: Bundle, key: String): Task? =
        bundle.getByteArray(key)?.let { fromByteArray(it) }

    override fun put(bundle: Bundle, key: String, value: Task?) {
        bundle.putByteArray(key, value?.let { toByteArray(it) })
    }

    override fun parseValue(value: String): Task? {
        return if (value == DECODED_NULL) {
            null
        } else {
            serializer.fromRouteString(value)       
        }
    }

    override fun serializeValue(value: Task?): String {
        return if (value == null) {
            ENCODED_NULL
        } else {
            encodeForRoute(serializer.toRouteString(value))
        }
    }

    override fun get(savedStateHandle: SavedStateHandle, key: String): Task? {
        return savedStateHandle.get<ByteArray>(key)?.let { fromByteArray(it) }
    }

    override fun put(savedStateHandle: SavedStateHandle, key: String, value: Task?) {
        savedStateHandle[key] = value?.let { toByteArray(it) }
    }

    private fun fromByteArray(bytes: ByteArray): Task = serializer.fromByteArray(bytes)

    private fun toByteArray(value: Task): ByteArray = serializer.toByteArray(value)

}
raamcosta commented 1 month ago

This is TaskNavType, I wonder how DayNavType looks like :)

raamcosta commented 1 month ago

That's where the error is, looking at the first image with the errors you posted.

mohsen2986 commented 1 month ago

It doesn't matter which type it is ! It always shows the same error: DefaultKtxSerializableNavTypeSerializer not found.

Here is the generated code with Day class.


package com.ramcosta.composedestinations.generated.navtype

import android.os.Bundle
import androidx.lifecycle.SavedStateHandle
import com.mohsen.habito.model.Day
import com.ramcosta.composedestinations.generated.navargs.ktxserializable.DefaultKtxSerializableNavTypeSerializer
import com.ramcosta.composedestinations.navargs.DestinationsNavType
import com.ramcosta.composedestinations.navargs.primitives.DECODED_NULL
import com.ramcosta.composedestinations.navargs.primitives.ENCODED_NULL
import com.ramcosta.composedestinations.navargs.utils.encodeForRoute
import kotlinx.serialization.ExperimentalSerializationApi

@OptIn(ExperimentalSerializationApi::class)
public val dayNavType: DayNavType = DayNavType(
    DefaultKtxSerializableNavTypeSerializer(Day.serializer())
)

@OptIn(ExperimentalSerializationApi::class)
public class DayNavType(
    private val serializer: DefaultKtxSerializableNavTypeSerializer<Day>
) : DestinationsNavType<Day?>() {

    override fun get(bundle: Bundle, key: String): Day? =
        bundle.getByteArray(key)?.let { fromByteArray(it) }

    override fun put(bundle: Bundle, key: String, value: Day?) {
        bundle.putByteArray(key, value?.let { toByteArray(it) })
    }

    override fun parseValue(value: String): Day? {
        return if (value == DECODED_NULL) {
            null
        } else {
            serializer.fromRouteString(value)       
        }
    }

    override fun serializeValue(value: Day?): String {
        return if (value == null) {
            ENCODED_NULL
        } else {
            encodeForRoute(serializer.toRouteString(value))
        }
    }

    override fun get(savedStateHandle: SavedStateHandle, key: String): Day? {
        return savedStateHandle.get<ByteArray>(key)?.let { fromByteArray(it) }
    }

    override fun put(savedStateHandle: SavedStateHandle, key: String, value: Day?) {
        savedStateHandle[key] = value?.let { toByteArray(it) }
    }

    private fun fromByteArray(bytes: ByteArray): Day = serializer.fromByteArray(bytes)

    private fun toByteArray(value: Day): ByteArray = serializer.toByteArray(value)

}

and here is the IDE errors image

raamcosta commented 1 month ago

What lib version are you using?

raamcosta commented 1 month ago

Do you have any navigation arguments other than the ones you want to send back, that are Ktx Serializable?

I think I may know what’s the issue 🤔

mohsen2986 commented 1 month ago

What lib version are you using?

I'm using 2.1.0-beta12 version

mohsen2986 commented 1 month ago

Do you have any navigation arguments other than the ones you want to send back, that are Ktx Serializable?

I think I may know what’s the issue 🤔

Here is my implementation at the moment


@Serializable
data class Day(
    val dayName: String,
    val monthDayNumber: String,
    @Serializable(with = DateSerializer::class)
    val date: Date,
)

and my dialog is


@Destination<RootGraph>(style = DestinationStyle.Dialog.Default::class)
@Composable
fun DatePicker(
    viewModel: MainViewModel,
    resultBackNavigator: ResultBackNavigator<Day>,
    navigator: DestinationsNavigator,
) {
    DatePickerContent(
        viewModel::setTaskDateForAddTask,
        navigator,
    )
}

and here, I want to result back data


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AddTask(
    addTask: (Task) -> Unit,
    taskDate: String,
    taskTime: SelectedClockState,
    navigator: DestinationsNavigator,
    resultRecipient: ResultRecipient<DatePickerDestination, Day>,
) {
}
raamcosta commented 1 month ago

Should be fixed on latest version, please let me know!

and thanks for reporting! 🙏

mohsen2986 commented 4 weeks ago

I tested it, and it works! Thank you for your attention.