Updated on 2026-08-14
This commit is contained in:
parent
330ae73357
commit
e7efe7b76a
4636 changed files with 234864 additions and 63507 deletions
1
data/feedback/.gitignore
vendored
Normal file
1
data/feedback/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
46
data/feedback/build.gradle.kts
Normal file
46
data/feedback/build.gradle.kts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.data.feedback"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
// region AndroidX libraries
|
||||
implementation(deps.androidx.datastore)
|
||||
// endregion
|
||||
|
||||
// region DI
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
// endregion
|
||||
|
||||
// region Tangem libraries
|
||||
implementation(tangemDeps.blockchain)
|
||||
implementation(tangemDeps.card.core)
|
||||
// endregion
|
||||
|
||||
// Other libraries
|
||||
implementation(deps.timber)
|
||||
// endregion
|
||||
|
||||
// region Core modules
|
||||
implementation(projects.core.datasource)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.utils)
|
||||
// endregion
|
||||
|
||||
|
||||
implementation(projects.domain.feedback)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package com.tangem.data.feedback
|
||||
|
||||
import android.os.Build
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.core.navigation.email.EmailSender
|
||||
import com.tangem.data.feedback.converters.BlockchainInfoConverter
|
||||
import com.tangem.data.feedback.converters.CardInfoConverter
|
||||
import com.tangem.datasource.local.logs.AppLogsStore
|
||||
import com.tangem.datasource.local.walletmanager.WalletManagersStore
|
||||
import com.tangem.domain.feedback.models.*
|
||||
import com.tangem.domain.feedback.repository.FeedbackRepository
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Implementation of [FeedbackRepository]
|
||||
*
|
||||
* @property appLogsStore app logs store
|
||||
* @property userWalletsListManager user wallets list manager
|
||||
* @property walletManagersStore wallet managers store
|
||||
* @property emailSender email sender
|
||||
* @property appVersionProvider app version provider
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultFeedbackRepository(
|
||||
private val appLogsStore: AppLogsStore,
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val walletManagersStore: WalletManagersStore,
|
||||
private val emailSender: EmailSender,
|
||||
private val appVersionProvider: AppVersionProvider,
|
||||
) : FeedbackRepository {
|
||||
|
||||
private val blockchainsErrors = MutableStateFlow<Map<UserWalletId, BlockchainErrorInfo>>(emptyMap())
|
||||
|
||||
override fun getCardInfo(scanResponse: ScanResponse) = CardInfoConverter.convert(value = scanResponse)
|
||||
|
||||
override fun getUserWalletsInfo(userWalletId: UserWalletId?): UserWalletsInfo {
|
||||
return UserWalletsInfo(
|
||||
selectedUserWalletId = userWalletId?.stringValue ?: "card isn't activated",
|
||||
totalUserWallets = userWalletsListManager.walletsCount,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getBlockchainInfoList(userWalletId: UserWalletId): List<BlockchainInfo> {
|
||||
return walletManagersStore
|
||||
.getAllSync(userWalletId = userWalletId)
|
||||
.map(BlockchainInfoConverter::convert)
|
||||
}
|
||||
|
||||
override suspend fun getBlockchainInfo(
|
||||
userWalletId: UserWalletId,
|
||||
blockchainId: String,
|
||||
derivationPath: String?,
|
||||
): BlockchainInfo? {
|
||||
return walletManagersStore
|
||||
.getSyncOrNull(
|
||||
userWalletId = userWalletId,
|
||||
blockchain = Blockchain.fromId(blockchainId),
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
?.let(BlockchainInfoConverter::convert)
|
||||
}
|
||||
|
||||
override fun getPhoneInfo(): PhoneInfo {
|
||||
return PhoneInfo(
|
||||
phoneModel = Build.MODEL,
|
||||
osVersion = Build.VERSION.SDK_INT.toString(),
|
||||
appVersion = appVersionProvider.versionName,
|
||||
)
|
||||
}
|
||||
|
||||
override fun saveBlockchainErrorInfo(error: BlockchainErrorInfo) {
|
||||
val userWallet = userWalletsListManager.selectedUserWalletSync ?: error("UserWallet is not selected")
|
||||
|
||||
blockchainsErrors.update {
|
||||
it.toMutableMap().apply {
|
||||
put(userWallet.walletId, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBlockchainErrorInfo(userWalletId: UserWalletId): BlockchainErrorInfo? {
|
||||
return blockchainsErrors.value[userWalletId].also {
|
||||
if (it == null) Timber.e("Blockchain error info is null for $userWalletId")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLogFile(): File? = appLogsStore.getFile()
|
||||
|
||||
override fun sendEmail(feedbackEmail: FeedbackEmail) {
|
||||
emailSender.send(
|
||||
EmailSender.Email(
|
||||
address = feedbackEmail.address,
|
||||
subject = feedbackEmail.subject,
|
||||
message = feedbackEmail.message,
|
||||
attachment = feedbackEmail.file,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.tangem.data.feedback.converters
|
||||
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.address.Address
|
||||
import com.tangem.domain.feedback.models.BlockchainInfo
|
||||
import com.tangem.domain.feedback.models.BlockchainInfo.Addresses.Multiple.AddressInfo
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.domain.feedback.models.BlockchainInfo.Addresses as BlockchainAddresses
|
||||
|
||||
/**
|
||||
* Converter from [WalletManager] to [BlockchainInfo]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object BlockchainInfoConverter : Converter<WalletManager, BlockchainInfo> {
|
||||
|
||||
override fun convert(value: WalletManager): BlockchainInfo {
|
||||
return BlockchainInfo(
|
||||
blockchain = value.wallet.blockchain.fullName,
|
||||
derivationPath = value.wallet.publicKey.derivationPath?.rawPath ?: "",
|
||||
outputsCount = value.outputsCount?.toString(),
|
||||
host = value.currentHost,
|
||||
addresses = value.wallet.mapAddresses(Address::value),
|
||||
explorerLinks = value.wallet.mapAddresses { value.wallet.getExploreUrl(it.value) },
|
||||
tokens = value.cardTokens.map { token ->
|
||||
BlockchainInfo.TokenInfo(
|
||||
id = token.id,
|
||||
name = token.name,
|
||||
contractAddress = token.contractAddress,
|
||||
decimals = token.decimals.toString(),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private inline fun Wallet.mapAddresses(map: (Address) -> String): BlockchainAddresses {
|
||||
return if (addresses.size == 1) {
|
||||
BlockchainAddresses.Single(value = map(addresses.first()))
|
||||
} else {
|
||||
BlockchainAddresses.Multiple(
|
||||
addresses.map {
|
||||
AddressInfo(type = it.type.name, value = map(it))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.data.feedback.converters
|
||||
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.domain.common.util.getBackupCardsCount
|
||||
import com.tangem.domain.feedback.models.CardInfo
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
/**
|
||||
* Converter from [ScanResponse] to [CardInfo]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object CardInfoConverter : Converter<ScanResponse, CardInfo> {
|
||||
|
||||
override fun convert(value: ScanResponse): CardInfo {
|
||||
return with(value) {
|
||||
CardInfo(
|
||||
userWalletId = createUserWalletId(scanResponse = value),
|
||||
cardId = card.cardId,
|
||||
cardsCount = value.getBackupCardsCount()?.toString() ?: "0",
|
||||
firmwareVersion = card.firmwareVersion.stringValue,
|
||||
cardBlockchain = walletData?.blockchain,
|
||||
signedHashesList = card.wallets.map {
|
||||
CardInfo.SignedHashes(curve = it.curve.curve, total = it.totalSignedHashes?.toString())
|
||||
},
|
||||
isImported = value.card.wallets.any(CardDTO.Wallet::isImported),
|
||||
isStart2Coin = value.card.isStart2Coin,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createUserWalletId(scanResponse: ScanResponse): UserWalletId? {
|
||||
return UserWalletIdBuilder.scanResponse(scanResponse = scanResponse).build()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.data.feedback.di
|
||||
|
||||
import com.tangem.core.navigation.email.EmailSender
|
||||
import com.tangem.data.feedback.DefaultFeedbackRepository
|
||||
import com.tangem.datasource.local.logs.AppLogsStore
|
||||
import com.tangem.datasource.local.walletmanager.WalletManagersStore
|
||||
import com.tangem.domain.feedback.repository.FeedbackRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object FeedbackRepositoryModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideFeedbackRepository(
|
||||
appLogsStore: AppLogsStore,
|
||||
userWalletsListManager: UserWalletsListManager,
|
||||
walletManagersStore: WalletManagersStore,
|
||||
emailSender: EmailSender,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
): FeedbackRepository {
|
||||
return DefaultFeedbackRepository(
|
||||
appLogsStore = appLogsStore,
|
||||
userWalletsListManager = userWalletsListManager,
|
||||
walletManagersStore = walletManagersStore,
|
||||
emailSender = emailSender,
|
||||
appVersionProvider = appVersionProvider,
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue