Skip to content

Commit

Permalink
feat(superapp): AND-6173 Add ctas for dashboard (#4094)
Browse files Browse the repository at this point in the history
* add buttons

* add buttons and fix couple of bugs

* make buttons flow+eligibility

* button clicks

* button clicks

* button clicks

* button clicks

* button clicks

* buy

* ktlint

* fix tests
  • Loading branch information
antonis-bc committed Nov 11, 2022
1 parent 073d3b8 commit 1abd620
Show file tree
Hide file tree
Showing 24 changed files with 502 additions and 14 deletions.
@@ -1,6 +1,7 @@
package com.blockchain.koin.modules

import android.content.Context
import androidx.activity.ComponentActivity
import androidx.biometric.BiometricManager
import com.blockchain.api.ConnectionApi
import com.blockchain.api.interceptors.SessionInfo
Expand All @@ -18,6 +19,7 @@ import com.blockchain.core.auth.metadata.WalletCredentialsMetadataUpdater
import com.blockchain.core.utils.SSLVerifyUtil
import com.blockchain.enviroment.Environment
import com.blockchain.enviroment.EnvironmentConfig
import com.blockchain.home.presentation.navigation.AssetActionsNavigation
import com.blockchain.keyboard.InputKeyboard
import com.blockchain.koin.applicationScope
import com.blockchain.koin.ars
Expand Down Expand Up @@ -136,6 +138,7 @@ import piuk.blockchain.android.ui.customviews.inputview.InputAmountKeyboard
import piuk.blockchain.android.ui.dataremediation.QuestionnaireModel
import piuk.blockchain.android.ui.dataremediation.QuestionnaireStateMachine
import piuk.blockchain.android.ui.home.ActionsSheetViewModel
import piuk.blockchain.android.ui.home.AssetActionsNavigationImpl
import piuk.blockchain.android.ui.home.CredentialsWiper
import piuk.blockchain.android.ui.kyc.email.entry.EmailVerificationModel
import piuk.blockchain.android.ui.kyc.settings.KycStatusHelper
Expand Down Expand Up @@ -241,6 +244,10 @@ val applicationModule = module {
BankPartnerCallbackProviderImpl()
}.bind(BankPartnerCallbackProvider::class)

scoped { (activity: ComponentActivity) -> AssetActionsNavigationImpl(activity = activity) }.bind(
AssetActionsNavigation::class
)

scoped {
CredentialsWiper(
appUtil = get(),
Expand Down
Expand Up @@ -15,6 +15,7 @@ import com.blockchain.componentlib.viewextensions.visible
import piuk.blockchain.android.R
import piuk.blockchain.android.databinding.ActivityActionBinding
import piuk.blockchain.android.ui.base.showFragment
import piuk.blockchain.android.ui.brokerage.BuySellFragment
import piuk.blockchain.android.ui.swap.SwapFragment
import piuk.blockchain.android.ui.transfer.receive.ReceiveFragment
import piuk.blockchain.android.ui.transfer.send.TransferSendFragment
Expand Down Expand Up @@ -68,6 +69,17 @@ class ActionActivity : BlockchainActivity(), SlidingModalBottomDialog.Host, Upse
updateToolbarTitle(getString(R.string.toolbar_receive))
ReceiveFragment.newInstance(cryptoTicker = cryptoTicker)
}
AssetAction.Sell,
AssetAction.Buy -> {
updateToolbarTitle(getString(R.string.buy_and_sell))
BuySellFragment.newInstance(
viewType = if (action == AssetAction.Sell) {
BuySellFragment.BuySellViewType.TYPE_SELL
} else {
BuySellFragment.BuySellViewType.TYPE_BUY
}
)
}
else -> {
throw IllegalStateException("$action is not supported")
}
Expand Down
@@ -0,0 +1,37 @@
package piuk.blockchain.android.ui.home

import androidx.activity.ComponentActivity
import com.blockchain.coincore.AssetAction
import com.blockchain.home.presentation.navigation.AssetActionsNavigation
import org.koin.androidx.compose.get
import piuk.blockchain.android.campaign.CampaignType
import piuk.blockchain.android.ui.kyc.navhost.KycNavHostActivity

class AssetActionsNavigationImpl(private val activity: ComponentActivity?) : AssetActionsNavigation {
private val actionsResultContract =
activity?.registerForActivityResult(ActionActivity.BlockchainActivityResultContract()) {
when (it) {
ActionActivity.ActivityResult.StartKyc -> launchKyc()
is ActionActivity.ActivityResult.StartReceive -> launchReceive()
ActionActivity.ActivityResult.StartBuyIntro -> launchBuy()
null -> {
}
}
}

private fun launchBuy() {
actionsResultContract!!.launch(ActionActivity.ActivityArgs(action = AssetAction.Buy, null))
}

private fun launchReceive() {
actionsResultContract!!.launch(ActionActivity.ActivityArgs(AssetAction.Receive))
}

private fun launchKyc() {
KycNavHostActivity.start(activity!!, campaignType = CampaignType.None)
}

override fun navigate(assetAction: AssetAction) {
return actionsResultContract!!.launch(ActionActivity.ActivityArgs(action = assetAction, null))
}
}
Expand Up @@ -113,7 +113,7 @@ private fun PreviewDefiBuyCrypto() {
AppTheme {
BottomItem(
sheetAction = SheetAction(
icon = R.drawable.ic_sheet_menu_swap,
icon = R.drawable.ic_cta_swap,
title = R.string.common_buy,
subtitle = R.string.common_buy,
action = AssetAction.Buy,
Expand Down
Expand Up @@ -110,7 +110,7 @@ abstract class PasswordAuthPresenter<T : PasswordAuthView> : MvpPresenter<T>() {
}

private fun getSessionId(guid: String): Observable<String> =
sessionId?.let { Observable.just(it) } ?: authDataManager.getSessionId(guid)
sessionId?.takeIf { it.isNotEmpty() }?.let { Observable.just(it) } ?: authDataManager.getSessionId(guid)

@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
fun verifyPassword(password: String, guid: String) {
Expand Down
8 changes: 8 additions & 0 deletions app/src/test/java/com/blockchain/koin/KoinGraphTest.kt
@@ -1,11 +1,14 @@
package com.blockchain.koin

import org.junit.After
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.koin.core.context.stopKoin
import org.koin.test.KoinTest
import org.koin.test.check.checkModules
import org.koin.test.mock.MockProviderRule
import org.mockito.Mockito
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import piuk.blockchain.android.BlockchainTestApplication
Expand All @@ -14,6 +17,11 @@ import piuk.blockchain.android.BlockchainTestApplication
@RunWith(RobolectricTestRunner::class)
class KoinGraphTest : KoinTest {

@get:Rule
val mockProvider = MockProviderRule.create { clazz ->
Mockito.mock(clazz.java)
}

@After
fun cleanup() {
stopKoin()
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/java/Dependencies.kt
Expand Up @@ -17,7 +17,7 @@ object Versions {
const val kotlin = "1.7.0"

// Coroutines
const val coroutines = "1.5.2"
const val coroutines = "1.6.4"

// Kotlin Immutable Collections
const val immutableCollections = "0.3.5"
Expand Down
Expand Up @@ -21,6 +21,7 @@ import androidx.constraintlayout.compose.Dimension
import com.blockchain.chrome.ChromeBackgroundColors
import com.blockchain.chrome.backgroundColors
import com.blockchain.componentlib.theme.AppTheme
import com.blockchain.koin.superAppModeService
import com.blockchain.walletmode.WalletModeService
import org.koin.androidx.compose.get

Expand All @@ -44,7 +45,9 @@ import org.koin.androidx.compose.get
*/
@Composable
fun MultiAppSingleScreen(
backgroundColors: ChromeBackgroundColors = get<WalletModeService>().enabledWalletMode().backgroundColors(),
backgroundColors: ChromeBackgroundColors = get<WalletModeService>(
superAppModeService
).enabledWalletMode().backgroundColors(),
content: @Composable () -> Unit
) {
val statusBarHeight = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
Expand Down
Expand Up @@ -9,12 +9,21 @@ import androidx.core.view.WindowCompat
import androidx.navigation.compose.rememberNavController
import com.blockchain.chrome.navigation.MultiAppNavHost
import com.blockchain.commonarch.presentation.base.BlockchainActivity
import com.blockchain.home.presentation.navigation.AssetActionsNavigation
import com.blockchain.koin.payloadScope
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import org.koin.core.parameter.parametersOf

class MultiAppActivity : BlockchainActivity() {
override val alwaysDisableScreenshots: Boolean
get() = false

private val assetActionsNavigation: AssetActionsNavigation = payloadScope.get {
parametersOf(
this
)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

Expand All @@ -25,7 +34,7 @@ class MultiAppActivity : BlockchainActivity() {
val systemUiController = rememberSystemUiController()
systemUiController.setStatusBarColor(Color.Transparent)

MultiAppNavHost(navController = rememberNavController())
MultiAppNavHost(navController = rememberNavController(), assetActionsNavigation = assetActionsNavigation)
}
}

Expand Down
Expand Up @@ -41,7 +41,6 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.Velocity
Expand All @@ -63,6 +62,7 @@ import com.blockchain.chrome.toolbar.ScrollState
import com.blockchain.commonarch.presentation.mvi_v2.ModelConfigArgs
import com.blockchain.componentlib.theme.AppTheme
import com.blockchain.data.DataResource
import com.blockchain.home.presentation.navigation.AssetActionsNavigation
import com.blockchain.koin.payloadScope
import com.blockchain.walletmode.WalletMode
import kotlin.math.min
Expand All @@ -84,6 +84,7 @@ private fun rememberToolbarState(): CollapsingToolbarState {
fun MultiAppChrome(
viewModel: MultiAppViewModel = getViewModel(scope = payloadScope),
openCryptoAssets: () -> Unit,
assetActionsNavigation: AssetActionsNavigation,
openActivity: () -> Unit
) {
DisposableEffect(key1 = viewModel) {
Expand Down Expand Up @@ -115,6 +116,7 @@ fun MultiAppChrome(
},
openCryptoAssets = openCryptoAssets,
openActivity = openActivity,
assetActionsNavigation = assetActionsNavigation,
onBalanceRevealed = {
viewModel.onIntent(MultiAppIntents.BalanceRevealed)
}
Expand All @@ -135,6 +137,7 @@ fun MultiAppChromeScreen(
bottomNavigationItems: List<ChromeBottomNavigationItem>,
onModeSelected: (WalletMode) -> Unit,
openCryptoAssets: () -> Unit,
assetActionsNavigation: AssetActionsNavigation,
openActivity: () -> Unit,
onBalanceRevealed: () -> Unit
) {
Expand Down Expand Up @@ -627,6 +630,7 @@ fun MultiAppChromeScreen(
},
openCryptoAssets = openCryptoAssets,
openActivity = openActivity,
assetActionsNavigation = assetActionsNavigation
)
}

Expand Down Expand Up @@ -686,7 +690,7 @@ fun MultiAppChromeScreen(
}
}

@Preview
/*@Preview
@Composable
fun PreviewMultiAppContainer() {
MultiAppChromeScreen(
Expand All @@ -707,4 +711,5 @@ fun PreviewMultiAppContainer() {
openActivity = {},
onBalanceRevealed = {}
)
}
}
*/
Expand Up @@ -11,12 +11,14 @@ import com.blockchain.chrome.composable.DemoScreen
import com.blockchain.componentlib.chrome.ChromeScreen
import com.blockchain.componentlib.chrome.ListStateInfo
import com.blockchain.home.presentation.dashboard.composable.HomeScreen
import com.blockchain.home.presentation.navigation.AssetActionsNavigation

@Composable
fun MultiAppBottomNavigationHost(
modifier: Modifier = Modifier,
navController: NavHostController,
enableRefresh: Boolean,
assetActionsNavigation: AssetActionsNavigation,
updateScrollInfo: (Pair<ChromeBottomNavigationItem, ListStateInfo>) -> Unit,
refreshStarted: () -> Unit,
refreshComplete: () -> Unit,
Expand All @@ -34,6 +36,7 @@ fun MultiAppBottomNavigationHost(
HomeScreen(
listState = listState,
openCryptoAssets = openCryptoAssets,
assetActionsNavigation = assetActionsNavigation,
openActivity = openActivity
)
},
Expand Down
Expand Up @@ -7,28 +7,31 @@ import androidx.navigation.compose.NavHost
import com.blockchain.chrome.composable.MultiAppChrome
import com.blockchain.commonarch.presentation.mvi_v2.compose.composable
import com.blockchain.commonarch.presentation.mvi_v2.compose.navigate
import com.blockchain.home.presentation.navigation.AssetActionsNavigation
import com.blockchain.home.presentation.navigation.HomeDestination
import com.blockchain.home.presentation.navigation.homeGraph

@Composable
fun MultiAppNavHost(
navController: NavHostController,
assetActionsNavigation: AssetActionsNavigation,
) {
NavHost(
navController = navController,
startDestination = ChromeDestination.Main.route
) {
// main chrome
chrome(navController)
chrome(navController, assetActionsNavigation)

// home screens
homeGraph()
}
}

private fun NavGraphBuilder.chrome(navController: NavHostController) {
private fun NavGraphBuilder.chrome(navController: NavHostController, assetActionsNavigation: AssetActionsNavigation) {
composable(navigationEvent = ChromeDestination.Main) {
MultiAppChrome(
assetActionsNavigation = assetActionsNavigation,
openCryptoAssets = {
navController.navigate(HomeDestination.CryptoAssets)
},
Expand Down
Expand Up @@ -24,6 +24,7 @@ import com.blockchain.core.kyc.domain.KycService
import com.blockchain.core.payload.PayloadDataManager
import com.blockchain.core.staking.domain.StakingService
import com.blockchain.data.DataResource
import com.blockchain.data.onErrorReturn
import com.blockchain.featureflag.FeatureFlag
import com.blockchain.logging.RemoteLogger
import com.blockchain.nabu.datamanagers.CustodialWalletManager
Expand Down Expand Up @@ -266,6 +267,8 @@ internal class DynamicAssetLoader(
balances.map {
get(it.currency)
}
}.onErrorReturn {
emptyList()
}.filterIsInstance<DataResource.Data<List<Asset>>>()

val enabledL1AssetsFlow = flow {
Expand Down
Expand Up @@ -31,6 +31,7 @@ import info.blockchain.balance.Money
import info.blockchain.balance.percentageDelta
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterIsInstance
Expand Down Expand Up @@ -216,7 +217,10 @@ class AssetsViewModel(
.flatMapLatest { accounts ->
val balances = accounts.data.map { account ->
account.balance.distinctUntilChanged()
.map { it to account }
.map { DataResource.Data(it) as DataResource<AccountBalance> to account }
.catch { t ->
emit(DataResource.Error(t as Exception) to account)
}
}.merge().onEach { (balance, account) ->
updateState { state ->
state.copy(
Expand Down Expand Up @@ -341,15 +345,15 @@ private fun List<DataResource<Money>>.sumAvailableBalances(): DataResource<Money

private fun DataResource<List<ModelAccount>>.withBalancedAccount(
account: SingleAccount,
balance: AccountBalance
balance: DataResource<AccountBalance>
): DataResource<List<ModelAccount>> {
return this.map { accounts ->
val oldAccount = accounts.first { it.singleAccount == account }
accounts.replace(
old = oldAccount,
new = oldAccount.copy(
balance = DataResource.Data(balance.total),
fiatBalance = DataResource.Data(balance.totalFiat)
balance = balance.map { it.total },
fiatBalance = balance.map { it.totalFiat }
)
)
}
Expand Down

0 comments on commit 1abd620

Please sign in to comment.