Updated on 2026-08-14
This commit is contained in:
commit
8e1f3cf37c
11 changed files with 118 additions and 101 deletions
|
|
@ -137,6 +137,8 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
cardSdkLifecycleObserver.onCreate(context = this)
|
||||
|
||||
bootstrapMainStateUpdates(application)
|
||||
|
||||
splashScreen.setKeepOnScreenCondition { isInitializing }
|
||||
|
|
@ -146,8 +148,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
|
||||
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
|
||||
|
||||
cardSdkLifecycleObserver.onCreate(context = this)
|
||||
|
||||
tangemSdkManager = injectedTangemSdkManager
|
||||
appStateHolder.tangemSdkManager = tangemSdkManager
|
||||
backupService = BackupService.init(cardSdkConfigRepository.sdk, this)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.blockchain.blockchains.cardano.CardanoUtils
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.common.flatMap
|
||||
|
|
@ -71,12 +72,22 @@ class DefaultCustomTokenInteractor(
|
|||
onSuccess: suspend (ScanResponse) -> Unit,
|
||||
) {
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencyList) }
|
||||
val derivationDataList = currencyList.mapNotNull { currency ->
|
||||
val curve = config.primaryCurve(currency.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currency) }
|
||||
}
|
||||
|
||||
val derivations = derivationDataList.associate(TokensMiddleware.DerivationData::derivations)
|
||||
val derivations = buildMap<ByteArrayKey, MutableList<DerivationPath>> {
|
||||
derivationDataList.forEach {
|
||||
val current = this[it.derivations.first]
|
||||
if (current != null) {
|
||||
current.addAll(it.derivations.second)
|
||||
current.distinct()
|
||||
} else {
|
||||
this[it.derivations.first] = it.derivations.second.toMutableList()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (derivations.isEmpty()) {
|
||||
onSuccess(scanResponse)
|
||||
return
|
||||
|
|
@ -110,24 +121,22 @@ class DefaultCustomTokenInteractor(
|
|||
private fun getDerivations(
|
||||
curve: EllipticCurve,
|
||||
scanResponse: ScanResponse,
|
||||
currencyList: List<Currency>,
|
||||
currency: Currency,
|
||||
): TokensMiddleware.DerivationData? {
|
||||
val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
|
||||
|
||||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
val supportedCurves = currency.blockchain.getSupportedCurves()
|
||||
val path = currency.blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
it.blockchain.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull { it.derivationPath }.map { DerivationPath(it) }
|
||||
val customPath = currency.derivationPath?.let {
|
||||
DerivationPath(it)
|
||||
}.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val bothCandidates = (manageTokensCandidates + customTokensCandidates).distinct().toMutableList()
|
||||
val bothCandidates = listOfNotNull(path, customPath).distinct().toMutableList()
|
||||
if (bothCandidates.isEmpty()) return null
|
||||
|
||||
currencyList.find { it is Currency.Blockchain && it.blockchain == Blockchain.Cardano }?.let { currency ->
|
||||
if (currency is Currency.Blockchain && currency.blockchain == Blockchain.Cardano) {
|
||||
currency.derivationPath?.let {
|
||||
bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,14 @@ internal class AppSettingsFragment : ComposeFragment(), StoreSubscriber<DetailsS
|
|||
AppSettingsViewModel(store, detailsFeatureToggles, appCurrencyRepository)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(R.transition.fade)
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
viewModel.checkBiometricsStatus(lifecycleScope)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
AppSettingsScreen(
|
||||
|
|
@ -46,12 +54,6 @@ internal class AppSettingsFragment : ComposeFragment(), StoreSubscriber<DetailsS
|
|||
)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel.checkBiometricsStatus(lifecycleScope)
|
||||
}
|
||||
|
||||
override fun TransitionInflater.inflateTransitions(): Boolean {
|
||||
enterTransition = inflateTransition(R.transition.fade)
|
||||
exitTransition = inflateTransition(R.transition.fade)
|
||||
|
|
|
|||
|
|
@ -105,10 +105,6 @@ internal class AppSettingsViewModel(
|
|||
onCheckedChange = ::onFlipToHideBalanceToggled,
|
||||
).let(::add)
|
||||
|
||||
itemsFactory.createSelectThemeModeButton(state.selectedThemeMode) {
|
||||
showThemeModeSelector(state.selectedThemeMode)
|
||||
}.let(::add)
|
||||
|
||||
if (state.darkThemeSwitchEnabled) {
|
||||
itemsFactory.createSelectThemeModeButton(state.selectedThemeMode) {
|
||||
showThemeModeSelector(state.selectedThemeMode)
|
||||
|
|
|
|||
|
|
@ -156,11 +156,22 @@ object TokensMiddleware {
|
|||
onSuccess: (ScanResponse) -> Unit,
|
||||
) {
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getLegacyDerivations(curve, scanResponse, currencyList) }
|
||||
val derivationDataList = currencyList.mapNotNull { currency ->
|
||||
val curve = config.primaryCurve(currency.blockchain)
|
||||
curve?.let { getLegacyDerivations(curve, scanResponse, currency) }
|
||||
}
|
||||
val derivations = derivationDataList.associate { it.derivations }
|
||||
val derivations = buildMap<ByteArrayKey, MutableList<DerivationPath>> {
|
||||
derivationDataList.forEach {
|
||||
val current = this[it.derivations.first]
|
||||
if (current != null) {
|
||||
current.addAll(it.derivations.second)
|
||||
current.distinct()
|
||||
} else {
|
||||
this[it.derivations.first] = it.derivations.second.toMutableList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (derivations.isEmpty()) {
|
||||
onSuccess(scanResponse)
|
||||
return
|
||||
|
|
@ -204,9 +215,9 @@ object TokensMiddleware {
|
|||
onSuccess: (ScanResponse) -> Unit,
|
||||
) {
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
config.primaryCurve(blockchain = Blockchain.fromId(it.network.id.value))
|
||||
?.let { curve -> getNewDerivations(curve, scanResponse, currencyList) }
|
||||
val derivationDataList = currencyList.mapNotNull { currency ->
|
||||
config.primaryCurve(blockchain = Blockchain.fromId(currency.network.id.value))
|
||||
?.let { curve -> getNewDerivations(curve, scanResponse, currency) }
|
||||
}
|
||||
val derivations = derivationDataList.associate(DerivationData::derivations)
|
||||
if (derivations.isEmpty()) {
|
||||
|
|
@ -249,24 +260,22 @@ object TokensMiddleware {
|
|||
private fun getLegacyDerivations(
|
||||
curve: EllipticCurve,
|
||||
scanResponse: ScanResponse,
|
||||
currencyList: List<Currency>,
|
||||
currency: Currency,
|
||||
): DerivationData? {
|
||||
val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
|
||||
|
||||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
val supportedCurves = currency.blockchain.getSupportedCurves()
|
||||
val path = currency.blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
it.blockchain.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull { it.derivationPath }.map { DerivationPath(it) }
|
||||
val customPath = currency.derivationPath?.let {
|
||||
DerivationPath(it)
|
||||
}.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val bothCandidates = (manageTokensCandidates + customTokensCandidates).distinct().toMutableList()
|
||||
val bothCandidates = listOfNotNull(path, customPath).distinct().toMutableList()
|
||||
if (bothCandidates.isEmpty()) return null
|
||||
|
||||
currencyList.find { it is Currency.Blockchain && it.blockchain == Blockchain.Cardano }?.let { currency ->
|
||||
if (currency is Currency.Blockchain && currency.blockchain == Blockchain.Cardano) {
|
||||
currency.derivationPath?.let {
|
||||
bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
|
||||
}
|
||||
|
|
@ -286,30 +295,27 @@ object TokensMiddleware {
|
|||
private fun getNewDerivations(
|
||||
curve: EllipticCurve,
|
||||
scanResponse: ScanResponse,
|
||||
currencyList: List<CryptoCurrency>,
|
||||
currency: CryptoCurrency,
|
||||
): DerivationData? {
|
||||
val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
|
||||
|
||||
val manageTokensCandidates = currencyList
|
||||
.map { Blockchain.fromId(it.network.id.value) }
|
||||
.distinct()
|
||||
.filter { it.getSupportedCurves().contains(curve) }
|
||||
.mapNotNull { it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle()) }
|
||||
val blockchain = Blockchain.fromId(currency.network.id.value)
|
||||
val supportedCurves = blockchain.getSupportedCurves()
|
||||
val path = blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val customTokensCandidates = currencyList
|
||||
.filter { Blockchain.fromId(it.network.id.value).getSupportedCurves().contains(curve) }
|
||||
.mapNotNull { it.network.derivationPath.value }
|
||||
.map(::DerivationPath)
|
||||
val customPath = currency.network.derivationPath.value?.let {
|
||||
DerivationPath(it)
|
||||
}.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val bothCandidates = (manageTokensCandidates + customTokensCandidates).distinct().toMutableList()
|
||||
val bothCandidates = listOfNotNull(path, customPath).distinct().toMutableList()
|
||||
if (bothCandidates.isEmpty()) return null
|
||||
|
||||
currencyList.find { it is CryptoCurrency.Coin && Blockchain.fromId(it.network.id.value) == Blockchain.Cardano }
|
||||
?.let { currency ->
|
||||
currency.network.derivationPath.value?.let {
|
||||
bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
|
||||
}
|
||||
if (currency is CryptoCurrency.Coin && blockchain == Blockchain.Cardano) {
|
||||
currency.network.derivationPath.value?.let {
|
||||
bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
|
||||
}
|
||||
}
|
||||
|
||||
val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
|
||||
val alreadyDerivedKeys: ExtendedPublicKeysMap =
|
||||
|
|
|
|||
|
|
@ -82,9 +82,6 @@ data class WalletState(
|
|||
get() = primaryWalletStore?.walletsData
|
||||
?.firstOrNull { it.currency !is Currency.Blockchain }
|
||||
|
||||
val shouldShowDetails: Boolean =
|
||||
primaryWalletData?.status !is WalletDataModel.Unreachable
|
||||
|
||||
fun getWalletManager(currency: Currency?): WalletManager? {
|
||||
if (currency?.blockchain == null) return null
|
||||
return getWalletStore(currency)?.walletManager
|
||||
|
|
|
|||
|
|
@ -189,9 +189,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber<W
|
|||
|
||||
walletView.onNewState(state)
|
||||
|
||||
if (!state.shouldShowDetails) {
|
||||
binding.toolbar.menu.removeItem(R.id.details_menu)
|
||||
} else if (binding.toolbar.menu.findItem(R.id.details_menu) == null) {
|
||||
if (binding.toolbar.menu.findItem(R.id.details_menu) == null) {
|
||||
binding.toolbar.inflateMenu(R.menu.menu_wallet)
|
||||
}
|
||||
|
||||
|
|
@ -327,6 +325,6 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber<W
|
|||
),
|
||||
)
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
if (store.state.walletState.shouldShowDetails) inflater.inflate(R.menu.menu_wallet, menu)
|
||||
inflater.inflate(R.menu.menu_wallet, menu)
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
|||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware
|
||||
import com.tangem.tap.scope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -97,11 +98,21 @@ class DerivationManagerImpl(
|
|||
onFailure: (Exception) -> Unit,
|
||||
) {
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencyList) }
|
||||
val derivationDataList = currencyList.mapNotNull { currency ->
|
||||
val curve = config.primaryCurve(currency.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currency) }
|
||||
}
|
||||
val derivations = buildMap<ByteArrayKey, MutableList<DerivationPath>> {
|
||||
derivationDataList.forEach {
|
||||
val current = this[it.derivations.first]
|
||||
if (current != null) {
|
||||
current.addAll(it.derivations.second)
|
||||
current.distinct()
|
||||
} else {
|
||||
this[it.derivations.first] = it.derivations.second.toMutableList()
|
||||
}
|
||||
}
|
||||
}
|
||||
val derivations = derivationDataList.associate { it.derivations }
|
||||
if (derivations.isEmpty()) {
|
||||
onSuccess(scanResponse)
|
||||
return
|
||||
|
|
@ -159,23 +170,29 @@ class DerivationManagerImpl(
|
|||
private fun getDerivations(
|
||||
curve: EllipticCurve,
|
||||
scanResponse: ScanResponse,
|
||||
currencyList: List<WalletModelCurrency>,
|
||||
): DerivationData? {
|
||||
currency: com.tangem.tap.features.wallet.models.Currency,
|
||||
): TokensMiddleware.DerivationData? {
|
||||
val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
|
||||
|
||||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
val supportedCurves = currency.blockchain.getSupportedCurves()
|
||||
val path = currency.blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
it.blockchain.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull { it.derivationPath }.map { DerivationPath(it) }
|
||||
val customPath = currency.derivationPath?.let {
|
||||
DerivationPath(it)
|
||||
}.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val bothCandidates = (manageTokensCandidates + customTokensCandidates).distinct().toMutableList()
|
||||
val bothCandidates = listOfNotNull(path, customPath).distinct().toMutableList()
|
||||
if (bothCandidates.isEmpty()) return null
|
||||
|
||||
if (currency is WalletModelCurrency.Blockchain &&
|
||||
currency.blockchain == Blockchain.Cardano
|
||||
) {
|
||||
currency.derivationPath?.let {
|
||||
bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
|
||||
}
|
||||
}
|
||||
|
||||
val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
|
||||
val alreadyDerivedKeys: ExtendedPublicKeysMap =
|
||||
scanResponse.derivedKeys[mapKeyOfWalletPublicKey] ?: ExtendedPublicKeysMap(emptyMap())
|
||||
|
|
@ -184,16 +201,7 @@ class DerivationManagerImpl(
|
|||
val toDerive = bothCandidates.filterNot { alreadyDerivedPaths.contains(it) }
|
||||
if (toDerive.isEmpty()) return null
|
||||
|
||||
currencyList.find { it is WalletModelCurrency.Blockchain && it.blockchain == Blockchain.Cardano }
|
||||
?.let { currency ->
|
||||
currency.derivationPath?.let {
|
||||
bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
|
||||
}
|
||||
}
|
||||
|
||||
return DerivationData(
|
||||
derivations = mapKeyOfWalletPublicKey to toDerive,
|
||||
)
|
||||
return TokensMiddleware.DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
},
|
||||
{
|
||||
"name": "NEW_CARD_SCANNING_ENABLED",
|
||||
"version": "4.11.0"
|
||||
"version": "undefined"
|
||||
},
|
||||
{
|
||||
"name": "REDESIGNED_WALLET_SCREEN_ENABLED",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import com.tangem.common.CardFilter
|
|||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.common.core.Config
|
||||
import com.tangem.sdk.extensions.initWithBiometrics
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
|
@ -20,17 +19,18 @@ import javax.inject.Singleton
|
|||
internal class DefaultCardSdkProvider @Inject constructor() : CardSdkProvider, CardSdkLifecycleObserver {
|
||||
|
||||
override val sdk: TangemSdk
|
||||
get() = requireNotNull(value = _sdk?.get()) { "Impossible to get the TangemSdk when activity is destroyed" }
|
||||
get() = requireNotNull(value = _sdk) { "Impossible to get the TangemSdk when activity is destroyed" }
|
||||
|
||||
private var _sdk: WeakReference<TangemSdk?>? = null
|
||||
private var _sdk: TangemSdk? = null
|
||||
|
||||
override fun onCreate(context: Context) {
|
||||
_sdk = WeakReference(TangemSdk.initWithBiometrics(activity = context as FragmentActivity, config = config))
|
||||
_sdk = TangemSdk.initWithBiometrics(activity = context as FragmentActivity, config = config)
|
||||
}
|
||||
|
||||
override fun onDestroy(context: Context) {
|
||||
// Commented out to prevent crash on getting sdk when it's null.
|
||||
// FIXME: We still should find the real cause and fix it properly.
|
||||
// idea: pass everywhere DefaultCardSdkProvider instead sdk to reach lazy access to sdk property
|
||||
// _sdk = null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ compose-navigation = "2.5.3"
|
|||
compose-accompanist = "0.30.1"
|
||||
compose-paging = "3.2.0"
|
||||
compose-reorderable = "0.9.6"
|
||||
compoese-lifecycle-runtime = "2.6.1"
|
||||
# endregion Compose
|
||||
|
||||
# region Other libraries
|
||||
|
|
@ -80,9 +81,9 @@ okHttp-prettyLogging = "3.1.0"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "release-app_4.11-344"
|
||||
tangemBlockchainSdk = "develop-350"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "release-app_4.11-294"
|
||||
tangemCardSdk = "develop-297"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds
|
||||
# endregion Tangem
|
||||
|
||||
|
|
@ -132,7 +133,7 @@ androidx-paging-runtime = { module = "androidx.paging:paging-runtime", version.r
|
|||
lifecycle-common-java8 = { module = "androidx.lifecycle:lifecycle-common-java8", version.ref = "androidxLifecycle" }
|
||||
lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidxLifecycle" }
|
||||
lifecycle-viewModel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidxLifecycle" }
|
||||
lifecycle-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidxLifecycle" }
|
||||
lifecycle-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "compoese-lifecycle-runtime" }
|
||||
# region AndroidX
|
||||
|
||||
# region Compose
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue