diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8c5969e599..aa64c0d699 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -80,6 +80,7 @@ dependencies { implementation(projects.data.analytics) implementation(projects.data.transaction) implementation(projects.data.visa) + implementation(projects.data.promo) /** Features */ implementation(projects.features.onboarding) diff --git a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt index b439d53019..7149fc13da 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt @@ -100,6 +100,7 @@ internal object TokensDomainModule { marketCryptoCurrencyRepository: MarketCryptoCurrencyRepository, swapRepository: SwapRepository, showSwapPromoTokenUseCase: ShouldShowSwapPromoTokenUseCase, + promoRepository: PromoRepository, dispatchers: CoroutineDispatcherProvider, ): GetCurrencyWarningsUseCase { return GetCurrencyWarningsUseCase( @@ -110,6 +111,7 @@ internal object TokensDomainModule { marketCryptoCurrencyRepository = marketCryptoCurrencyRepository, swapRepository = swapRepository, showSwapPromoTokenUseCase = showSwapPromoTokenUseCase, + promoRepository = promoRepository, dispatchers = dispatchers, ) } diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/PromotionApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/PromotionApi.kt deleted file mode 100644 index d71061c21a..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/PromotionApi.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.tangem.datasource.api.promotion - -import com.tangem.datasource.api.promotion.models.* -import retrofit2.http.* - -/** - * - * Promotion API - * @see Documentation -[REDACTED_AUTHOR] - */ -interface PromotionApi { - - @Headers("Cache-Control: max-age=3600") - @GET("promotion") - suspend fun getPromotionInfo(@Query("programName") name: String): PromotionInfoResponse - - @POST("promotion/code/validate") - suspend fun validateCode(@Body request: CodeValidateRequestBody): CodeValidateResponse - - @POST("promotion/code/award") - suspend fun requestAwardByCode(@Body request: CodeAwardRequestBody): CodeAwardResponse - - @POST("promotion/validate") - suspend fun validate(@Body request: ValidateRequestBody): ValidateResponse - - @POST("promotion/award") - suspend fun requestAward(@Body request: AwardRequestBody): AwardResponse -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AbstractPromotionResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AbstractPromotionResponse.kt deleted file mode 100644 index edfc8e990d..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AbstractPromotionResponse.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.datasource.api.promotion.models - -import com.squareup.moshi.Json - -/** -[REDACTED_AUTHOR] - */ -abstract class AbstractPromotionResponse { - - abstract val error: Error? - - fun isError(): Boolean = error != null - - data class Error( - @Json(name = "code") val code: Int, - @Json(name = "message") val message: String, - ) -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardRequestBody.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardRequestBody.kt deleted file mode 100644 index c8ac7faed1..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardRequestBody.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.datasource.api.promotion.models - -import com.squareup.moshi.Json - -/** -[REDACTED_AUTHOR] - */ -data class AwardRequestBody( - @Json(name = "walletId") val walletId: String, - @Json(name = "address") val address: String, - @Json(name = "programName") val programName: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardResponse.kt deleted file mode 100644 index c43c59fa45..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardResponse.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.datasource.api.promotion.models - -import com.squareup.moshi.Json - -/** -[REDACTED_AUTHOR] - */ -data class AwardResponse( - @Json(name = "status") val status: Boolean?, - @Json(name = "error") override val error: Error? = null, -) : AbstractPromotionResponse() \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardRequestBody.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardRequestBody.kt deleted file mode 100644 index 51e8626d4b..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardRequestBody.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.datasource.api.promotion.models - -import com.squareup.moshi.Json - -/** -[REDACTED_AUTHOR] - */ -data class CodeAwardRequestBody( - @Json(name = "walletId") val walletId: String, - @Json(name = "address") val address: String, - @Json(name = "code") val code: String?, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardResponse.kt deleted file mode 100644 index 33d9313c42..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardResponse.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.datasource.api.promotion.models - -import com.squareup.moshi.Json - -/** -[REDACTED_AUTHOR] - */ -data class CodeAwardResponse( - @Json(name = "status") val status: Boolean?, - @Json(name = "error") override val error: Error? = null, -) : AbstractPromotionResponse() \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateRequestBody.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateRequestBody.kt deleted file mode 100644 index 769ecdad26..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateRequestBody.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.datasource.api.promotion.models - -import com.squareup.moshi.Json - -/** -[REDACTED_AUTHOR] - */ -data class CodeValidateRequestBody( - @Json(name = "walletId") val walletId: String, - @Json(name = "code") val code: String?, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateResponse.kt deleted file mode 100644 index e6e87e0ff3..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateResponse.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.datasource.api.promotion.models - -import com.squareup.moshi.Json - -/** -[REDACTED_AUTHOR] - */ -data class CodeValidateResponse( - @Json(name = "valid") val valid: Boolean?, - @Json(name = "error") override val error: Error? = null, -) : AbstractPromotionResponse() \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromotionInfoResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromotionInfoResponse.kt index ca5406aba5..fa9140eea1 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromotionInfoResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromotionInfoResponse.kt @@ -1,40 +1,23 @@ package com.tangem.datasource.api.promotion.models import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass -/** -[REDACTED_AUTHOR] - */ +@JsonClass(generateAdapter = true) data class PromotionInfoResponse( - @Json(name = "newCard") val newCard: Data?, - @Json(name = "oldCard") val oldCard: Data?, - @Json(name = "awardPaymentToken") val awardPaymentToken: TokenData?, - @Json(name = "error") override val error: Error? = null, -) : AbstractPromotionResponse() { + @Json(name = "name") val name: String, + @Json(name = "all") val bannerState: BannerState?, +) { - data class Data( - @Json(name = "status") val status: Status, - @Json(name = "award") val award: Double, + @JsonClass(generateAdapter = true) + data class BannerState( + @Json(name = "timeline") val timeline: Timeline, + @Json(name = "status") val status: String, ) - enum class Status(val value: String) { - @Json(name = "pending") - PENDING("pending"), - - @Json(name = "active") - ACTIVE("active"), - - @Json(name = "finished") - FINISHED("finished"), - } - - data class TokenData( - @Json(name = "id") val id: String, - @Json(name = "name") val name: String, - @Json(name = "symbol") val symbol: String, - @Json(name = "active") val active: Boolean, - @Json(name = "networkId") val networkId: String, - @Json(name = "contractAddress") val contractAddress: String, - @Json(name = "decimalCount") val decimalCount: Int, + @JsonClass(generateAdapter = true) + data class Timeline( + @Json(name = "start") val start: String, + @Json(name = "end") val end: String, ) } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateRequestBody.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateRequestBody.kt deleted file mode 100644 index 090f0e0d29..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateRequestBody.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.datasource.api.promotion.models - -import com.squareup.moshi.Json - -/** -[REDACTED_AUTHOR] - */ -data class ValidateRequestBody( - @Json(name = "walletId") val walletId: String, - @Json(name = "programName") val programName: String, -) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateResponse.kt deleted file mode 100644 index 97cd74645d..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateResponse.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.datasource.api.promotion.models - -import com.squareup.moshi.Json - -/** -[REDACTED_AUTHOR] - */ -data class ValidateResponse( - @Json(name = "valid") val valid: Boolean?, - @Json(name = "error") override val error: Error? = null, -) : AbstractPromotionResponse() \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt index 9992d45c5f..43ff3af6e5 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt @@ -1,6 +1,7 @@ package com.tangem.datasource.api.tangemTech import com.tangem.datasource.api.common.response.ApiResponse +import com.tangem.datasource.api.promotion.models.PromotionInfoResponse import com.tangem.datasource.api.tangemTech.models.* import retrofit2.http.* @@ -71,4 +72,7 @@ interface TangemTechApi { @Query("coinIds") coinIds: String, @Query("fields") fields: String = "price,priceChange24h,lastUpdatedAt", ): ApiResponse + + @GET("promotion") + suspend fun getPromotionInfo(@Query("programName") name: String): ApiResponse } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/PromotionOneInch.kt b/core/datasource/src/main/java/com/tangem/datasource/di/DevTangemApi.kt similarity index 80% rename from core/datasource/src/main/java/com/tangem/datasource/di/PromotionOneInch.kt rename to core/datasource/src/main/java/com/tangem/datasource/di/DevTangemApi.kt index 9e2d6b3981..4bfacf89db 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/PromotionOneInch.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/DevTangemApi.kt @@ -5,4 +5,4 @@ import javax.inject.Qualifier @Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) -annotation class PromotionOneInch \ No newline at end of file +annotation class DevTangemApi \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt index 754936c7a5..eb61db86b2 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt @@ -5,12 +5,10 @@ import com.squareup.moshi.Moshi import com.tangem.datasource.BuildConfig import com.tangem.datasource.api.common.response.ApiResponseCallAdapterFactory import com.tangem.datasource.api.express.TangemExpressApi -import com.tangem.datasource.api.promotion.PromotionApi import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.utils.RequestHeader.* import com.tangem.datasource.utils.addHeaders import com.tangem.datasource.utils.addLoggers -import com.tangem.lib.auth.AuthProvider import com.tangem.lib.auth.ExpressAuthProvider import dagger.Module import dagger.Provides @@ -20,7 +18,6 @@ import dagger.hilt.components.SingletonComponent import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.moshi.MoshiConverterFactory -import java.util.concurrent.TimeUnit import javax.inject.Singleton @Module @@ -75,31 +72,25 @@ class NetworkModule { } @Provides + @DevTangemApi @Singleton - @PromotionOneInch - fun providePromotionOneInchApi( - authProvider: AuthProvider, - @NetworkMoshi moshi: Moshi, - @ApplicationContext context: Context, - ): PromotionApi { - val okClient = OkHttpClient.Builder() - .addHeaders(AuthenticationHeader(authProvider)) - .addLoggers(context) - .callTimeout(API_ONE_INCH_TIMEOUT_MS, TimeUnit.MILLISECONDS) - .connectTimeout(API_ONE_INCH_TIMEOUT_MS, TimeUnit.MILLISECONDS) - .readTimeout(API_ONE_INCH_TIMEOUT_MS, TimeUnit.MILLISECONDS) - .writeTimeout(API_ONE_INCH_TIMEOUT_MS, TimeUnit.MILLISECONDS) - .build() - return createBasePromotionRetrofit(okClient, moshi) - } - - private fun createBasePromotionRetrofit(okHttpClient: OkHttpClient, moshi: Moshi): PromotionApi { + fun provideTangemTechDevApi(@NetworkMoshi moshi: Moshi, @ApplicationContext context: Context): TangemTechApi { return Retrofit.Builder() .addConverterFactory(MoshiConverterFactory.create(moshi)) - .baseUrl(PROD_TANGEM_TECH_BASE_URL) - .client(okHttpClient) + .addCallAdapterFactory(ApiResponseCallAdapterFactory.create()) + .baseUrl(DEV_TANGEM_TECH_BASE_URL) + .client( + OkHttpClient.Builder() + .addHeaders( + CacheControlHeader, + // TODO("refactor header init") get auth data after biometric auth to avoid race condition + // AuthenticationHeader(authProvider), + ) + .addLoggers(context) + .build(), + ) .build() - .create(PromotionApi::class.java) + .create(TangemTechApi::class.java) } private companion object { diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index 02432a3d03..652187147e 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -45,9 +45,13 @@ object PreferencesKeys { val LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY by lazy { stringPreferencesKey(name = "lastSwappedCryptoCurrency") } - val IS_WALLET_SWAP_PROMO_SHOW_KEY by lazy { booleanPreferencesKey(name = "isWalletSwapPromoShown") } + val IS_WALLET_SWAP_PROMO_CHANGELLY_SHOW_KEY by lazy { + booleanPreferencesKey(name = "isWalletSwapPromoChangellyShown") + } - val IS_TOKEN_SWAP_PROMO_SHOW_KEY by lazy { booleanPreferencesKey(name = "isTokenSwapPromoShown") } + val IS_TOKEN_SWAP_PROMO_CHANGELLY_SHOW_KEY by lazy { + booleanPreferencesKey(name = "isTokenSwapPromoChangellyShown") + } } /** Preferences keys set that should be migrated from "PreferencesDataSource" to a new DataStore */ diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index e257132463..0276e3c034 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -273,8 +273,8 @@ 1INCH токены будут зачислены на адрес вашего кошелька в сети %s в течение 48 часов Чтобы получить доступ ко всем сетям, вам необходимо отсканировать карту Отсканируйте карту - Обменивайте свои цифровые активы между различными сетями - Кроссчейн-своп теперь доступен + Обменивайте свои токены с %1$s комиссии провайдера через Changelly с %2$s по %3$s февраля. + Обмен с Changelly, %s комиссии Токены Добавить Изменить @@ -575,9 +575,9 @@ Токен %1$s является основной валютой в сети %2$s и не может быть скрыт до тех пор, пока у вас в списке есть другие токены этой сети. Невозможно скрыть %s Нет цены + Обменивайте этот токен на другие с %1$s комиссии за обслуживание с %2$s по %3$s февраля. + Обмен с Changelly, %s комиссии Обменять - Обменяйте этот токен на другие активы в вашем портфеле - Представляем кроссчейн-своп контракт: %s У вас еще нет транзакций Не удалось загрузить историю транзакций.\nНажмите на кнопку перезагрузки, чтобы обновить информацию. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index dd42088e6b..43914b654e 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -273,8 +273,8 @@ 1INCH tokens will be credited to your %s wallet address within 48 hours To access all the networks you need to scan the card Scan your card - Swap multiple currencies across several blockchains - Cross-chain swaps are now available + Enjoy %1$s service fees on swaps via Changelly from February %2$s-%3$s + Swap with Changelly, %s fees Tokens Add Edit @@ -587,8 +587,8 @@ The %1$s token is the main currency on the %2$s network and cannot be hidden as long as you have other tokens on this network in the list. Unable to hide %s No rate - Exchange this token for other assets in your portfolio - Introducing cross-chain swaps + Exchange this token for another at %1$s service fees from February %2$s-%3$s. + Swap with Changelly, %s fees Swap now contract: %s You don\'t have any transactions yet diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt index 691cded7ba..e4e8a06833 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt @@ -28,6 +28,7 @@ import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.res.LocalIsInDarkTheme import com.tangem.core.ui.res.TangemColorPalette.Dark6 import com.tangem.core.ui.res.TangemColorPalette.Light4 @@ -55,7 +56,7 @@ fun NotificationWithBackground(config: NotificationConfig, modifier: Modifier = val spacing14 = TangemTheme.dimens.spacing14 Image( - painter = painterResource(config.backgroundResId ?: R.drawable.img_swap_promo_banner_background), + painter = painterResource(config.backgroundResId ?: R.drawable.img_swap_promo_blue_banner_background), contentDescription = null, contentScale = ContentScale.Crop, modifier = Modifier.constrainAs(backgroundRef) { @@ -171,13 +172,19 @@ private class NotificationWithBackgroundPreviewProvider : PreviewParameterProvid override val values: Sequence get() = sequenceOf( NotificationConfig( - title = resourceReference(id = R.string.main_swap_promotion_title), - subtitle = resourceReference(id = R.string.main_swap_promotion_message), + title = resourceReference(id = R.string.main_swap_changelly_promotion_title), + subtitle = resourceReference( + id = R.string.main_swap_changelly_promotion_message, + formatArgs = wrappedList("1", "2"), + ), iconResId = R.drawable.img_swap_promo, - backgroundResId = R.drawable.img_swap_promo_banner_background, + backgroundResId = R.drawable.img_swap_promo_blue_banner_background, ), NotificationConfig( - title = resourceReference(id = R.string.token_swap_promotion_title), + title = resourceReference( + id = R.string.token_swap_changelly_promotion_title, + formatArgs = wrappedList("1", "2"), + ), subtitle = stringReference( "Swap multiple currencies between any chains you wish. Swap multiple " + "currencies between any chains you wish. Swap multiple " + @@ -185,7 +192,7 @@ private class NotificationWithBackgroundPreviewProvider : PreviewParameterProvid "till Dec 31.", ), iconResId = R.drawable.img_swap_promo, - backgroundResId = R.drawable.img_swap_promo_banner_background, + backgroundResId = R.drawable.img_swap_promo_blue_banner_background, buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( text = resourceReference(id = R.string.token_swap_promotion_button), onClick = {}, diff --git a/core/ui/src/main/res/drawable/img_swap_promo_banner_background.webp b/core/ui/src/main/res/drawable/img_swap_promo_blue_banner_background.webp similarity index 100% rename from core/ui/src/main/res/drawable/img_swap_promo_banner_background.webp rename to core/ui/src/main/res/drawable/img_swap_promo_blue_banner_background.webp diff --git a/core/ui/src/main/res/drawable/img_swap_promo_green_banner_background.webp b/core/ui/src/main/res/drawable/img_swap_promo_green_banner_background.webp new file mode 100644 index 0000000000..ffaced2ad2 Binary files /dev/null and b/core/ui/src/main/res/drawable/img_swap_promo_green_banner_background.webp differ diff --git a/data/promo/.gitignore b/data/promo/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/data/promo/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/data/promo/build.gradle.kts b/data/promo/build.gradle.kts new file mode 100644 index 0000000000..b11dc26ed9 --- /dev/null +++ b/data/promo/build.gradle.kts @@ -0,0 +1,25 @@ +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.promo" +} + +dependencies { + implementation(deps.androidx.datastore) + + implementation(deps.jodatime) + implementation(deps.hilt.android) + kapt(deps.hilt.kapt) + + implementation(projects.domain.tokens) + implementation(projects.domain.tokens.models) + + implementation(projects.core.datasource) + implementation(projects.core.utils) +} \ No newline at end of file diff --git a/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt new file mode 100644 index 0000000000..3121a961d7 --- /dev/null +++ b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt @@ -0,0 +1,29 @@ +package com.tangem.data.promo + +import com.tangem.data.promo.converters.PromoResponseConverter +import com.tangem.datasource.api.common.response.getOrThrow +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.domain.promo.PromoBanner +import com.tangem.domain.tokens.repository.PromoRepository +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.runCatching + +internal class DefaultPromoRepository( + private val tangemApi: TangemTechApi, + private val dispatchers: CoroutineDispatcherProvider, +) : PromoRepository { + + private val promoResponseConverter = PromoResponseConverter() + override suspend fun getChangellyPromoBanner(): PromoBanner? { + return runCatching(dispatchers.io) { + promoResponseConverter.convert( + tangemApi.getPromotionInfo(CHANGELLY_NAME) + .getOrThrow(), + ) + }.getOrNull() + } + + private companion object { + private const val CHANGELLY_NAME = "changelly" + } +} \ No newline at end of file diff --git a/data/promo/src/main/java/com/tangem/data/promo/converters/PromoResponseConverter.kt b/data/promo/src/main/java/com/tangem/data/promo/converters/PromoResponseConverter.kt new file mode 100644 index 0000000000..c7ad8f331a --- /dev/null +++ b/data/promo/src/main/java/com/tangem/data/promo/converters/PromoResponseConverter.kt @@ -0,0 +1,23 @@ +package com.tangem.data.promo.converters + +import com.tangem.datasource.api.promotion.models.PromotionInfoResponse +import com.tangem.domain.promo.PromoBanner +import com.tangem.utils.converter.Converter +import org.joda.time.DateTime + +class PromoResponseConverter : Converter { + + override fun convert(value: PromotionInfoResponse): PromoBanner? { + val bannerState = value.bannerState ?: return null + return PromoBanner( + name = value.name, + bannerState = PromoBanner.BannerState( + status = bannerState.status, + timeline = PromoBanner.Timeline( + start = DateTime.parse(bannerState.timeline.start), + end = DateTime.parse(bannerState.timeline.end), + ), + ), + ) + } +} \ No newline at end of file diff --git a/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt b/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt new file mode 100644 index 0000000000..c094043a9c --- /dev/null +++ b/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt @@ -0,0 +1,26 @@ +package com.tangem.data.promo.di + +import com.tangem.data.promo.DefaultPromoRepository +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.di.DevTangemApi +import com.tangem.domain.tokens.repository.PromoRepository +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 PromoDataModule { + + @Provides + @Singleton + fun providePromoRepository( + @DevTangemApi tangemTechApi: TangemTechApi, + dispatchers: CoroutineDispatcherProvider, + ): PromoRepository { + return DefaultPromoRepository(tangemTechApi, dispatchers) + } +} \ No newline at end of file diff --git a/data/settings/src/main/java/com/tangem/data/settings/DefaultSwapPromoRepository.kt b/data/settings/src/main/java/com/tangem/data/settings/DefaultSwapPromoRepository.kt index 8ba9fe211e..6d9ccf740a 100644 --- a/data/settings/src/main/java/com/tangem/data/settings/DefaultSwapPromoRepository.kt +++ b/data/settings/src/main/java/com/tangem/data/settings/DefaultSwapPromoRepository.kt @@ -1,14 +1,12 @@ package com.tangem.data.settings import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.preferences.PreferencesKeys.IS_TOKEN_SWAP_PROMO_SHOW_KEY -import com.tangem.datasource.local.preferences.PreferencesKeys.IS_WALLET_SWAP_PROMO_SHOW_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.IS_TOKEN_SWAP_PROMO_CHANGELLY_SHOW_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.IS_WALLET_SWAP_PROMO_CHANGELLY_SHOW_KEY import com.tangem.datasource.local.preferences.utils.get import com.tangem.datasource.local.preferences.utils.store import com.tangem.domain.settings.repositories.SwapPromoRepository import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import java.util.Calendar /** * Repository for showing swap promo notification. @@ -16,47 +14,25 @@ import java.util.Calendar class DefaultSwapPromoRepository( private val appPreferencesStore: AppPreferencesStore, ) : SwapPromoRepository { - override fun isReadyToShowWallet(): Flow { - return appPreferencesStore.get(IS_WALLET_SWAP_PROMO_SHOW_KEY, true) - .map { it && checkPromoPeriod() } + override fun isReadyToShowWalletPromo(): Flow { + return appPreferencesStore.get(IS_WALLET_SWAP_PROMO_CHANGELLY_SHOW_KEY, true) } - override fun isReadyToShowToken(): Flow { - return appPreferencesStore.get(IS_TOKEN_SWAP_PROMO_SHOW_KEY, true) - .map { it && checkPromoPeriod() } + override fun isReadyToShowTokenPromo(): Flow { + return appPreferencesStore.get(IS_TOKEN_SWAP_PROMO_CHANGELLY_SHOW_KEY, true) } - override suspend fun setNeverToShowWallet() { + override suspend fun setNeverToShowWalletPromo() { appPreferencesStore.store( - key = IS_WALLET_SWAP_PROMO_SHOW_KEY, + key = IS_WALLET_SWAP_PROMO_CHANGELLY_SHOW_KEY, value = false, ) } - override suspend fun setNeverToShowToken() { + override suspend fun setNeverToShowTokenPromo() { appPreferencesStore.store( - key = IS_TOKEN_SWAP_PROMO_SHOW_KEY, + key = IS_TOKEN_SWAP_PROMO_CHANGELLY_SHOW_KEY, value = false, ) } - - private suspend fun checkPromoPeriod(): Boolean { - val calendar = Calendar.getInstance() - val currentTime = calendar.timeInMillis - calendar.set(END_YEAR_KEY, END_MONTH_KEY, END_DAY_KEY, 0, 0, 0) - val endTime = calendar.timeInMillis - - val shouldShow = endTime - currentTime > 0 - if (!shouldShow) { - setNeverToShowToken() - setNeverToShowWallet() - } - return shouldShow - } - - companion object { - private const val END_DAY_KEY = 1 - private const val END_MONTH_KEY = 1 // February - private const val END_YEAR_KEY = 2024 - } } \ No newline at end of file diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoTokenUseCase.kt b/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoTokenUseCase.kt index 0c75a4f52a..966e1bcf83 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoTokenUseCase.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoTokenUseCase.kt @@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.Flow class ShouldShowSwapPromoTokenUseCase(private val swapPromoRepository: SwapPromoRepository) { - operator fun invoke(): Flow = swapPromoRepository.isReadyToShowToken() + operator fun invoke(): Flow = swapPromoRepository.isReadyToShowTokenPromo() - suspend fun neverToShow() = swapPromoRepository.setNeverToShowToken() + suspend fun neverToShow() = swapPromoRepository.setNeverToShowTokenPromo() } \ No newline at end of file diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoWalletUseCase.kt b/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoWalletUseCase.kt index 573a5ea94b..e2b30e1ba5 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoWalletUseCase.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoWalletUseCase.kt @@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.Flow class ShouldShowSwapPromoWalletUseCase(private val swapPromoRepository: SwapPromoRepository) { - operator fun invoke(): Flow = swapPromoRepository.isReadyToShowWallet() + operator fun invoke(): Flow = swapPromoRepository.isReadyToShowWalletPromo() - suspend fun neverToShow() = swapPromoRepository.setNeverToShowWallet() + suspend fun neverToShow() = swapPromoRepository.setNeverToShowWalletPromo() } \ No newline at end of file diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SwapPromoRepository.kt b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SwapPromoRepository.kt index 95d31f65d8..ca97755e66 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SwapPromoRepository.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SwapPromoRepository.kt @@ -3,11 +3,11 @@ package com.tangem.domain.settings.repositories import kotlinx.coroutines.flow.Flow interface SwapPromoRepository { - fun isReadyToShowWallet(): Flow + fun isReadyToShowWalletPromo(): Flow - fun isReadyToShowToken(): Flow + fun isReadyToShowTokenPromo(): Flow - suspend fun setNeverToShowWallet() + suspend fun setNeverToShowWalletPromo() - suspend fun setNeverToShowToken() + suspend fun setNeverToShowTokenPromo() } \ No newline at end of file diff --git a/domain/tokens/models/build.gradle.kts b/domain/tokens/models/build.gradle.kts index a354fa4700..f3bf4ce59c 100644 --- a/domain/tokens/models/build.gradle.kts +++ b/domain/tokens/models/build.gradle.kts @@ -15,4 +15,5 @@ dependencies { implementation(deps.tangem.blockchain) { exclude(module = "joda-time") } + implementation(deps.jodatime) } \ No newline at end of file diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/promo/PromoBanner.kt b/domain/tokens/models/src/main/java/com/tangem/domain/promo/PromoBanner.kt new file mode 100644 index 0000000000..564a49e3d4 --- /dev/null +++ b/domain/tokens/models/src/main/java/com/tangem/domain/promo/PromoBanner.kt @@ -0,0 +1,25 @@ +package com.tangem.domain.promo + +import org.joda.time.DateTime + +data class PromoBanner( + val name: String, + val bannerState: BannerState, +) { + + val isActive = bannerState.status == ACTIVE_STATUS && bannerState.timeline.end.isAfterNow + + data class BannerState( + val timeline: Timeline, + val status: String, + ) + + data class Timeline( + val start: DateTime, + val end: DateTime, + ) + + private companion object { + const val ACTIVE_STATUS = "active" + } +} \ No newline at end of file diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt index e393e4fbd3..b90d787043 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt @@ -1,6 +1,7 @@ package com.tangem.domain.tokens.model.warnings import com.tangem.domain.tokens.model.CryptoCurrency +import org.joda.time.DateTime import java.math.BigDecimal sealed class CryptoCurrencyWarning { @@ -42,5 +43,8 @@ sealed class CryptoCurrencyWarning { data class HasPendingTransactions(val blockchainSymbol: String) : CryptoCurrencyWarning() - object SwapPromo : CryptoCurrencyWarning() + data class SwapPromo( + val startDateTime: DateTime, + val endDateTime: DateTime, + ) : CryptoCurrencyWarning() } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt index b43052898e..3e5b6a3ed4 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt @@ -7,10 +7,7 @@ import com.tangem.domain.tokens.model.FeePaidCurrency import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations -import com.tangem.domain.tokens.repository.CurrenciesRepository -import com.tangem.domain.tokens.repository.MarketCryptoCurrencyRepository -import com.tangem.domain.tokens.repository.NetworksRepository -import com.tangem.domain.tokens.repository.QuotesRepository +import com.tangem.domain.tokens.repository.* import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.domain.api.SwapRepository @@ -29,6 +26,7 @@ class GetCurrencyWarningsUseCase( private val networksRepository: NetworksRepository, private val swapRepository: SwapRepository, private val marketCryptoCurrencyRepository: MarketCryptoCurrencyRepository, + private val promoRepository: PromoRepository, private val showSwapPromoTokenUseCase: ShouldShowSwapPromoTokenUseCase, private val dispatchers: CoroutineDispatcherProvider, ) { @@ -90,7 +88,9 @@ class GetCurrencyWarningsUseCase( showSwapPromoTokenUseCase().conflate(), flowOf(marketCryptoCurrencyRepository.isExchangeable(userWalletId, currency)).conflate(), ) { shouldShowSwapPromo, isExchangeable -> - if (shouldShowSwapPromo && isExchangeable && currencyStatus.value !is CryptoCurrencyStatus.Unreachable) { + val promoBanner = promoRepository.getChangellyPromoBanner() ?: return@combine null + val showPromo = promoBanner.isActive && shouldShowSwapPromo + if (showPromo && isExchangeable && currencyStatus.value !is CryptoCurrencyStatus.Unreachable) { cryptoStatuses.fold( ifLeft = { null }, ifRight = { cryptoCurrencyStatuses -> @@ -124,7 +124,10 @@ class GetCurrencyWarningsUseCase( } } if (showPromo) { - CryptoCurrencyWarning.SwapPromo + CryptoCurrencyWarning.SwapPromo( + startDateTime = promoBanner.bannerState.timeline.start, + endDateTime = promoBanner.bannerState.timeline.end, + ) } else { null } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/PromoRepository.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/PromoRepository.kt new file mode 100644 index 0000000000..b15e05db54 --- /dev/null +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/PromoRepository.kt @@ -0,0 +1,8 @@ +package com.tangem.domain.tokens.repository + +import com.tangem.domain.promo.PromoBanner + +interface PromoRepository { + + suspend fun getChangellyPromoBanner(): PromoBanner? +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt index 8a4732ea16..185abeff5d 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt @@ -9,6 +9,7 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.features.tokendetails.impl.R +import org.joda.time.DateTime @Immutable internal sealed class TokenDetailsNotification(val config: NotificationConfig) { @@ -41,14 +42,22 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) { ) data class SwapPromo( + val startDateTime: DateTime, + val endDateTime: DateTime, val onSwapClick: () -> Unit, val onCloseClick: () -> Unit, ) : TokenDetailsNotification( config = NotificationConfig( - title = resourceReference(id = R.string.token_swap_promotion_title), - subtitle = resourceReference(id = R.string.token_swap_promotion_message), + title = resourceReference( + id = R.string.token_swap_changelly_promotion_title, + formatArgs = wrappedList("0%"), + ), + subtitle = resourceReference( + id = R.string.token_swap_changelly_promotion_message, + formatArgs = wrappedList("0%", startDateTime.dayOfMonth, endDateTime.dayOfMonth), + ), iconResId = R.drawable.img_swap_promo, - backgroundResId = R.drawable.img_swap_promo_banner_background, + backgroundResId = R.drawable.img_swap_promo_green_banner_background, onCloseClick = onCloseClick, buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( text = resourceReference(id = com.tangem.core.ui.R.string.token_swap_promotion_button), diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt index c2a5ea5591..bf37784e25 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt @@ -68,6 +68,8 @@ internal class TokenDetailsNotificationConverter( coinSymbol = warning.blockchainSymbol, ) is CryptoCurrencyWarning.SwapPromo -> SwapPromo( + startDateTime = warning.startDateTime, + endDateTime = warning.endDateTime, onSwapClick = clickIntents::onSwapPromoClick, onCloseClick = clickIntents::onSwapPromoDismiss, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt index 574705c9f4..e4bec421bb 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt @@ -4,13 +4,16 @@ import arrow.core.Either import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase +import com.tangem.domain.promo.PromoBanner import com.tangem.domain.settings.IsReadyToShowRateAppUseCase +import com.tangem.domain.settings.ShouldShowSwapPromoWalletUseCase import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.NetworkGroup import com.tangem.domain.tokens.model.TokenList +import com.tangem.domain.tokens.repository.PromoRepository import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification @@ -26,12 +29,15 @@ import kotlinx.coroutines.flow.flowOf import timber.log.Timber import javax.inject.Inject +@Suppress("LongParameterList") @ViewModelScoped internal class GetMultiWalletWarningsFactory @Inject constructor( private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, private val getTokenListUseCase: GetTokenListUseCase, private val isDemoCardUseCase: IsDemoCardUseCase, private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase, + private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase, + private val promoRepository: PromoRepository, private val isNeedToBackupUseCase: IsNeedToBackupUseCase, ) { @@ -52,9 +58,15 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( flow = getTokenListUseCase(userWallet.walletId).conflate(), flow2 = isReadyToShowRateAppUseCase().conflate(), flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(), - ) { maybeTokenList, isReadyToShowRating, isNeedToBackup -> + flow4 = shouldShowSwapPromoWalletUseCase().conflate(), + ) { maybeTokenList, isReadyToShowRating, isNeedToBackup, shouldShowPromo -> + + val promoBanner = promoRepository.getChangellyPromoBanner() + readyForRateAppNotification = true buildList { + addSwapPromoNotification(shouldShowPromo, promoBanner, clickIntents) + addCriticalNotifications(cardTypesResolver) addInformationalNotifications(cardTypesResolver, maybeTokenList, clickIntents) @@ -66,6 +78,23 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( } } + private fun MutableList.addSwapPromoNotification( + shouldShowPromo: Boolean, + promoBanner: PromoBanner?, + clickIntents: WalletClickIntentsV2, + ) { + promoBanner ?: return + val promoNotification = WalletNotification.SwapPromo( + startDateTime = promoBanner.bannerState.timeline.start, + endDateTime = promoBanner.bannerState.timeline.end, + onCloseClick = clickIntents::onCloseSwapPromoClick, + ) + addIf( + element = promoNotification, + condition = shouldShowPromo && promoBanner.isActive, + ) + } + private fun MutableList.addCriticalNotifications(cardTypesResolver: CardTypesResolver) { addIf( element = WalletNotification.Critical.DevCard, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt index 7f6bfd6b46..6feefe3150 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt @@ -7,6 +7,7 @@ import com.tangem.core.ui.extensions.pluralReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.feature.wallet.impl.R +import org.joda.time.DateTime /** * Wallet notification component state @@ -168,13 +169,21 @@ sealed class WalletNotification(val config: NotificationConfig) { ) data class SwapPromo( + val startDateTime: DateTime, + val endDateTime: DateTime, val onCloseClick: () -> Unit, ) : WalletNotification( config = NotificationConfig( - title = resourceReference(id = R.string.main_swap_promotion_title), - subtitle = resourceReference(id = R.string.main_swap_promotion_message), + title = resourceReference( + id = R.string.main_swap_changelly_promotion_title, + formatArgs = wrappedList("0%"), + ), + subtitle = resourceReference( + id = R.string.main_swap_changelly_promotion_message, + formatArgs = wrappedList("0%", startDateTime.dayOfMonth, endDateTime.dayOfMonth), + ), iconResId = R.drawable.img_swap_promo, - backgroundResId = R.drawable.img_swap_promo_banner_background, + backgroundResId = R.drawable.img_swap_promo_green_banner_background, onCloseClick = onCloseClick, ), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt index dad5efb741..5c390dcb0b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt @@ -72,6 +72,4 @@ internal interface WalletClickIntents { fun onExploreClick() fun onTransactionClick(txHash: String) - - fun onCloseSwapPromoNotificationClick() } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt index c0145c919b..da74cc71c1 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt @@ -5,7 +5,6 @@ import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.settings.IsReadyToShowRateAppUseCase -import com.tangem.domain.settings.ShouldShowSwapPromoWalletUseCase import com.tangem.domain.tokens.GetMissedAddressesCryptoCurrenciesUseCase import com.tangem.domain.tokens.error.GetCurrenciesError import com.tangem.domain.tokens.model.CryptoCurrency @@ -41,7 +40,6 @@ internal class WalletNotificationsListFactory( private val isNeedToBackupUseCase: IsNeedToBackupUseCase, private val getMissedAddressCryptoCurrenciesUseCase: GetMissedAddressesCryptoCurrenciesUseCase, private val hasSingleWalletSignedHashesUseCase: HasSingleWalletSignedHashesUseCase, - private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase, private val clickIntents: WalletClickIntents, ) { @@ -57,12 +55,9 @@ internal class WalletNotificationsListFactory( flow2 = isReadyToShowRateAppUseCase().conflate(), flow3 = isNeedToBackupUseCase(selectedWallet.walletId).conflate(), flow4 = getMissedAddressCryptoCurrenciesUseCase(selectedWallet.walletId).conflate(), - flow5 = shouldShowSwapPromoWalletUseCase().conflate(), - ) { hasSignedHashes, isReadyToShowRating, isNeedToBackup, maybeMissedAddressCurrencies, isShowSwapPromo -> + ) { hasSignedHashes, isReadyToShowRating, isNeedToBackup, maybeMissedAddressCurrencies -> readyForRateAppNotification = true buildList { - addSwapPromoNotification(isShowSwapPromo, cardTypesResolver) - addCriticalNotifications(cardTypesResolver) addInformationalNotifications(cardTypesResolver, maybeMissedAddressCurrencies) @@ -86,18 +81,6 @@ internal class WalletNotificationsListFactory( } } - private fun MutableList.addSwapPromoNotification( - showSwapPromo: Boolean, - cardTypesResolver: CardTypesResolver, - ) { - addIf( - element = WalletNotification.SwapPromo( - clickIntents::onCloseSwapPromoNotificationClick, - ), - condition = showSwapPromo && cardTypesResolver.isMultiwalletAllowed(), - ) - } - private fun MutableList.addCriticalNotifications(cardTypesResolver: CardTypesResolver) { addIf( element = WalletNotification.Critical.DevCard, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 8adfe05590..b1c839e9d0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -129,7 +129,6 @@ internal class WalletViewModel @Inject constructor( private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase, private val isDemoCardUseCase: IsDemoCardUseCase, private val scanCardToUnlockWalletUseCase: ScanCardToUnlockWalletClickHandler, - private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase, isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase, isNeedToBackupUseCase: IsNeedToBackupUseCase, getMissedAddressesCryptoCurrenciesUseCase: GetMissedAddressesCryptoCurrenciesUseCase, @@ -148,7 +147,6 @@ internal class WalletViewModel @Inject constructor( isNeedToBackupUseCase = isNeedToBackupUseCase, getMissedAddressCryptoCurrenciesUseCase = getMissedAddressesCryptoCurrenciesUseCase, hasSingleWalletSignedHashesUseCase = hasSingleWalletSignedHashesUseCase, - shouldShowSwapPromoWalletUseCase = shouldShowSwapPromoWalletUseCase, clickIntents = this, ) @@ -795,12 +793,6 @@ internal class WalletViewModel @Inject constructor( refreshSingleCurrencyContent(selectedWalletIndex) } - override fun onCloseSwapPromoNotificationClick() { - viewModelScope.launch(dispatchers.main) { - shouldShowSwapPromoWalletUseCase.neverToShow() - } - } - // FIXME: refreshSingleCurrencyContent mustn't update the TxHistory and Buttons. It only must fetch primary // currency. Now it not works because GetPrimaryCurrency's subscriber uses .distinctUntilChanged() private fun refreshSingleCurrencyContent(walletIndex: Int) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt index ae87db6d02..a9c4287571 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt @@ -18,6 +18,7 @@ import com.tangem.domain.redux.LegacyAction import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.settings.NeverToSuggestRateAppUseCase import com.tangem.domain.settings.RemindToRateAppLaterUseCase +import com.tangem.domain.settings.ShouldShowSwapPromoWalletUseCase import com.tangem.domain.tokens.FetchTokenListUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UnlockWalletsError @@ -62,6 +63,8 @@ internal interface WalletWarningsClickIntents { fun onDislikeAppClick() fun onCloseRateAppWarningClick() + + fun onCloseSwapPromoClick() } @Suppress("LongParameterList") @@ -82,6 +85,7 @@ internal class WalletWarningsClickIntentsImplementer @Inject constructor( private val reduxStateHolder: ReduxStateHolder, private val testerFeatureToggles: TesterFeatureToggles, private val dispatchers: CoroutineDispatcherProvider, + private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase, ) : BaseWalletClickIntents(), WalletWarningsClickIntents { override fun onAddBackupCardClick() { @@ -302,4 +306,10 @@ internal class WalletWarningsClickIntentsImplementer @Inject constructor( remindToRateAppLaterUseCase() } } + + override fun onCloseSwapPromoClick() { + viewModelScope.launch(dispatchers.main) { + shouldShowSwapPromoWalletUseCase.neverToShow() + } + } } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 7fc4e85cba..11c13bfbe1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -152,4 +152,5 @@ include(":data:wallets") include(":data:analytics") include(":data:transaction") include(":data:visa") +include(":data:promo") // endregion Data modules \ No newline at end of file