<@UHAJKUSTU> Can you help me with handling back bu...
# multiplatform
s
@Arkadii Ivanov Can you help me with handling back buttons for android?.
Copy code
class RecceSectionsComponent(
    componentContext: ComponentContext,
    recceId: String,
    sectionId: String,
    sectionTitle: String,
    recceGuide: Guide?,
    projectId: String?,
    storeFactory: StoreFactory,
    private val output: (Output) -> Unit
) : ComponentContext by componentContext {
    private val recceStore = instanceKeeper.getStore {
        RecceDetailsStoreFactory(
            storeFactory = storeFactory
        ).create()
    }

    private val backCallback = BackCallback {
        onOutput(Output.NavigateBack)
    }


    init {
        lifecycle.subscribe(object : Lifecycle.Callbacks {

            override fun onResume() {
                super.onResume()
            }

            override fun onStart() {
                super.onStart()
            }
        })
        backHandler.register(backCallback)
        backCallback.isEnabled = true
    }

    val recceId = recceId

    val sectionId = sectionId

    val sectionTitle = sectionTitle
    val recceGuide = recceGuide

    val projectId = projectId

    @OptIn(ExperimentalCoroutinesApi::class)
    val state: StateFlow<RecceDetailsStore.State> = recceStore.stateFlow

    fun onEvent(event: RecceDetailsStore.Intent) {
        recceStore.accept(event)
    }

    fun onOutput(output: Output) {
        output(output)
    }

    sealed class Output {
        object NavigateBack : Output()
        object Logout : Output()
        data class OpenFullScreenComponent<T>(
            val imagesList: List<T>,
            val initialImageIndex: Int,
            val openFrom: String,
            val elementName: String? = null
        ) : Output()
    }
}
Above is RecceSectionsComponent declared in RootComponent.
Copy code
private val navigation = StackNavigation<Configuration>()

private val stack = childStack(
    source = navigation,
    initialConfiguration = getInitConfig(),
    childFactory = ::createChild
)
This is stack in RootCOmponent. I want to pop this component on backpressed, How to Dispacht and inboke this backHandler?
a
Perhaps, #decompose would be a better channel for this question. But regardless, I think you could use automatic navigation via back button, see the docs: https://arkivanov.github.io/Decompose/component/back-button/#navigation-with-back-button
s
@Arkadii Ivanov I already read that but it isn't clear enought can you explain?
Copy code
private val navigation = StackNavigation<Configuration>()

private val stack = childStack(
    source = navigation,
    initialConfiguration = getInitConfig(),
    childFactory = ::createChild,
    handleBackButton = true
)
it says to do something like this, right? But its not working
a
Yes, this. And you don't need
BackCallback
in your child component.
s
not working
Copy code
sealed class Child {
    data class EnterMobileNumber(val component: EnterMobileNumberComponent) : Child()
    data class EnterOtp(val component: EnterOtpComponent) : Child()
    data class ProjectListing(val component: ProjectListingComponent) : Child()
    data class ProjectDetails(val component: ProjectDetailsComponent) : Child()
    data class ImagePreviewFullScreen(val component: ImagePreviewFullScreenComponent) : Child()
    data class Notifications(val component: NotificationsComponent) : Child()
    data class ElementDetails(val component: ElementDetailsComponent) : Child()
    data class OutgoingOrders(val component: OutgoingOrderComponent) : Child()
    data class WorkProgressPreviewFullScreen(val component: WorkProgressPreviewComponent) :
        Child()

    data class DesignPreviewScreen(val component: DesignPreviewComponent) : Child()
    data class EmptyNotificationScreen(val component: EmptyNotificationComponent) : Child()
    data class GenerateReport(val component: GenerateReportComponent) : Child()
    data class Recces(val component: RecceComponent) : Child()
    data class ReccesDetails(val component: RecceDetailsComponent) : Child()
    data class RecceSections(val component: RecceSectionsComponent) : Child()

}
There are children of stack in RootComponent
Copy code
val childStack: Value<ChildStack<*, Child>> = stack

private fun createChild(
    configuration: Configuration, componentContext: ComponentContext
): Child = when (configuration) {
    is Configuration.EnterMobileNumber -> Child.EnterMobileNumber(
        enterMobileNumber(
            componentContext, ::onEnterMobileNumberOutput
        )
    )

    is Configuration.EnterOtp -> Child.EnterOtp(
        enterOtp(
            componentContext,
            configuration.mobile,
            configuration.verificationId,
            ::onEnterOtpOutput
        )
    )

    is Configuration.ProjectListing -> Child.ProjectListing(
        projectListing(componentContext, ::onProjectListingOutput)
    )

    is Configuration.ProjectDetails -> Child.ProjectDetails(
        projectDetails(
            componentContext, configuration.projectId, ::onProjectDetailsOutput
        )
    )

    is Configuration.RecceDetails -> Child.ReccesDetails(
        recceDetails(
            componentContext, configuration.recceId, ::onRecceDetailsOutput
        )
    )

    is Configuration.ImagePreviewFullScreen -> Child.ImagePreviewFullScreen(
        imagePreviewFullScreen(
            componentContext,
            configuration.imagesList,
            configuration.initialImageIndex,
            configuration.openFrom,
            configuration.elementName.toString(),
            ::onImagePreviewOutput
        )
    )

    is Configuration.Notification -> Child.Notifications(
        notifications(
            componentContext, ::onNotificationsOutput
        )
    )

    is Configuration.GenerateReport -> Child.GenerateReport(
        generateReport(componentContext, configuration.projectId, ::onGenerateReportOutput)
    )

    is Configuration.ElementDetails -> Child.ElementDetails(
        elementDetails(
            componentContext,
            configuration.projectId,
            configuration.elementId,
            configuration.position,
            configuration.projectUpdateRes,
            configuration.projectDetailsPermissionsResponse,
            configuration.myScopeElementRes,
            ::onElementDetailsOutput
        )
    )

    is Configuration.OutgoingOrders -> Child.OutgoingOrders(
        outgoingOrders(
            componentContext,
            configuration.projectId,
            configuration.vendorOrderId,
            configuration.orderType,
            ::onOutgoingOrdersOutput
        )
    )

    is Configuration.WorkProgressPreviewScreen -> Child.WorkProgressPreviewFullScreen(
        workProgressPreviewFullScreen(
            componentContext,
            configuration.context,
            configuration.progress_report_id,
            configuration.projectId,
            ::onWorkProgressPreviewFullScreenOutput
        )
    )

    is Configuration.DesignPreviewScreen -> Child.DesignPreviewScreen(
        designPreviewScreen(
            componentContext,
            configuration.projectId,
            configuration.fileId,
            configuration.downloadedPath,
            ::onDesignPreviewScreenOutput
        )
    )

    is Configuration.EmptyNotificationScreen -> Child.EmptyNotificationScreen(
        emptyNotificationScreen(
            componentContext, configuration.context, ::onEmptyNotificationScreenOutput
        )
    )

    is Configuration.Recce -> Child.Recces(
        recces(
            componentContext, ::onRecceOutput
        )
    )

    is Configuration.RecceSection -> Child.RecceSections(
        recceSections(
            componentContext,
            configuration.recceId,
            configuration.sectionId,
            configuration.sectionTitle,
            configuration.recceGuide,
            configuration.projectId,
            ::onRecceEditOutput
        )
    )

}
a
By "not working", do you mean nothing happens at all, or the app is closed instead?
s
the fragment is popped off, instead of component popping off and navigating to prev comp
@Arkadii Ivanov as i am using this inside a fragment, do in need to disable anyhow onBackpressed of fragment, as i thing onBackPressed is getting called (overriding)
a
Oh, so you are hosting the component tree in a fragment. In this case, are you following this doc? https://arkivanov.github.io/Decompose/component/overview/#root-componentcontext-in-fragment
s
@Arkadii Ivanov Awesome!, Exactly this, Thanks 🙂
🎉 1
Copy code
@Arkadii Ivanov 
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
    requireContext().applicationContext.let { AppContext.setContext(it) }
    pref.put(RdashConstants.AUTH_TOKEN, authToken)
    AppContext.setFrag(this)
    connectivityReceiver = ConnectivityReceiver()
    requireActivity().registerReceiver(
        connectivityReceiver,
        IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
    )
    val rootComponent = RootComponent(
        componentContext = defaultComponentContext(onBackPressedDispatcher = requireActivity().onBackPressedDispatcher),
        storeFactory = DefaultStoreFactory(),
        initComponent = RbConstants.RECCE_COMPONENT,
        recceDetailClickCallback = recceDetailClickCallback,

    )
    return ComposeView(requireContext()).apply {
        setContent {
            RbSharedTheme {
                Surface(
                    color = RbSharedColors.background, modifier = Modifier.fillMaxSize()
                ) {
                    RootContent(rootComponent)
                }
            }
        }
    }
}
Still not working, same
Copy code
private val navigation = StackNavigation<Configuration>()

private val stack = childStack(
    source = navigation,
    initialConfiguration = getInitConfig(),
    childFactory = ::createChild,
    handleBackButton = true
)
a
Please try creating your RootComponent in
onCreate
instead. It should work.
If it doesn't, then perhaps the back button is being intercepted somewhere else in your app, e.g. in the Activitity.
s
not working
Then how should i override onBackPressed of activity or fragment?
a
Also please note, that the child stack can not be empty. I.e. if there is only one child in the stack, then there is nothing to pop, and the hosting activity will handle the back button instead, closing the fragment.
s
yes , which would be actually right
my stack has more than one component
a
Then how should i override onBackPressed of activity or fragment?
You shouldn't, I believe it's deprecated. You can register your own back callbacks.
s
i am using fragment?, Fragment onBackPressed is not deprecated
how should i handle or register my callbacks then?
a
There is no Fragment#onBackPressed method.
s
oh sorry , Right
a
how should i handle or register my callbacks then?
Why do you need it? I thought you need to pop a child from the Decompose stack by pressing the back button. It works automatically if you supply
handleBackButton = true
argument. However, somewhere else (e.g. in the Activity or another Fragment), you may have a back callback registered and enabled, which may prevent Decompose from handling the back button. Back callbacks are checked in reverse order.
s
Yes, i need to pop a child from the Decompose stack by pressing the back
a
It's hard to tell what is exactly wrong in your case without a reproducer.
s
RootComponent -> Comp A -> Comp B, i need to pop "Comp B" onBackPressed
see first when i click back button on ui it works fine , but on clicking back button of system it pops off everything
Recce V2 is side nav opens RecceFragment which hosts RootComponent
THen we have Recces-> ReccesDetails -> RecceSections Components respectively
a
As I saied, It should work automatically if you supply
handleBackButton = true
argument in that
childStack
. Please double check the following: 1. Make sure that the stack has more than just one component. 2. Check if something prevents Decompose from handling the back button. E.g. try debugging
OnBackPressedDispatcher
of the hosting Activity, and see if the are any other callbacks in there, preventing Decompose from handling. I you believe it's a bug in Decompose, please file an issue with a reproducer here: https://github.com/arkivanov/Decompose/issues
s
sure
@Arkadii Ivanov How long will it take to fix this bug, as i have to push my code to production, this would be a blocker
a
I don't think there is a bug in Decompose. Please file an issue with a reproducer IF you believe that it's a bug.
s
sure i will do that
👍 1
@Arkadii Ivanov onBackPressed of Activity is getting called!