Updated on 2026-08-14
This commit is contained in:
parent
67a245a19c
commit
834a7e40c5
13 changed files with 78 additions and 38 deletions
|
|
@ -20,14 +20,14 @@ enum class SettingsElement(
|
|||
WalletConnect(R.drawable.ic_walletconnect, R.string.wallet_connect_title),
|
||||
Chat(R.drawable.ic_chat, R.string.details_ask_a_question),
|
||||
SendFeedback(R.drawable.ic_comment, R.string.details_row_title_send_feedback),
|
||||
ReferralProgram(R.drawable.ic_add_friends, R.string.details_referral_title),
|
||||
CardSettings(R.drawable.ic_card_settings, R.string.card_settings_title),
|
||||
AppCurrency(R.drawable.ic_currency, R.string.details_row_title_currency),
|
||||
AppSettings(R.drawable.ic_settings, R.string.app_settings_title),
|
||||
LinkMoreCards(R.drawable.ic_more_cards, R.string.details_row_title_create_backup),
|
||||
TermsOfService(R.drawable.ic_text, R.string.disclaimer_title), // General Terms of Service of the App
|
||||
TermsOfUse(R.drawable.ic_text, R.string.details_row_title_card_tou), // Terms of Use for S2C cards only
|
||||
PrivacyPolicy(R.drawable.ic_lock, R.string.details_row_privacy_policy),
|
||||
;
|
||||
PrivacyPolicy(R.drawable.ic_lock, R.string.details_row_privacy_policy);
|
||||
}
|
||||
|
||||
data class SocialNetworkLink(
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ class DetailsViewModel(private val store: Store<AppState>) {
|
|||
SettingsElement.PrivacyPolicy -> {
|
||||
// TODO: To be available later
|
||||
}
|
||||
SettingsElement.ReferralProgram -> {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.ReferralProgram))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ import com.tangem.tap.proxy.AppStateHolder
|
|||
|
||||
class AuthProviderImpl(private val appStateHolder: AppStateHolder) : AuthProvider {
|
||||
|
||||
override fun getAuthToken(): String {
|
||||
override fun getCardPublicKey(): String {
|
||||
return appStateHolder.scanResponse?.card?.cardPublicKey?.toHexString() ?: ""
|
||||
}
|
||||
|
||||
override fun getCardId(): String {
|
||||
return appStateHolder.scanResponse?.card?.cardId ?: ""
|
||||
}
|
||||
}
|
||||
9
app/src/main/res/drawable/ic_add_friends.xml
Normal file
9
app/src/main/res/drawable/ic_add_friends.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M15,4C13.939,4 12.922,4.421 12.172,5.172C11.421,5.922 11,6.939 11,8C11,9.061 11.421,10.078 12.172,10.828C12.922,11.579 13.939,12 15,12C16.061,12 17.078,11.579 17.828,10.828C18.579,10.078 19,9.061 19,8C19,6.939 18.579,5.922 17.828,5.172C17.078,4.421 16.061,4 15,4ZM15,5.9C16.16,5.9 17.1,6.84 17.1,8C17.1,9.16 16.16,10.1 15,10.1C14.443,10.1 13.909,9.879 13.515,9.485C13.121,9.091 12.9,8.557 12.9,8C12.9,7.443 13.121,6.909 13.515,6.515C13.909,6.121 14.443,5.9 15,5.9ZM4,7V10H1V12H4V15H6V12H9V10H6V7H4ZM15,13C12.33,13 7,14.33 7,17V20H23V17C23,14.33 17.67,13 15,13ZM15,14.9C17.97,14.9 21.1,16.36 21.1,17V18.1H8.9V17C8.9,16.36 12,14.9 15,14.9Z"
|
||||
android:fillColor="#000000" />
|
||||
</vector>
|
||||
|
|
@ -9,16 +9,17 @@ class AuthHeaderInterceptor(
|
|||
) : Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request().newBuilder().apply {
|
||||
addHeader(
|
||||
HEADER_CARD_KEY, authProvider.getAuthToken(),
|
||||
)
|
||||
}.build()
|
||||
val request = chain.request()
|
||||
.newBuilder()
|
||||
.addHeader(HEADER_CARD_KEY, authProvider.getCardPublicKey())
|
||||
.addHeader(HEADER_CARD_ID, authProvider.getCardId())
|
||||
.build()
|
||||
|
||||
return chain.proceed(request)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val HEADER_CARD_KEY = "card_public_key"
|
||||
const val HEADER_CARD_ID = "card_id"
|
||||
}
|
||||
}
|
||||
|
|
@ -5,17 +5,16 @@ import com.tangem.datasource.api.referral.models.StartReferralBody
|
|||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Query
|
||||
import retrofit2.http.Path
|
||||
|
||||
/**
|
||||
* Api for referral feature
|
||||
*/
|
||||
interface
|
||||
ReferralApi {
|
||||
interface ReferralApi {
|
||||
|
||||
/** Returns referral status by [walletId] */
|
||||
@GET("referral/{walletId}")
|
||||
suspend fun getReferralStatus(@Query("name") walletId: String): ReferralResponse
|
||||
suspend fun getReferralStatus(@Path("walletId") walletId: String): ReferralResponse
|
||||
|
||||
/** Make user referral, requires [StartReferralBody] */
|
||||
@POST("referral")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.datasource.api.referral.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.joda.time.DateTime
|
||||
|
||||
/**
|
||||
|
|
@ -21,7 +22,7 @@ data class Conditions(
|
|||
|
||||
data class Discount(
|
||||
@Json(name = "amount") val amount: Int,
|
||||
@Json(name = "discountType") val discountType: DiscountType,
|
||||
@Json(name = "type") val discountType: String,
|
||||
)
|
||||
|
||||
data class Award(
|
||||
|
|
@ -41,11 +42,7 @@ data class Token(
|
|||
data class Referral(
|
||||
@Json(name = "shareLink") val shareLink: String,
|
||||
@Json(name = "address") val address: String,
|
||||
@Json(name = "promocode") val promocode: String,
|
||||
@Json(name = "promoCode") val promocode: String,
|
||||
@Json(name = "walletsPurchased") val walletsPurchased: Int,
|
||||
@Json(name = "termsAcceptedAt") val termsAcceptedAt: DateTime?,
|
||||
)
|
||||
|
||||
enum class DiscountType {
|
||||
PERCENTAGE, VALUE
|
||||
}
|
||||
@Json(name = "termsAcceptedAt") val termsAcceptedAt: String?,
|
||||
)
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import com.tangem.datasource.api.AuthHeaderInterceptor
|
||||
import com.tangem.datasource.api.referral.ReferralApi
|
||||
import com.tangem.lib.auth.AuthProvider
|
||||
|
|
@ -22,7 +24,11 @@ class NetworkModule {
|
|||
fun provideReferralApi(okHttpClient: OkHttpClient): ReferralApi {
|
||||
return Retrofit.Builder()
|
||||
.addConverterFactory(
|
||||
MoshiConverterFactory.create(),
|
||||
MoshiConverterFactory.create(
|
||||
Moshi.Builder()
|
||||
.addLast(KotlinJsonAdapterFactory())
|
||||
.build(),
|
||||
),
|
||||
)
|
||||
.baseUrl(PROD_REFERRAL_BASE_URL)
|
||||
.client(okHttpClient)
|
||||
|
|
@ -34,14 +40,14 @@ class NetworkModule {
|
|||
@Singleton
|
||||
fun provideOkHttpClient(authProvider: AuthProvider): OkHttpClient {
|
||||
return OkHttpClient.Builder()
|
||||
.addInterceptor(
|
||||
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC),
|
||||
)
|
||||
.addInterceptor(AuthHeaderInterceptor(authProvider))
|
||||
.addInterceptor(
|
||||
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY),
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PROD_REFERRAL_BASE_URL = "https://api.tangem-tech.com/v1/"
|
||||
const val PROD_REFERRAL_BASE_URL = "https://devapi.tangem-tech.com/v1/"//"https://api.tangem-tech.com/v1/"
|
||||
}
|
||||
}
|
||||
9
core/utils/src/main/java/com/tangem/utils/Extensions.kt
Normal file
9
core/utils/src/main/java/com/tangem/utils/Extensions.kt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.utils
|
||||
|
||||
inline fun <reified T : Enum<T>> safeValueOf(type: String, default: T): T {
|
||||
return try {
|
||||
java.lang.Enum.valueOf(T::class.java, type)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
default
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,8 @@ import com.tangem.feature.referral.domain.models.ReferralData
|
|||
import com.tangem.feature.referral.domain.models.ReferralInfo
|
||||
import com.tangem.feature.referral.domain.models.TokenData
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.safeValueOf
|
||||
import org.joda.time.format.ISODateTimeFormat
|
||||
import javax.inject.Inject
|
||||
|
||||
class ReferralConverter @Inject constructor() : Converter<ReferralResponse, ReferralData> {
|
||||
|
|
@ -19,7 +21,7 @@ class ReferralConverter @Inject constructor() : Converter<ReferralResponse, Refe
|
|||
ReferralData.ParticipantData(
|
||||
award = conditions.award,
|
||||
discount = conditions.discount.amount,
|
||||
discountType = DiscountType.valueOf(conditions.discount.discountType.name),
|
||||
discountType = safeValueOf(conditions.discount.discountType.uppercase(), DiscountType.PERCENTAGE),
|
||||
tosLink = conditions.tosLink,
|
||||
tokens = tokenConverter.convertList(conditions.awards.map { it.token }),
|
||||
referral = ReferralInfo(
|
||||
|
|
@ -27,14 +29,16 @@ class ReferralConverter @Inject constructor() : Converter<ReferralResponse, Refe
|
|||
address = referral.address,
|
||||
promocode = referral.promocode,
|
||||
walletsPurchased = referral.walletsPurchased,
|
||||
termsAcceptedAt = referral.termsAcceptedAt,
|
||||
termsAcceptedAt = referral.termsAcceptedAt?.let {
|
||||
ISODateTimeFormat.dateTimeParser().parseDateTime(referral.termsAcceptedAt)
|
||||
},
|
||||
),
|
||||
)
|
||||
} else {
|
||||
ReferralData.NonParticipantData(
|
||||
award = conditions.award,
|
||||
discount = conditions.discount.amount,
|
||||
discountType = DiscountType.valueOf(conditions.discount.discountType.name),
|
||||
discountType = safeValueOf(conditions.discount.discountType.uppercase(), DiscountType.PERCENTAGE),
|
||||
tosLink = conditions.tosLink,
|
||||
tokens = tokenConverter.convertList(conditions.awards.map { it.token }),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
|||
BottomSheetScaffold(
|
||||
sheetContent = {
|
||||
AgreementBottomSheetContent(
|
||||
url = (stateHolder.referralInfoState as ReferralInfoContentState).url,
|
||||
url = (stateHolder.referralInfoState as? ReferralInfoContentState)?.url ?: "",
|
||||
)
|
||||
},
|
||||
scaffoldState = bottomSheetScaffoldState,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class ReferralViewModel @Inject constructor(
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : ViewModel() {
|
||||
|
||||
var uiState by mutableStateOf(createInitiallyUiState())
|
||||
var uiState: ReferralStateHolder by mutableStateOf(createInitiallyUiState())
|
||||
private set
|
||||
|
||||
init {
|
||||
|
|
@ -36,15 +36,24 @@ class ReferralViewModel @Inject constructor(
|
|||
private fun createInitiallyUiState() = ReferralStateHolder(
|
||||
headerState = ReferralStateHolder.HeaderState(onBackClicked = { }),
|
||||
referralInfoState = ReferralInfoState.Loading,
|
||||
errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = ::cancelErrorToast),
|
||||
errorToast = ReferralStateHolder.ErrorToast(
|
||||
visibility = false,
|
||||
changeVisibility = {
|
||||
uiState = uiState.copy(
|
||||
referralInfoState = uiState.referralInfoState,
|
||||
errorToast = uiState.errorToast.copy(visibility = false),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
private fun loadReferralData() {
|
||||
val lastUiState = uiState
|
||||
uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading)
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
runCatching(dispatchers.io) { referralInteractor.getReferralStatus() }
|
||||
.onSuccess { uiState = uiState.copy(referralInfoState = it.convertToReferralInfoState()) }
|
||||
.onFailure { uiState = uiState.copy(errorToast = uiState.errorToast.copy(visibility = true)) }
|
||||
.onFailure { uiState = lastUiState.copy(errorToast = lastUiState.errorToast.copy(visibility = true)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,15 +86,12 @@ class ReferralViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onParticipateClicked() {
|
||||
val lastUiState = uiState
|
||||
uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading)
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
runCatching(dispatchers.io) { referralInteractor.startReferral() }
|
||||
.onSuccess { uiState = uiState.copy(referralInfoState = it.convertToReferralInfoState()) }
|
||||
.onFailure { uiState = uiState.copy(errorToast = uiState.errorToast.copy(visibility = true)) }
|
||||
.onFailure { uiState = lastUiState.copy(errorToast = lastUiState.errorToast.copy(visibility = true)) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelErrorToast() {
|
||||
uiState = uiState.copy(errorToast = uiState.errorToast.copy(visibility = false))
|
||||
}
|
||||
}
|
||||
|
|
@ -8,5 +8,7 @@ interface AuthProvider {
|
|||
/**
|
||||
* Returns authToken for tangem tech api
|
||||
*/
|
||||
fun getAuthToken(): String
|
||||
fun getCardPublicKey(): String
|
||||
|
||||
fun getCardId(): String
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue