package com.withpersona.sdk2.reactnative import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.withpersona.sdk2.inquiry.ExperimentalInlineApi import com.withpersona.sdk2.inquiry.InquiryResponse import com.withpersona.sdk2.inquiry.inline_inquiry.InlineInquiryController import com.withpersona.sdk2.inquiry.inline_inquiry.InlineInquiryScreen import com.withpersona.sdk2.inquiry.internal.InquiryIntentKeys import com.withpersona.sdk2.inquiry.types.DEFAULT_REQUEST_KEY import com.withpersona.sdk2.inquiry.types.InquiryErrorMessages import com.withpersona.sdk2.inquiry.types.collected_data.ErrorCode import kotlinx.coroutines.launch /** * Wrapper fragment that acts as a parent for [InquiryFragment] and implements * [InlineInquiryController] to receive event callbacks from the child [InquiryFragment]. */ @OptIn(ExperimentalInlineApi::class) class InlineInquiryWrapperFragment : Fragment(), InlineInquiryController { companion object { private const val ARG_REQUEST_KEY = "pi2_rn_request_key" const val ARG_EVENT = "pi2_rn_event" fun newInstance( requestKey: String, inquiryFragment: Fragment, ): InlineInquiryWrapperFragment = InlineInquiryWrapperFragment().apply { arguments = Bundle().apply { putString(ARG_REQUEST_KEY, requestKey) } // This is a hack in order to let InlineInquiryWrapperFragment launch the InquiryFragment. // This is very difficult to do without code changes to the SDK side. This hack should // not cause any issues since the fragment should only need to be launched once. // On kill/restore, the fragment state should be saved by the fragment manager. this.inquiryFragment = inquiryFragment } } private var inlineInquiryScreen: InlineInquiryScreen? = null private var inquiryFragment: Fragment? = null private var requestKey: String? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { return FrameLayout(requireContext()).apply { id = R.id.pi2_rn_wrapper_fragment_frame_layout layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) requestKey = arguments?.getString(ARG_REQUEST_KEY) childFragmentManager.setFragmentResultListener(DEFAULT_REQUEST_KEY, viewLifecycleOwner) { _, result -> parentFragmentManager.setFragmentResult(DEFAULT_REQUEST_KEY, result) } // Only add the fragment on first launch. On save/restore, the fragment manager should // restore the fragment for us. if (savedInstanceState == null) { val inquiryFragment = inquiryFragment if (inquiryFragment != null) { childFragmentManager .beginTransaction() .add(R.id.pi2_rn_wrapper_fragment_frame_layout, inquiryFragment) .commit() } else { parentFragmentManager.setFragmentResult( DEFAULT_REQUEST_KEY, Bundle().apply { putString( InquiryIntentKeys.PERSONA_ACTIVITY_RESULT, InquiryIntentKeys.Status.INQUIRY_ERROR.name, ) putString(InquiryIntentKeys.ERROR_DEBUG_MESSAGE, InquiryErrorMessages.unexpectedError) putParcelable(InquiryIntentKeys.ERROR_CODE, ErrorCode.UnexpectedError) } ) } } } override fun onAttached(inlineInquiryScreen: InlineInquiryScreen) { this.inlineInquiryScreen = inlineInquiryScreen viewLifecycleOwner.lifecycleScope.launch { inlineInquiryScreen.eventFlow.collect { val requestKey = requestKey if (requestKey != null) { parentFragmentManager.setFragmentResult( requestKey, Bundle().apply { putParcelable(ARG_EVENT, it) } ) } } } } override fun onDetached() { inlineInquiryScreen = null } }