diff --git a/feature_assets_impl/build.gradle.kts b/feature_assets_impl/build.gradle.kts index e64e090ee..9f686b6bd 100644 --- a/feature_assets_impl/build.gradle.kts +++ b/feature_assets_impl/build.gradle.kts @@ -78,6 +78,7 @@ dependencies { implementation(project(":feature_account_api")) implementation(project(":sorasubstrate")) implementation(project(":feature_main_api")) + implementation(project(":feature_sora_card_api")) implementation(project(":feature_blockexplorer_api")) implementation(libs.xsubstrateDep) diff --git a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/assetdetails/AssetDetailsFragment.kt b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/assetdetails/AssetDetailsFragment.kt index 652f03230..b3a56b042 100644 --- a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/assetdetails/AssetDetailsFragment.kt +++ b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/assetdetails/AssetDetailsFragment.kt @@ -54,6 +54,7 @@ import jp.co.soramitsu.androidfoundation.fragment.CustomViewModelFactory import jp.co.soramitsu.common.base.SoraBaseFragment import jp.co.soramitsu.common.base.theOnlyRoute import jp.co.soramitsu.common.domain.BottomBarController +import jp.co.soramitsu.oauth.base.sdk.contract.SoraCardContract import jp.co.soramitsu.ui_core.resources.Dimens @AndroidEntryPoint @@ -71,6 +72,10 @@ class AssetDetailsFragment : SoraBaseFragment() { } } + private val soraCardSignIn = registerForActivityResult( + SoraCardContract() + ) { } + @Inject lateinit var vmf: AssetDetailsViewModel.AssetDetailsViewModelFactory @@ -125,5 +130,8 @@ class AssetDetailsFragment : SoraBaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) (activity as BottomBarController).hideBottomBar() + viewModel.launchSoraCardSignIn.observe { contract -> + soraCardSignIn.launch(contract) + } } } diff --git a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/assetdetails/AssetDetailsViewModel.kt b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/assetdetails/AssetDetailsViewModel.kt index 0e2c7aa76..ded9587a9 100644 --- a/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/assetdetails/AssetDetailsViewModel.kt +++ b/feature_assets_impl/src/main/java/jp/co/soramitsu/feature_assets_impl/presentation/screens/assetdetails/AssetDetailsViewModel.kt @@ -35,11 +35,13 @@ package jp.co.soramitsu.feature_assets_impl.presentation.screens.assetdetails import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import java.math.BigDecimal +import jp.co.soramitsu.androidfoundation.fragment.SingleLiveEvent import jp.co.soramitsu.androidfoundation.fragment.trigger import jp.co.soramitsu.androidfoundation.phone.BasicClipboardManager import jp.co.soramitsu.androidfoundation.resource.ResourceManager @@ -68,7 +70,9 @@ import jp.co.soramitsu.feature_blockexplorer_api.data.SoraConfigManager import jp.co.soramitsu.feature_blockexplorer_api.domain.TransactionHistoryHandler import jp.co.soramitsu.feature_polkaswap_api.domain.interfaces.PoolsInteractor import jp.co.soramitsu.feature_polkaswap_api.launcher.PolkaswapRouter +import jp.co.soramitsu.feature_sora_card_api.util.createSoraCardGateHubContract import jp.co.soramitsu.feature_wallet_api.launcher.WalletRouter +import jp.co.soramitsu.oauth.base.sdk.contract.SoraCardContractData import jp.co.soramitsu.sora.substrate.runtime.SubstrateOptionsProvider import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest @@ -99,6 +103,9 @@ class AssetDetailsViewModel @AssistedInject constructor( private const val TX_HISTORY_COUNT = 5 } + private val _launchSoraCardSignIn = SingleLiveEvent() + val launchSoraCardSignIn: LiveData = _launchSoraCardSignIn + internal var state by mutableStateOf(AssetCardState(true, emptyAssetCardState)) private set @@ -277,6 +284,6 @@ class AssetDetailsViewModel @AssistedInject constructor( } fun onBuyCrypto() { - assetsRouter.showBuyCrypto() + _launchSoraCardSignIn.value = createSoraCardGateHubContract() } } diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreFragment.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreFragment.kt index 5a46a36a8..05ee6d415 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreFragment.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreFragment.kt @@ -145,7 +145,7 @@ class ExploreFragment : SoraBaseFragment() { ) } } else { - if (state.assets != null && state.farms.isEmpty() && state.pools.isEmpty()) { + if ((state.ecoSystemTokensState == null || state.ecoSystemTokensState.topTokens.isEmpty()) && state.farms.isEmpty() && state.pools.isEmpty()) { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center @@ -160,7 +160,7 @@ class ExploreFragment : SoraBaseFragment() { Column { val listState1 = rememberLazyListState() LazyColumn(state = listState1) { - if (state.assets != null) { + if (state.ecoSystemTokensState != null) { item { Text( modifier = Modifier.padding(start = Dimens.x3, bottom = Dimens.x2), @@ -172,12 +172,12 @@ class ExploreFragment : SoraBaseFragment() { } items( - count = state.assets.topTokens.size, + count = state.ecoSystemTokensState.topTokens.size, ) { position -> AssetItemEnumerated( modifier = Modifier.padding(vertical = Dimens.x1), - assetState = state.assets.topTokens[position].second, - number = state.assets.topTokens[position].first, + assetState = state.ecoSystemTokensState.topTokens[position].second, + number = state.ecoSystemTokensState.topTokens[position].first, testTag = "AssetFilteredItem", onClick = viewModel::onTokenClicked, ) diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/model/ExploreScreenState.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreScreenState.kt similarity index 97% rename from feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/model/ExploreScreenState.kt rename to feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreScreenState.kt index 0e69c1a53..e9b7a9907 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/model/ExploreScreenState.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreScreenState.kt @@ -30,7 +30,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jp.co.soramitsu.feature_ecosystem_impl.presentation.explore.model +package jp.co.soramitsu.feature_ecosystem_impl.presentation.explore import jp.co.soramitsu.common_wallet.presentation.compose.BasicFarmListItemState import jp.co.soramitsu.common_wallet.presentation.compose.BasicPoolListItemState @@ -38,7 +38,7 @@ import jp.co.soramitsu.feature_ecosystem_impl.presentation.EcoSystemTokensState internal data class ExploreScreenState( val isSearching: Boolean = false, - val assets: EcoSystemTokensState? = null, + val ecoSystemTokensState: EcoSystemTokensState? = null, val pools: List = emptyList(), val farms: List = emptyList(), val isLoading: Boolean = false, diff --git a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreViewModel.kt b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreViewModel.kt index dea113933..439687c1d 100644 --- a/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreViewModel.kt +++ b/feature_ecosystem_impl/src/main/java/jp/co/soramitsu/feature_ecosystem_impl/presentation/explore/ExploreViewModel.kt @@ -57,7 +57,6 @@ import jp.co.soramitsu.feature_ecosystem_impl.domain.EcoSystemMapper import jp.co.soramitsu.feature_ecosystem_impl.domain.EcoSystemTokens import jp.co.soramitsu.feature_ecosystem_impl.domain.EcoSystemTokensInteractor import jp.co.soramitsu.feature_ecosystem_impl.presentation.EcoSystemTokensState -import jp.co.soramitsu.feature_ecosystem_impl.presentation.explore.model.ExploreScreenState import jp.co.soramitsu.feature_polkaswap_api.domain.interfaces.PoolsInteractor import jp.co.soramitsu.feature_polkaswap_api.launcher.PolkaswapRouter import jp.co.soramitsu.sora.substrate.runtime.SubstrateOptionsProvider @@ -132,7 +131,7 @@ class ExploreViewModel @Inject constructor( _state.value = state.value.copy( isLoading = false, pools = pools, - assets = assets, + ecoSystemTokensState = assets, farms = farms, ) } @@ -152,7 +151,7 @@ class ExploreViewModel @Inject constructor( val mapped = ecoSystemMapper.mapEcoSystemTokens(EcoSystemTokens(tokensFiltered)) val mappedEnumerated = mapped.map { - val indexInAll = positions.get(it.second.tokenId).orEmpty() + val indexInAll = positions[it.second.tokenId].orEmpty() indexInAll to it.second } diff --git a/feature_ecosystem_impl/src/test/java/jp/co/soramitsu/feature_ecosystem_impl/explore/ExploreViewModelTest.kt b/feature_ecosystem_impl/src/test/java/jp/co/soramitsu/feature_ecosystem_impl/explore/ExploreViewModelTest.kt index 5f03064a9..182e000ab 100644 --- a/feature_ecosystem_impl/src/test/java/jp/co/soramitsu/feature_ecosystem_impl/explore/ExploreViewModelTest.kt +++ b/feature_ecosystem_impl/src/test/java/jp/co/soramitsu/feature_ecosystem_impl/explore/ExploreViewModelTest.kt @@ -33,22 +33,31 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package jp.co.soramitsu.feature_ecosystem_impl.explore import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import io.mockk.coEvery import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.junit4.MockKRule import io.mockk.verify import jp.co.soramitsu.androidfoundation.resource.ResourceManager import jp.co.soramitsu.common.util.NumbersFormatter +import jp.co.soramitsu.demeter.domain.DemeterFarmingBasicPool import jp.co.soramitsu.demeter.domain.DemeterFarmingInteractor import jp.co.soramitsu.feature_assets_api.presentation.AssetsRouter import jp.co.soramitsu.feature_ecosystem_impl.domain.EcoSystemMapper +import jp.co.soramitsu.feature_ecosystem_impl.domain.EcoSystemToken +import jp.co.soramitsu.feature_ecosystem_impl.domain.EcoSystemTokens import jp.co.soramitsu.feature_ecosystem_impl.domain.EcoSystemTokensInteractor import jp.co.soramitsu.feature_ecosystem_impl.presentation.explore.ExploreViewModel import jp.co.soramitsu.feature_polkaswap_api.domain.interfaces.PoolsInteractor import jp.co.soramitsu.feature_polkaswap_api.launcher.PolkaswapRouter +import jp.co.soramitsu.test_data.PolkaswapTestData.BASIC_POOL_DATA +import jp.co.soramitsu.test_data.TestTokens import jp.co.soramitsu.test_shared.MainCoroutineRule import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Rule import org.junit.Test @@ -91,18 +100,49 @@ class ExploreViewModelTest { @MockK private lateinit var assetsRouter: AssetsRouter - private lateinit var discoverViewModel: ExploreViewModel + private lateinit var exploreViewModel: ExploreViewModel @Before fun setUp() = runTest { every { assetsRouter.showAssetDetails(any()) } returns Unit every { resourceManager.getString(any()) } returns "" - discoverViewModel = ExploreViewModel( + coEvery { ecoSystemTokensInteractor.getTokensWithTvl() } returns EcoSystemTokens( + tokens = listOf( + EcoSystemToken( + token = TestTokens.xorToken, + liquidityFiat = 12.4, + ), + EcoSystemToken( + token = TestTokens.valToken, + liquidityFiat = 122.4, + ), + EcoSystemToken( + token = TestTokens.kxorToken, + liquidityFiat = 2.4, + ), + EcoSystemToken( + token = TestTokens.pswapToken, + liquidityFiat = 22.3, + ), + ), + ) + coEvery { poolsInteractor.getBasicPools() } returns listOf(BASIC_POOL_DATA) + coEvery { demeterFarmingInteractor.getFarmedBasicPools() } returns listOf( + DemeterFarmingBasicPool( + tokenBase = TestTokens.pswapToken, + tokenTarget = TestTokens.xorToken, + tokenReward = TestTokens.valToken, + apr = 1.2, + tvl = 123445.toBigDecimal(), + fee = 4.5, + ) + ) + exploreViewModel = ExploreViewModel( resourceManager, demeterFarmingInteractor, poolsInteractor, ecoSystemTokensInteractor, - ecoSystemMapper, + EcoSystemMapper(NumbersFormatter()), polkaswapRouter, assetsRouter, numbersFormatter @@ -111,7 +151,17 @@ class ExploreViewModelTest { @Test fun test() = runTest { - discoverViewModel.onTokenClicked("0x00") + exploreViewModel.onTokenClicked("0x00") verify { assetsRouter.showAssetDetails("0x00") } } + + @Test + fun `explore search tokens test 01`() = runTest { + advanceUntilIdle() + exploreViewModel.onToolbarSearch("kxo") + advanceUntilIdle() + val ts = exploreViewModel.state.value.ecoSystemTokensState + assertNotNull(ts) + assertEquals(1, ts!!.topTokens.size) + } } diff --git a/feature_main_impl/src/main/java/jp/co/soramitsu/feature_main_impl/presentation/profile/ProfileScreen.kt b/feature_main_impl/src/main/java/jp/co/soramitsu/feature_main_impl/presentation/profile/ProfileScreen.kt index dd939ca94..439e20f53 100644 --- a/feature_main_impl/src/main/java/jp/co/soramitsu/feature_main_impl/presentation/profile/ProfileScreen.kt +++ b/feature_main_impl/src/main/java/jp/co/soramitsu/feature_main_impl/presentation/profile/ProfileScreen.kt @@ -85,15 +85,15 @@ internal fun ProfileItems( icon = R.drawable.ic_buy_crypto, onClick = onSoraCardClick, ) -// CategoryItem( -// modifier = Modifier -// .testTagAsId("BuyXor") -// .padding(top = Dimens.x2), -// title = stringResource(id = R.string.buy_crypto_buy_xor_with_fiat_title), -// subtitle = stringResource(id = R.string.buy_crypto_buy_xor_with_fiat_subtitle), -// icon = R.drawable.ic_settings_buy_crypto, -// onClick = onBuyCrypto, -// ) + CategoryItem( + modifier = Modifier + .testTagAsId("BuyXor") + .padding(top = Dimens.x2), + title = stringResource(id = R.string.buy_crypto_buy_xor_with_fiat_title), + subtitle = stringResource(id = R.string.buy_crypto_buy_xor_with_fiat_subtitle), + icon = R.drawable.ic_settings_buy_crypto, + onClick = onBuyCrypto, + ) } CategoryItem( modifier = Modifier diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 97f0df3d8..5a491e592 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.4.1" +agp = "8.5.0" kotlin = "1.9.24" appcompat = "1.6.1" coroutines = "1.8.1" @@ -41,6 +41,7 @@ timber = "5.0.1" ktor = "2.3.1" soracard = "1.1.11" xnetworking = "0.2.9" +xnetworkingS = "1.0.1" xsubstrate = "1.2.4" uicore = "0.2.32" xbackup = "1.2.1" @@ -90,6 +91,7 @@ lazySodiumDep = { module = "com.goterl:lazysodium-android", version.ref = "lazyS jnaDep = { module = "net.java.dev.jna:jna", version.ref = "jna" } ktorWebSocketDep = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor" } soraCardDep = { module = "jp.co.soramitsu:android-sora-card", version.ref = "soracard" } +xnetworkingSDep = { module = "jp.co.soramitsu.xnetworking:lib-android", version.ref = "xnetworkingS" } xnetworkingDep = { module = "jp.co.soramitsu.xnetworking:basic-android", version.ref = "xnetworking" } xnetworkingSoraWalletDep = { module = "jp.co.soramitsu.xnetworking:sorawallet-android", version.ref = "xnetworking" } xsubstrateDep = { module = "jp.co.soramitsu:xsubstrate", version.ref = "xsubstrate" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c32cb774b..4b792ab3e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Jan 13 13:13:48 MSK 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/test_data/src/main/java/jp/co/soramitsu/test_data/Tokens.kt b/test_data/src/main/java/jp/co/soramitsu/test_data/Tokens.kt index ad1e6371c..c7780ebea 100644 --- a/test_data/src/main/java/jp/co/soramitsu/test_data/Tokens.kt +++ b/test_data/src/main/java/jp/co/soramitsu/test_data/Tokens.kt @@ -36,6 +36,18 @@ import jp.co.soramitsu.common.domain.Token object TestTokens { + val kxorToken = Token( + "0x02000e0000000000000000000000000000000000000000000000000000000000", + "Kensetsu xor token", + "KXOR", + 18, + true, + null, + null, + null, + null, + ) + val xorToken = Token( "0x0200000000000000000000000000000000000000000000000000000000000000", "Sora token",