Skip to content

Commit

Permalink
fix(health-sdk): Fix Share With flow broken when clients pop backst…
Browse files Browse the repository at this point in the history
…ack after getting payment request callback

- Added a broadcast receiver to intercept taps on the system share sheet
- Move sending of `OpenBankState.Success` to after user picks an external app to share to
- Drawback is that the `OpenBankState.Success` event is not shared if the user dismisses the share sheet - but then I guess it's not of interest to the client to know that the `paymentRequest` was created, but not finalised

IPC-290
  • Loading branch information
danicretu committed Jul 1, 2024
1 parent 6e392e6 commit ab530fa
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ open class InvoicesActivity : AppCompatActivity() {
when (paymentState) {
is GiniHealth.PaymentState.Success -> {
viewModel.updateDocument()
supportFragmentManager.popBackStack()
}
else -> {}
}
Expand Down
1 change: 1 addition & 0 deletions health-sdk/sdk/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<receiver android:name=".review.ReviewFragment$ShareWithBroadcastReceiver" android:exported="false"/>
</application>

<queries>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package net.gini.android.health.sdk.review

import android.app.PendingIntent
import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
Expand Down Expand Up @@ -128,6 +132,12 @@ class ReviewFragment private constructor(
private var documentPageAdapter: DocumentPageAdapter by autoCleared()
private var isKeyboardShown = false
private var errorSnackbar: Snackbar? = null
private var broadcastReceiver = object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
viewModel.setOpenBankStateAfterShareWith()
}
}


override fun onGetLayoutInflater(savedInstanceState: Bundle?): LayoutInflater {
val inflater = super.onGetLayoutInflater(savedInstanceState)
Expand Down Expand Up @@ -214,6 +224,10 @@ class ReviewFragment private constructor(
handlePaymentNextStep(paymentNextStep)
}
}
launch {
requireActivity().registerReceiver(broadcastReceiver, IntentFilter().also { it.addAction(SHARE_INTENT_FILTER) },
Context.RECEIVER_NOT_EXPORTED)
}
}
}
}
Expand Down Expand Up @@ -585,7 +599,7 @@ class ReviewFragment private constructor(
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
putExtra(Intent.EXTRA_STREAM, uriForFile)
}
startActivity(Intent.createChooser(shareIntent, uriForFile.lastPathSegment))
startActivity(Intent.createChooser(shareIntent, uriForFile.lastPathSegment, createSharePendingIntent().intentSender))
}

private fun handlePaymentNextStep(paymentNextStep: ReviewViewModel.PaymentNextStep) {
Expand All @@ -609,13 +623,28 @@ class ReviewFragment private constructor(
}
}

private fun createSharePendingIntent() = PendingIntent.getBroadcast(
requireContext(), CHOOSER_REQUEST_ID,
Intent(requireContext(), ShareWithBroadcastReceiver::class.java),
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)

override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(PAGER_HEIGHT, binding.pager.layoutParams.height)
super.onSaveInstanceState(outState)
}

override fun onStop() {
requireActivity().unregisterReceiver(broadcastReceiver)
super.onStop()
}

internal companion object {
private const val PAGER_HEIGHT = "pager_height"
internal const val SHARE_INTENT_FILTER = "share_intent_filter"

// This is only required to send when creating the pending intent for the share sheet - not actually used anywhere else
internal const val CHOOSER_REQUEST_ID = 123
fun newInstance(
giniHealth: GiniHealth,
configuration: ReviewConfiguration = ReviewConfiguration(),
Expand All @@ -625,4 +654,10 @@ class ReviewFragment private constructor(
viewModelFactory: ViewModelProvider.Factory = ReviewViewModel.Factory(giniHealth, configuration, paymentComponent, documentId),
): ReviewFragment = ReviewFragment(listener, paymentComponent, viewModelFactory)
}

internal class ShareWithBroadcastReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
context?.sendBroadcast(Intent().also { it.action = SHARE_INTENT_FILTER })
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ internal class ReviewViewModel(

private var openWithCounter: Int = 0

private val _paymentRequestFlow = MutableStateFlow<PaymentRequest?>(null)

val isPaymentButtonEnabled: Flow<Boolean> =
combine(giniHealth.openBankState, paymentDetails) { paymentState, paymentDetails ->
val noEmptyFields = paymentDetails.recipient.isNotEmpty() && paymentDetails.iban.isNotEmpty() &&
Expand Down Expand Up @@ -305,6 +307,7 @@ internal class ReviewViewModel(
giniHealth.setOpenBankState(GiniHealth.PaymentState.Error(throwable), viewModelScope)
return@withContext
}
_paymentRequestFlow.value = paymentRequest
val byteArrayResource = async { giniHealth.giniHealthAPI.documentManager.getPaymentRequestDocument(paymentRequest.id) }.await()
when (byteArrayResource) {
is Resource.Cancelled -> {
Expand All @@ -314,7 +317,6 @@ internal class ReviewViewModel(
giniHealth.setOpenBankState(GiniHealth.PaymentState.Error(byteArrayResource.exception ?: Exception("Error")), viewModelScope)
}
is Resource.Success -> {
giniHealth.setOpenBankState(GiniHealth.PaymentState.Success(paymentRequest), viewModelScope)
val newFile = externalCacheDir?.createTempPdfFile(byteArrayResource.data, "payment-request")
newFile?.let {
_paymentNextStep.tryEmit(PaymentNextStep.OpenSharePdf(it))
Expand All @@ -325,6 +327,12 @@ internal class ReviewViewModel(
}
}

internal fun setOpenBankStateAfterShareWith() {
_paymentRequestFlow.value?.let {
giniHealth.setOpenBankState(GiniHealth.PaymentState.Success(it), viewModelScope)
}
}

private fun sendFeedbackAndStartLoading() {
giniHealth.setOpenBankState(GiniHealth.PaymentState.Loading, viewModelScope)
// TODO: first get the payment request and handle error before proceeding
Expand Down

0 comments on commit ab530fa

Please sign in to comment.