Skip to content

Commit

Permalink
Add institution icon to account picker
Browse files Browse the repository at this point in the history
This also combines the `loadingContent` and `loadedContent` methods to fix an issue where the institution icon was flashing.
  • Loading branch information
tillh-stripe committed May 16, 2024
1 parent 6ecb6b5 commit 2cb49ed
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ internal class AccountPickerPreviewParameterProvider :
)

private fun multiSelect() = AccountPickerState(
institution = Success(
FinancialConnectionsInstitution(
id = "1",
name = "Institution 1",
url = "Institution 1 url",
featured = false,
featuredOrder = null,
icon = Image(default = ""),
logo = null,
mobileHandoffCapable = false
)
),
payload = Success(
AccountPickerState.Payload(
skipAccountSelection = false,
Expand All @@ -73,6 +85,18 @@ internal class AccountPickerPreviewParameterProvider :
)

private fun singleSelect() = AccountPickerState(
institution = Success(
FinancialConnectionsInstitution(
id = "1",
name = "Institution 1",
url = "Institution 1 url",
featured = false,
featuredOrder = null,
icon = Image(default = ""),
logo = null,
mobileHandoffCapable = false
)
),
payload = Success(
AccountPickerState.Payload(
skipAccountSelection = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyListState
Expand All @@ -34,12 +35,14 @@ import com.stripe.android.financialconnections.features.accountpicker.AccountPic
import com.stripe.android.financialconnections.features.accountpicker.AccountPickerState.SelectionMode
import com.stripe.android.financialconnections.features.accountpicker.AccountPickerState.ViewEffect.OpenUrl
import com.stripe.android.financialconnections.features.common.AccountItem
import com.stripe.android.financialconnections.features.common.InstitutionIcon
import com.stripe.android.financialconnections.features.common.LoadingShimmerEffect
import com.stripe.android.financialconnections.features.common.MerchantDataAccessModel
import com.stripe.android.financialconnections.features.common.MerchantDataAccessText
import com.stripe.android.financialconnections.features.common.NoAccountsAvailableErrorContent
import com.stripe.android.financialconnections.features.common.NoSupportedPaymentMethodTypeAccountsErrorContent
import com.stripe.android.financialconnections.features.common.UnclassifiedErrorContent
import com.stripe.android.financialconnections.model.FinancialConnectionsInstitution
import com.stripe.android.financialconnections.model.PartnerAccount
import com.stripe.android.financialconnections.presentation.Async
import com.stripe.android.financialconnections.presentation.Async.Fail
Expand Down Expand Up @@ -140,85 +143,92 @@ private fun AccountPickerLoaded(
onClickableTextClick: (String) -> Unit,
onSubmit: () -> Unit
) {
val displayablePayload = payload()?.takeIf { it.shouldSkipPane.not() }

LazyLayout(
lazyListState = lazyListState,
verticalArrangement = Arrangement.spacedBy(16.dp),
loading = payload is Loading,
showPillOnSlowLoad = true,
body = {
payload()
?.takeIf { it.shouldSkipPane.not() }
?.let {
loadedContent(
payload = it,
state = state,
onAccountClicked = onAccountClicked
)
} ?: run { loadingContent() }
accountPickerContent(
institution = state.institution(),
payload = displayablePayload,
selectedIds = state.selectedIds,
onAccountClicked = onAccountClicked,
)
},
footer = {
payload()
?.takeIf { it.shouldSkipPane.not() }
?.let {
Footer(
merchantDataAccessModel = it.merchantDataAccess,
onClickableTextClick = onClickableTextClick,
submitEnabled = state.submitEnabled,
submitLoading = state.submitLoading,
onSubmit = onSubmit,
selectedIds = state.selectedIds
)
}
displayablePayload?.let {
Footer(
merchantDataAccessModel = it.merchantDataAccess,
onClickableTextClick = onClickableTextClick,
submitEnabled = state.submitEnabled,
submitLoading = state.submitLoading,
onSubmit = onSubmit,
selectedIds = state.selectedIds
)
}
}

)
}

private fun LazyListScope.loadedContent(
payload: AccountPickerState.Payload,
state: AccountPickerState,
onAccountClicked: (PartnerAccount) -> Unit
private fun LazyListScope.accountPickerContent(
institution: FinancialConnectionsInstitution?,
payload: AccountPickerState.Payload?,
selectedIds: Set<String>,
onAccountClicked: (PartnerAccount) -> Unit,
) {
item {
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(
when (payload.selectionMode) {
SelectionMode.Single -> R.string.stripe_account_picker_singleselect_account
SelectionMode.Multiple -> R.string.stripe_account_picker_multiselect_account
}
),
style = FinancialConnectionsTheme.typography.headingXLarge
)
}
items(payload.accounts, key = { it.id }) { account ->
AccountItem(
selected = state.selectedIds.contains(account.id),
showInstitutionIcon = false,
onAccountClicked = onAccountClicked,
account = account,
item("icon") {
InstitutionIcon(
institutionIcon = institution?.icon?.default,
modifier = Modifier.padding(top = 16.dp),
disablePlaceholder = true,
)
}
}

private fun LazyListScope.loadingContent() {
item {
Text(
modifier = Modifier.fillMaxWidth(),
text = "Retrieving accounts",
style = FinancialConnectionsTheme.typography.headingXLarge
)
item("header") {
if (payload != null) {
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(
when (payload.selectionMode) {
SelectionMode.Single -> R.string.stripe_account_picker_singleselect_account
SelectionMode.Multiple -> R.string.stripe_account_picker_multiselect_account
}
),
style = FinancialConnectionsTheme.typography.headingXLarge
)
} else {
Text(
modifier = Modifier.fillMaxWidth(),
text = "Retrieving accounts",
style = FinancialConnectionsTheme.typography.headingXLarge
)
}
}
items(3) {
LoadingShimmerEffect {
Box(
modifier = Modifier
.fillMaxWidth()
.height(72.dp)
.clip(RoundedCornerShape(16.dp))
.background(it)

if (payload != null) {
items(payload.accounts, key = { it.id }) { account ->
AccountItem(
selected = selectedIds.contains(account.id),
showInstitutionIcon = false,
onAccountClicked = onAccountClicked,
account = account,
)
}
} else {
items(3) {
LoadingShimmerEffect {
Box(
modifier = Modifier
.fillMaxWidth()
.height(72.dp)
.clip(RoundedCornerShape(16.dp))
.background(it)
)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.stripe.android.financialconnections.features.common.isDataFlow
import com.stripe.android.financialconnections.features.notice.NoticeSheetState.NoticeSheetContent.DataAccess
import com.stripe.android.financialconnections.features.notice.PresentNoticeSheet
import com.stripe.android.financialconnections.model.DataAccessNotice
import com.stripe.android.financialconnections.model.FinancialConnectionsInstitution
import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane
import com.stripe.android.financialconnections.model.PartnerAccount
import com.stripe.android.financialconnections.model.PartnerAccountsList
Expand Down Expand Up @@ -72,6 +73,7 @@ internal class AccountPickerViewModel @AssistedInject constructor(
init {
logErrors()
onPayloadLoaded()
loadInstitution()
loadAccounts()
}

Expand All @@ -83,6 +85,16 @@ internal class AccountPickerViewModel @AssistedInject constructor(
)
}

private fun loadInstitution() {
suspend {
val sync = getOrFetchSync()
val manifest = sync.manifest
requireNotNull(manifest.activeInstitution)
}.execute {
copy(institution = it)
}
}

private fun loadAccounts() {
suspend {
val state = stateFlow.value
Expand Down Expand Up @@ -376,6 +388,7 @@ internal class AccountPickerViewModel @AssistedInject constructor(
}

internal data class AccountPickerState(
val institution: Async<FinancialConnectionsInstitution> = Uninitialized,
val payload: Async<Payload> = Uninitialized,
val canRetry: Boolean = true,
val selectAccounts: Async<PartnerAccountsList> = Uninitialized,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,34 @@ import com.stripe.android.financialconnections.ui.theme.FinancialConnectionsThem
import com.stripe.android.uicore.image.StripeImage

@Composable
internal fun InstitutionIcon(institutionIcon: String?) {
internal fun InstitutionIcon(
institutionIcon: String?,
modifier: Modifier = Modifier,
disablePlaceholder: Boolean = false,
) {
val previewMode = LocalInspectionMode.current
val iconModifier = Modifier
val iconModifier = modifier
.size(56.dp)
.shadow(1.dp, RoundedCornerShape(12.dp), clip = true)

when {
previewMode || institutionIcon == null -> InstitutionPlaceholder(iconModifier)
else -> StripeImage(
url = institutionIcon,
imageLoader = LocalImageLoader.current,
contentDescription = null,
modifier = iconModifier,
contentScale = ContentScale.Crop,
loadingContent = { Box(modifier = iconModifier.background(colors.backgroundOffset)) },
errorContent = { InstitutionPlaceholder(iconModifier) }
)
institutionIcon == null && disablePlaceholder -> {
Box(modifier = iconModifier.background(colors.backgroundOffset))
}
previewMode || institutionIcon == null -> {
InstitutionPlaceholder(iconModifier)
}
else -> {
StripeImage(
url = institutionIcon,
imageLoader = LocalImageLoader.current,
contentDescription = null,
modifier = iconModifier,
contentScale = ContentScale.Crop,
loadingContent = { Box(modifier = iconModifier.background(colors.backgroundOffset)) },
errorContent = { InstitutionPlaceholder(iconModifier) }
)
}
}
}

Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2cb49ed

Please sign in to comment.