Skip to content

Commit 1038196

Browse files
committed
feat(flipcash): add back cash link confirmation modal - but smarter
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 58c4d8e commit 1038196

4 files changed

Lines changed: 148 additions & 40 deletions

File tree

apps/flipcash/core/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,7 @@
123123
<string name="error_description_missingBiometrics">Biometrics are no longer available on your device.</string>
124124

125125
<string name="action_unlockCode">Unlock Flipcash</string>
126+
127+
<string name="prompt_description_didYouSendLink">Any cash that isn\'t collected within 24 hours will be automatically returned to your balance.</string>
128+
126129
</resources>

apps/flipcash/features/scanner/src/main/kotlin/com/flipcash/app/scanner/internal/bills/BillContainerView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ internal fun BillContainer(
232232
// wait for spring settle to enable cancel to not prematurely cancel
233233
// the enter. doing so causing the exit of the bill to not run, or run its own dismiss animation
234234
if (transition.targetState == EnterExitState.Visible && transition.currentState == transition.targetState) {
235-
delay(300)
235+
delay(500)
236236
canCancel = true
237237
}
238238
}

apps/flipcash/shared/session/src/main/kotlin/com/flipcash/app/session/internal/RealSessionController.kt

Lines changed: 143 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.flipcash.core.R
2222
import com.flipcash.services.billing.BillingClient
2323
import com.flipcash.services.controllers.AccountController
2424
import com.flipcash.services.user.UserManager
25+
import com.getcode.manager.BottomBarAction
2526
import com.getcode.manager.BottomBarManager
2627
import com.getcode.manager.TopBarManager
2728
import com.getcode.opencode.controllers.TransactionController
@@ -46,6 +47,7 @@ import com.kik.kikx.models.ScannableKikCode
4647
import kotlinx.coroutines.CoroutineScope
4748
import kotlinx.coroutines.Dispatchers
4849
import kotlinx.coroutines.SupervisorJob
50+
import kotlinx.coroutines.coroutineScope
4951
import kotlinx.coroutines.delay
5052
import kotlinx.coroutines.flow.MutableStateFlow
5153
import kotlinx.coroutines.flow.StateFlow
@@ -301,51 +303,88 @@ class RealSessionController @Inject constructor(
301303
amount: LocalFiat, owner: AccountCluster, restartBillGrabber: () -> Unit
302304
) {
303305
val giftCard = GiftCardAccount.create()
304-
305-
val initiateFunding = { amt: LocalFiat, resetShareController: Boolean ->
306-
billController.fundGiftCard(
307-
giftCard = giftCard,
308-
amount = amt,
309-
owner = owner,
310-
onFunded = {
311-
toastController.show(it)
312-
bringActivityFeedCurrent()
313-
if (resetShareController) {
314-
shareSheetController.reset()
315-
}
316-
},
317-
onError = {
318-
cancelSend()
319-
TopBarManager.showMessage(
320-
title = resources.getString(R.string.error_title_failedToCreateGiftCard),
321-
message = resources.getString(R.string.error_description_failedToCreateGiftCard)
322-
)
323-
}
324-
)
325-
}
306+
val shareable = Shareable.CashLink(giftCardAccount = giftCard, amount = amount)
326307

327308
scope.launch {
328309
shareSheetController.onShared = { result ->
329310
when (result) {
330311
ShareResult.CopiedToClipboard -> {
331-
// pop the bill out as if grabbed/sent, but don't toast until funded
332-
cancelSend(PresentationStyle.Pop, overrideToast = true)
312+
presentShareConfirmationModal(
313+
giftCard, owner, amount, result,
314+
onDidNotShare = restartBillGrabber,
315+
reshare = {
316+
scope.launch { shareSheetController.present(shareable) }
317+
}
318+
)
319+
}
320+
321+
is ShareResult.SharedToApp -> {
322+
presentShareConfirmationModal(
323+
giftCard, owner, amount, result,
324+
onDidNotShare = restartBillGrabber,
325+
reshare = {
326+
scope.launch { shareSheetController.present(shareable) }
327+
}
328+
)
329+
}
330+
331+
ShareResult.NotShared -> {
332+
restartBillGrabber()
333+
}
334+
}
335+
}
336+
delay(500)
337+
shareSheetController.present(shareable)
338+
}
339+
}
340+
341+
private fun presentShareConfirmationModal(
342+
giftCard: GiftCardAccount,
343+
owner: AccountCluster,
344+
amount: LocalFiat,
345+
shareResult: ShareResult,
346+
onDidNotShare: () -> Unit,
347+
reshare: () -> Unit,
348+
) {
349+
billController.cancelAwaitForGrab()
350+
351+
val handleConfirmationOrTimeout = { didConfirm: Boolean ->
352+
when (shareResult) {
353+
ShareResult.CopiedToClipboard -> {
354+
// pop the bill out as if grabbed/sent, but don't toast until funded
355+
cancelSend(PresentationStyle.Pop, overrideToast = true)
356+
trace(
357+
tag = "Session",
358+
message = "Cash link copied to clipboard",
359+
metadata = {
360+
"amount" to amount
361+
},
362+
type = TraceType.User,
363+
)
364+
initiateGiftCardFunding(giftCard, owner, amount, true)
365+
vibrator.vibrate()
366+
}
367+
ShareResult.NotShared -> Unit
368+
is ShareResult.SharedToApp -> {
369+
if (!didConfirm) {
370+
// user never confirmed the send, treat as so
333371
trace(
334372
tag = "Session",
335-
message = "Cash link copied to clipboard",
373+
message = "Cash link shared with ${shareResult.to}",
336374
metadata = {
337375
"amount" to amount
338376
},
339377
type = TraceType.User,
340378
)
341-
initiateFunding(amount, true)
342-
}
343-
344-
is ShareResult.SharedToApp -> {
379+
// pop the bill out as if grabbed/sent, but don't toast until funded
380+
cancelSend(PresentationStyle.Pop, overrideToast = true)
381+
giftCard.fund()
382+
initiateGiftCardFunding(giftCard, owner, amount, false)
383+
} else {
345384
if (!giftCard.funded) {
346385
trace(
347386
tag = "Session",
348-
message = "Cash link shared with ${result.to}",
387+
message = "Cash link shared with ${shareResult.to}",
349388
metadata = {
350389
"amount" to amount
351390
},
@@ -354,7 +393,7 @@ class RealSessionController @Inject constructor(
354393
// pop the bill out as if grabbed/sent, but don't toast until funded
355394
cancelSend(PresentationStyle.Pop, overrideToast = true)
356395
giftCard.fund()
357-
initiateFunding(amount, false)
396+
initiateGiftCardFunding(giftCard, owner, amount, false)
358397
} else {
359398
// due to android lifecycles, we need to await
360399
// the return to the app before showing the toast
@@ -363,16 +402,82 @@ class RealSessionController @Inject constructor(
363402
shareSheetController.reset()
364403
}
365404
}
366-
367-
ShareResult.NotShared -> {
368-
restartBillGrabber()
369-
}
370405
}
371406
}
372-
val shareable = Shareable.CashLink(giftCardAccount = giftCard, amount = amount)
373-
delay(500)
374-
shareSheetController.present(shareable)
375407
}
408+
scope.launch {
409+
delay(2.5.seconds)
410+
411+
BottomBarManager.showMessage(
412+
BottomBarManager.BottomBarMessage(
413+
title = resources.getString(R.string.prompt_title_didYouSendLink),
414+
subtitle = resources.getString(R.string.prompt_description_didYouSendLink),
415+
positiveText = resources.getString(R.string.action_yes),
416+
negativeText = resources.getString(R.string.action_noTryAgain),
417+
tertiaryText = resources.getString(R.string.action_cancelSend),
418+
actions = buildList {
419+
add(
420+
BottomBarAction(
421+
text = resources.getString(R.string.action_yes),
422+
onClick = {
423+
handleConfirmationOrTimeout(true)
424+
},
425+
)
426+
)
427+
add(
428+
BottomBarAction(
429+
text = resources.getString(R.string.action_noTryAgain),
430+
style = BottomBarManager.BottomBarButtonStyle.Filled50,
431+
onClick = reshare
432+
)
433+
)
434+
},
435+
onPositive = {
436+
437+
},
438+
onNegative = reshare,
439+
onTertiary = onDidNotShare,
440+
onClose = { fromAction ->
441+
if (!fromAction) {
442+
handleConfirmationOrTimeout(false)
443+
} else {
444+
onDidNotShare()
445+
}
446+
},
447+
type = BottomBarManager.BottomBarMessageType.REMOTE_SEND,
448+
isDismissible = false,
449+
showCancel = true,
450+
timeoutSeconds = 60
451+
)
452+
)
453+
}
454+
}
455+
456+
private fun initiateGiftCardFunding(
457+
giftCard: GiftCardAccount,
458+
owner: AccountCluster,
459+
amount: LocalFiat,
460+
resetShareController: Boolean
461+
) {
462+
billController.fundGiftCard(
463+
giftCard = giftCard,
464+
amount = amount,
465+
owner = owner,
466+
onFunded = {
467+
toastController.show(it)
468+
bringActivityFeedCurrent()
469+
if (resetShareController) {
470+
shareSheetController.reset()
471+
}
472+
},
473+
onError = {
474+
cancelSend()
475+
TopBarManager.showMessage(
476+
title = resources.getString(R.string.error_title_failedToCreateGiftCard),
477+
message = resources.getString(R.string.error_description_failedToCreateGiftCard)
478+
)
479+
}
480+
)
376481
}
377482

378483
override fun onCodeScan(code: ScannableKikCode) {

ui/components/src/main/kotlin/com/getcode/ui/components/bars/BottomBarContainer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ fun BottomBarView(
231231
modifier = Modifier
232232
.fillMaxWidth()
233233
.rememberedClickable {
234-
onClose(false)
234+
onClose(true)
235235
}
236236
.padding(vertical = CodeTheme.dimens.grid.x3),
237237
style = CodeTheme.typography.textMedium,

0 commit comments

Comments
 (0)