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/settings/.gitignore
vendored
Normal file
1
data/settings/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
39
data/settings/build.gradle.kts
Normal file
39
data/settings/build.gradle.kts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import com.tangem.plugin.configuration.configurations.extension.kaptForObfuscatingVariants
|
||||
|
||||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
alias(deps.plugins.hilt.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.data.settings"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation(projects.core.datasource)
|
||||
implementation(projects.core.utils)
|
||||
|
||||
implementation(projects.domain.balanceHiding.models)
|
||||
implementation(projects.domain.settings)
|
||||
|
||||
implementation(deps.androidx.datastore)
|
||||
|
||||
// region DI
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
// endregion
|
||||
|
||||
// region Others dependencies
|
||||
implementation(deps.jodatime)
|
||||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.moshi)
|
||||
implementation(deps.moshi.kotlin)
|
||||
implementation(deps.timber)
|
||||
kaptForObfuscatingVariants(deps.moshi.kotlin.codegen)
|
||||
kaptForObfuscatingVariants(deps.retrofit.response.type.keeper)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.tangem.data.settings
|
||||
|
||||
import androidx.datastore.preferences.core.MutablePreferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.get
|
||||
import com.tangem.domain.settings.repositories.AppRatingRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import java.util.Calendar
|
||||
|
||||
internal class DefaultAppRatingRepository(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
) : AppRatingRepository {
|
||||
|
||||
override suspend fun setWalletWithFundsFound() {
|
||||
appPreferencesStore.edit { mutablePreferences ->
|
||||
val foundDate = mutablePreferences[PreferencesKeys.FUNDS_FOUND_DATE_KEY]
|
||||
if (foundDate != null && foundDate != FUNDS_FOUND_DATE_UNDEFINED) return@edit
|
||||
|
||||
mutablePreferences[PreferencesKeys.FUNDS_FOUND_DATE_KEY] = Calendar.getInstance().timeInMillis
|
||||
|
||||
val appLaunchCount = mutablePreferences[PreferencesKeys.APP_LAUNCH_COUNT_KEY] ?: DEFAULT_APP_LAUNCH_COUNT
|
||||
mutablePreferences[PreferencesKeys.SHOW_RATING_DIALOG_AT_LAUNCH_COUNT_KEY] =
|
||||
appLaunchCount + FIRST_SHOWING_COUNT
|
||||
}
|
||||
}
|
||||
|
||||
override fun isReadyToShow(): Flow<Boolean> {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
return combine(
|
||||
appPreferencesStore.get(key = PreferencesKeys.USER_WAS_INTERACT_WITH_RATING_KEY, default = false),
|
||||
appPreferencesStore.get(
|
||||
key = PreferencesKeys.SHOW_RATING_DIALOG_AT_LAUNCH_COUNT_KEY,
|
||||
default = FIRST_SHOWING_COUNT,
|
||||
),
|
||||
appPreferencesStore.get(key = PreferencesKeys.APP_LAUNCH_COUNT_KEY, default = DEFAULT_APP_LAUNCH_COUNT),
|
||||
appPreferencesStore.get(key = PreferencesKeys.FUNDS_FOUND_DATE_KEY, default = FUNDS_FOUND_DATE_UNDEFINED),
|
||||
) { isInteracting, ratingShowingCount, appLaunchCount, fundsFoundDate ->
|
||||
if (!isInteracting) {
|
||||
val diff = Calendar.getInstance().timeInMillis - fundsFoundDate
|
||||
val diffInDays = diff / DAY_IN_MILLIS
|
||||
val isFundsFound = fundsFoundDate != FUNDS_FOUND_DATE_UNDEFINED
|
||||
|
||||
appLaunchCount >= ratingShowingCount && diffInDays >= FIRST_SHOWING_COUNT && isFundsFound
|
||||
} else {
|
||||
appLaunchCount >= ratingShowingCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun remindLater() {
|
||||
appPreferencesStore.edit { mutablePreferences ->
|
||||
mutablePreferences[PreferencesKeys.APP_LAUNCH_COUNT_KEY]?.let {
|
||||
mutablePreferences.updateNextShowing(it + DEFER_SHOWING_COUNT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setNeverToShow() {
|
||||
appPreferencesStore.edit { mutablePreferences ->
|
||||
mutablePreferences.updateNextShowing(at = Int.MAX_VALUE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutablePreferences.updateNextShowing(at: Int) {
|
||||
this[PreferencesKeys.SHOW_RATING_DIALOG_AT_LAUNCH_COUNT_KEY] = at
|
||||
this[PreferencesKeys.USER_WAS_INTERACT_WITH_RATING_KEY] = true
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val FUNDS_FOUND_DATE_UNDEFINED = -1L
|
||||
const val DEFAULT_APP_LAUNCH_COUNT = 1
|
||||
const val FIRST_SHOWING_COUNT = 3
|
||||
const val DEFER_SHOWING_COUNT = 20
|
||||
const val DAY_IN_MILLIS = 1000 * 60 * 60 * 24
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.data.settings
|
||||
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys.getShouldShowInitialPermissionScreen
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys.getShouldShowPermission
|
||||
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
||||
import com.tangem.datasource.local.preferences.utils.store
|
||||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
|
||||
internal class DefaultPermissionRepository(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
) : PermissionRepository {
|
||||
|
||||
override suspend fun shouldInitiallyShowPermissionScreen(permission: String): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(
|
||||
key = getShouldShowInitialPermissionScreen(permission),
|
||||
default = true,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun neverInitiallyShowPermissionScreen(permission: String) {
|
||||
appPreferencesStore.store(
|
||||
key = getShouldShowInitialPermissionScreen(permission),
|
||||
value = false,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun shouldAskPermission(permission: String): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(getShouldShowPermission(permission), true)
|
||||
}
|
||||
|
||||
override suspend fun neverAskPermission(permission: String) {
|
||||
appPreferencesStore.store(key = getShouldShowPermission(permission), value = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
package com.tangem.data.settings
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.models.GeoResponse
|
||||
import com.tangem.datasource.local.logs.AppLogsStore
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
||||
import com.tangem.datasource.local.preferences.utils.store
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.util.Locale
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
internal class DefaultSettingsRepository(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val appLogsStore: AppLogsStore,
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : SettingsRepository {
|
||||
|
||||
private val userCountryFlow = MutableStateFlow<UserCountry?>(value = null)
|
||||
|
||||
override suspend fun shouldShowSaveUserWalletScreen(): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(
|
||||
key = PreferencesKeys.SHOULD_SHOW_SAVE_USER_WALLET_SCREEN_KEY,
|
||||
default = true,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setShouldShowSaveUserWalletScreen(value: Boolean) {
|
||||
appPreferencesStore.store(key = PreferencesKeys.SHOULD_SHOW_SAVE_USER_WALLET_SCREEN_KEY, value = value)
|
||||
}
|
||||
|
||||
override suspend fun isWalletScrollPreviewEnabled(): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(
|
||||
key = PreferencesKeys.WALLETS_SCROLL_PREVIEW_KEY,
|
||||
default = true,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setWalletScrollPreviewAvailability(isEnabled: Boolean) {
|
||||
appPreferencesStore.store(
|
||||
key = PreferencesKeys.WALLETS_SCROLL_PREVIEW_KEY,
|
||||
value = isEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
override fun deleteDeprecatedLogs(maxSize: Int) {
|
||||
appLogsStore.deleteDeprecatedLogs(maxSize)
|
||||
}
|
||||
|
||||
override suspend fun isSendTapHelpPreviewEnabled(): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(
|
||||
key = PreferencesKeys.SEND_TAP_HELP_PREVIEW_KEY,
|
||||
default = true,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setSendTapHelpPreviewAvailability(isEnabled: Boolean) {
|
||||
appPreferencesStore.store(
|
||||
key = PreferencesKeys.SEND_TAP_HELP_PREVIEW_KEY,
|
||||
value = isEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun wasApplicationStopped(): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(key = PreferencesKeys.WAS_APPLICATION_STOPPED_KEY, default = false)
|
||||
}
|
||||
|
||||
override suspend fun setWasApplicationStopped(value: Boolean) {
|
||||
appPreferencesStore.store(key = PreferencesKeys.WAS_APPLICATION_STOPPED_KEY, value = value)
|
||||
}
|
||||
|
||||
override suspend fun shouldOpenWelcomeScreenOnResume(): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(
|
||||
key = PreferencesKeys.SHOULD_OPEN_WELCOME_ON_RESUME_KEY,
|
||||
default = false,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setShouldOpenWelcomeScreenOnResume(value: Boolean) {
|
||||
appPreferencesStore.store(key = PreferencesKeys.SHOULD_OPEN_WELCOME_ON_RESUME_KEY, value = value)
|
||||
}
|
||||
|
||||
override suspend fun shouldSaveAccessCodes(): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(key = PreferencesKeys.SHOULD_SAVE_ACCESS_CODES_KEY, default = false)
|
||||
}
|
||||
|
||||
override suspend fun setShouldSaveAccessCodes(value: Boolean) {
|
||||
appPreferencesStore.store(key = PreferencesKeys.SHOULD_SAVE_ACCESS_CODES_KEY, value = value)
|
||||
}
|
||||
|
||||
override suspend fun incrementAppLaunchCounter() {
|
||||
appPreferencesStore.editData { preferences ->
|
||||
val count = preferences.getOrDefault(key = PreferencesKeys.APP_LAUNCH_COUNT_KEY, default = 0)
|
||||
preferences[PreferencesKeys.APP_LAUNCH_COUNT_KEY] = count + 1
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun shouldShowMarketsTooltip(): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(
|
||||
key = PreferencesKeys.SHOULD_SHOW_MARKETS_TOOLTIP_KEY,
|
||||
default = true,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setMarketsTooltipShown(value: Boolean) {
|
||||
appPreferencesStore.store(key = PreferencesKeys.SHOULD_SHOW_MARKETS_TOOLTIP_KEY, value = !value)
|
||||
}
|
||||
|
||||
override suspend fun getUserCountryCodeSync(): UserCountry? {
|
||||
// If user country code is already set, return it
|
||||
val countryCode = userCountryFlow.value
|
||||
if (countryCode != null) return countryCode
|
||||
|
||||
coroutineScope {
|
||||
launch { fetchUserCountryCode() }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getUserCountryCode(): StateFlow<UserCountry?> = userCountryFlow
|
||||
|
||||
override suspend fun fetchUserCountryCode() {
|
||||
Timber.i("Start fetching user country code")
|
||||
|
||||
withContext(dispatchers.io) {
|
||||
val country = runCatching { tangemTechApi.getUserCountryCode() }
|
||||
.fold(
|
||||
onSuccess = GeoResponse::code,
|
||||
onFailure = { Locale.getDefault().country },
|
||||
)
|
||||
.lowercase()
|
||||
|
||||
val code = when (country) {
|
||||
UserCountry.Russia.code -> UserCountry.Russia
|
||||
else -> UserCountry.Other(code = country)
|
||||
}
|
||||
|
||||
Timber.i("User code country is $code")
|
||||
|
||||
userCountryFlow.value = code
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setGoogleServicesAvailability(value: Boolean) {
|
||||
appPreferencesStore.store(key = PreferencesKeys.IS_GOOGLE_SERVICES_AVAILABLE_KEY, value = value)
|
||||
}
|
||||
|
||||
override suspend fun isGoogleServicesAvailability(): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(
|
||||
key = PreferencesKeys.IS_GOOGLE_SERVICES_AVAILABLE_KEY,
|
||||
default = false,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setGooglePayAvailability(value: Boolean) {
|
||||
appPreferencesStore.store(key = PreferencesKeys.IS_GOOGLE_PAY_AVAILABLE_KEY, value = value)
|
||||
}
|
||||
|
||||
override suspend fun isGooglePayAvailability(): Boolean {
|
||||
return appPreferencesStore.getSyncOrDefault(
|
||||
key = PreferencesKeys.IS_GOOGLE_PAY_AVAILABLE_KEY,
|
||||
default = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.data.settings.di
|
||||
|
||||
import com.tangem.data.settings.DefaultAppRatingRepository
|
||||
import com.tangem.data.settings.DefaultPermissionRepository
|
||||
import com.tangem.data.settings.DefaultSettingsRepository
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.local.logs.AppLogsStore
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.domain.settings.repositories.AppRatingRepository
|
||||
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
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 SettingsDataModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSettingsRepository(
|
||||
appPreferencesStore: AppPreferencesStore,
|
||||
appLogsStore: AppLogsStore,
|
||||
tangemTechApi: TangemTechApi,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): SettingsRepository {
|
||||
return DefaultSettingsRepository(
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
appLogsStore = appLogsStore,
|
||||
tangemTechApi = tangemTechApi,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAppRatingRepository(appPreferencesStore: AppPreferencesStore): AppRatingRepository {
|
||||
return DefaultAppRatingRepository(appPreferencesStore = appPreferencesStore)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providePushPermissionRepository(appPreferencesStore: AppPreferencesStore): PermissionRepository {
|
||||
return DefaultPermissionRepository(appPreferencesStore = appPreferencesStore)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue