Updated on 2026-08-14

This commit is contained in:
Tangem 2023-11-22 12:48:29 +03:00
commit a1b910cc7e
149 changed files with 4442 additions and 1330 deletions

View file

@ -30,7 +30,6 @@ import com.tangem.domain.apptheme.repository.AppThemeModeRepository
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
import com.tangem.domain.card.ScanCardProcessor
import com.tangem.domain.common.LogConfig
import com.tangem.domain.settings.repositories.AppRatingRepository
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
@ -209,9 +208,6 @@ internal class TapApplication : Application(), ImageLoaderFactory {
@Inject
lateinit var userTokensStore: UserTokensStore
@Inject
lateinit var appRatingRepository: AppRatingRepository
@Inject
lateinit var getAppThemeModeUseCase: GetAppThemeModeUseCase
@ -248,10 +244,8 @@ internal class TapApplication : Application(), ImageLoaderFactory {
// TODO: Try to performance and user experience.
// [REDACTED_JIRA]
runBlocking {
walletsRepository.initialize()
initUserWalletsListManager()
featureTogglesManager.init()
appRatingRepository.initialize()
// learn2earnInteractor.init()
}

View file

@ -0,0 +1,24 @@
package com.tangem.tap.di.domain
import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.android.scopes.ViewModelScoped
@Module
@InstallIn(ViewModelComponent::class)
internal object TransactionDomainModule {
@Provides
@ViewModelScoped
fun provideGetUseCase(
walletManagersFacade: WalletManagersFacade,
dispatchers: CoroutineDispatcherProvider,
): GetFeeUseCase {
return GetFeeUseCase(walletManagersFacade, dispatchers)
}
}

View file

@ -18,7 +18,7 @@ import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.details.ui.appsettings.AppSettingsItemsFactory
import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState.Item
import com.tangem.tap.features.details.ui.common.TangemSwitch
import com.tangem.core.ui.components.TangemSwitch
@Composable
internal fun SettingsSwitchItem(item: Item.Switch, modifier: Modifier = Modifier) {

View file

@ -1,88 +0,0 @@
package com.tangem.tap.features.details.ui.common
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.indication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.res.TangemTheme
@Suppress("MagicNumber")
@Composable
fun TangemSwitch(
onCheckedChange: (Boolean) -> Unit,
checkedColor: Color = TangemTheme.colors.icon.accent,
uncheckedColor: Color = TangemTheme.colors.icon.informative,
size: Dp = 48.dp,
checked: Boolean = false,
enabled: Boolean = true,
) {
val transition = updateTransition(checked, label = "SwitchState")
val color by transition.animateColor(
transitionSpec = {
tween(durationMillis = 200, easing = FastOutLinearInEasing)
},
label = "",
) { isChecked ->
(if (isChecked) checkedColor else uncheckedColor)
.copy(alpha = if (enabled) 1f else .4f)
}
val interactionSource = remember { MutableInteractionSource() }
Box(
modifier = Modifier
.clickable(
interactionSource = interactionSource,
indication = null,
enabled = enabled,
) {
onCheckedChange(!checked)
}
.indication(
interactionSource = interactionSource,
indication = rememberRipple(
bounded = false,
color = Color.Transparent,
),
),
) {
BoxWithConstraints(
modifier = Modifier
.width(size)
.height(size / 2)
.indication(interactionSource, null)
.background(color = color, shape = RoundedCornerShape(100)),
contentAlignment = Alignment.CenterStart,
) {
val roundCardSize = this.maxWidth / 2
val xOffset by transition.animateDp(
transitionSpec = {
tween(durationMillis = 150, easing = LinearOutSlowInEasing)
},
label = "xOffset",
) { enabled ->
if (enabled) this.maxWidth - roundCardSize else 0.dp
}
Box(
modifier = Modifier
.size(this.maxWidth / 2)
.offset(x = xOffset, y = 0.dp)
.padding(3.dp)
.background(color = Color.White, shape = RoundedCornerShape(100)),
)
}
}
}

View file

@ -14,6 +14,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
@ -25,7 +26,6 @@ import coil.request.ImageRequest
import com.tangem.core.ui.components.CurrencyPlaceholderIcon
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.ImageBackgroundContrastChecker
import com.tangem.tap.common.compose.extensions.toPx
import com.tangem.tap.features.tokens.impl.presentation.states.TokenItemState
import com.tangem.wallet.R
import kotlinx.coroutines.launch
@ -126,29 +126,37 @@ internal fun TokenItem(model: TokenItemState) {
@Composable
private fun Icon(name: String, iconUrl: String, onContrastCalculate: (Color) -> Unit, modifier: Modifier = Modifier) {
val pixelsSize = with(LocalDensity.current) { TangemTheme.dimens.size46.roundToPx() }
val iconModifier = modifier
.size(size = TangemTheme.dimens.size46)
.clip(TangemTheme.shapes.roundedCorners8)
val screenBackgroundColor = TangemTheme.colors.background.primary.toArgb()
var iconBackgroundColor by remember { mutableStateOf(Color.Transparent) }
var isBackgroundColorDefined by remember { mutableStateOf(false) }
val itemBackgroundColor = TangemTheme.colors.background.primary.toArgb()
val isDarkTheme = isSystemInDarkTheme()
val coroutineScope = rememberCoroutineScope()
SubcomposeAsyncImage(
modifier = iconModifier,
model = ImageRequest.Builder(context = LocalContext.current)
.size(size = TangemTheme.dimens.size46.toPx().toInt())
.data(data = iconUrl)
.size(size = pixelsSize)
.memoryCacheKey(key = iconUrl + pixelsSize)
.crossfade(enable = true)
.allowHardware(false)
.listener(
onSuccess = { _, result ->
if (isDarkTheme) {
if (!isBackgroundColorDefined && isDarkTheme) {
coroutineScope.launch {
val color = ImageBackgroundContrastChecker(
drawable = result.drawable,
backgroundColor = screenBackgroundColor,
).getContrastColorIfNeeded(isDarkTheme)
backgroundColor = itemBackgroundColor,
size = pixelsSize,
).getContrastColor(isDarkTheme = true)
onContrastCalculate(color)
iconBackgroundColor = color
isBackgroundColorDefined = true
}
}
},
@ -189,13 +197,12 @@ private fun Subtitle(isExpanded: Boolean, modifier: Modifier = Modifier) {
}
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun ChangeNetworksViewButton(isExpanded: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
IconButton(onClick = onClick, modifier = modifier.size(size = TangemTheme.dimens.size46)) {
AnimatedContent(
targetState = isExpanded,
transitionSpec = { fadeIn() + scaleIn() with scaleOut() + fadeOut() },
transitionSpec = { (fadeIn() + scaleIn()).togetherWith(scaleOut() + fadeOut()) },
) { isExpanded ->
Icon(
painter = painterResource(

View file

@ -4,7 +4,7 @@ import com.tangem.common.extensions.toHexString
import com.tangem.lib.auth.AuthProvider
import com.tangem.tap.proxy.AppStateHolder
class AuthProviderImpl(private val appStateHolder: AppStateHolder) : AuthProvider {
internal class DefaultAuthProvider(private val appStateHolder: AppStateHolder) : AuthProvider {
override fun getCardPublicKey(): String {
return appStateHolder.scanResponse?.card?.cardPublicKey?.toHexString() ?: ""

View file

@ -0,0 +1,32 @@
package com.tangem.tap.network.auth
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.lib.auth.sessionId.ExpressSessionIdGenerator
import java.util.UUID
import java.util.concurrent.atomic.AtomicReference
internal class DefaultExpressAuthProvider(
private val userWalletsStore: UserWalletsStore,
private val configManager: ConfigManager,
) : ExpressAuthProvider, ExpressSessionIdGenerator {
private var uuid = AtomicReference(UUID.randomUUID())
override fun getApiKey(): String {
return configManager.config.tangemExpressApiKey
}
override fun getUserId(): String {
return userWalletsStore.selectedUserWalletOrNull?.walletId?.stringValue ?: ""
}
override fun getSessionId(): String {
return uuid.get().toString()
}
override fun generateNewSessionId() {
uuid = AtomicReference(UUID.randomUUID())
}
}

View file

@ -1,7 +1,11 @@
package com.tangem.tap.network.auth.di
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.lib.auth.AuthProvider
import com.tangem.tap.network.auth.AuthProviderImpl
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.tap.network.auth.DefaultAuthProvider
import com.tangem.tap.network.auth.DefaultExpressAuthProvider
import com.tangem.tap.proxy.AppStateHolder
import dagger.Module
import dagger.Provides
@ -16,6 +20,18 @@ class AuthModule {
@Provides
@Singleton
fun provideAuthProvider(appStateHolder: AppStateHolder): AuthProvider {
return AuthProviderImpl(appStateHolder)
return DefaultAuthProvider(appStateHolder)
}
@Provides
@Singleton
fun provideExpressAuthProvider(
userWalletsStore: UserWalletsStore,
configManager: ConfigManager,
): ExpressAuthProvider {
return DefaultExpressAuthProvider(
userWalletsStore = userWalletsStore,
configManager = configManager,
)
}
}