Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-15 13:06:26 +03:00
parent c2e8cb82a7
commit c428dc5bf5
9 changed files with 148 additions and 0 deletions

View file

@ -1,4 +1,5 @@
import com.tangem.plugin.configuration.configurations.TogglesGenerator import com.tangem.plugin.configuration.configurations.TogglesGenerator
import io.gitlab.arturbosch.detekt.Detekt
plugins { plugins {
alias(deps.plugins.android.library) alias(deps.plugins.android.library)
@ -58,6 +59,10 @@ tasks.named("preBuild") {
dependsOn(generateToggles) dependsOn(generateToggles)
} }
tasks.withType<Detekt>().configureEach {
exclude { it.file.absolutePath.contains("/build/generated/") }
}
tasks.withType<Test>().configureEach { tasks.withType<Test>().configureEach {
useJUnitPlatform() useJUnitPlatform()
} }

View file

@ -70,5 +70,9 @@
{ {
"name": "SWAP_AB_ENABLED", "name": "SWAP_AB_ENABLED",
"version": "undefined" "version": "undefined"
},
{
"name": "TWI_1403_PUSH_NOTIFICATION_SETTINGS_ENABLED",
"version": "undefined"
} }
] ]

View file

@ -0,0 +1,61 @@
package com.tangem.core.configtoggle.feature
import com.google.common.truth.Truth
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import com.tangem.core.configtoggle.storage.ConfigToggle
import org.junit.jupiter.api.Test
import java.io.File
internal class FeatureTogglesNamingConventionTest {
@Test
fun `all new feature toggles must follow AND_id or TWI_id naming`() {
val toggles = parseToggles(CONFIG_FILE)
val invalid = toggles
.map(ConfigToggle::name)
.filterNot { it in EXCLUDED_TOGGLES_LIST }
.filterNot(VALID_NAME_PATTERN::matches)
Truth.assertWithMessage(
"""New feature toggles must match pattern ${VALID_NAME_PATTERN.pattern} — AND_<ticket_id> (Android ticket, e.g. AND_15312_PUSH_NOTIFICATION_SETTINGS_ENABLED) or TWI_<ticket_id> (idea ticket, e.g. TWI_1403_PUSH_NOTIFICATION_SETTINGS_ENABLED).
|Either rename these or, only if you have an explicit reason, add them to LEGACY_EXCLUDED.""".trimMargin(),
).that(invalid).isEmpty()
}
private fun parseToggles(file: File): List<ConfigToggle> {
val moshi = Moshi.Builder().build()
val listType = Types.newParameterizedType(List::class.java, ConfigToggle::class.java)
val adapter = moshi.adapter<List<ConfigToggle>>(listType)
return requireNotNull(adapter.fromJson(file.readText())) { "Failed to parse $file" }
}
private companion object {
val VALID_NAME_PATTERN = Regex("""^(AND|TWI)_\d+(?:_[A-Z0-9]+)+$""")
val CONFIG_FILE = File("src/main/assets/configs/feature_toggles_config.json")
/** Toggles created before the AND_/TWI_ naming convention. Do NOT add new entries. */
val EXCLUDED_TOGGLES_LIST = setOf(
"ADDRESS_SYNC_ENABLED",
"ADD_AND_MANAGE_TOKENS_ENABLED",
"APP_REDESIGN_ENABLED",
"ASSETS_DISCOVERY_ENABLED",
"DYNAMIC_ADDRESSES_ENABLED",
"GASLESS_APPROVAL_ENABLED",
"HEDERA_ERC20_ENABLED",
"NEW_CARD_SCANNING_ENABLED",
"SOLANA_SCALED_UI_AMOUNT_ENABLED",
"SOLANA_TX_HISTORY_ENABLED",
"STAKING_ETH_ENABLED",
"SWAP_AB_ENABLED",
"SWAP_INTEGRATED_APPROVE",
"SWAP_SWITCH_TO_TRANSFER_ENABLED",
"USEDESK_ENABLED",
"VIRTUAL_ACCOUNTS_ENABLED",
"VISA_ONBOARDING_ENABLED",
"WALLET_CONNECT_BITCOIN_ENABLED",
)
}
}

View file

@ -0,0 +1,9 @@
plugins {
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
id("configuration")
}
android {
namespace = "com.tangem.features.pushnotificationsettings.api"
}

View file

@ -0,0 +1,5 @@
package com.tangem.features.pushnotificationsettings
interface PushNotificationSettingsFeatureToggles {
val isPushNotificationSettingsEnabled: Boolean
}

View file

@ -0,0 +1,26 @@
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.features.pushnotificationsettings.impl"
}
dependencies {
/** Api */
implementation(projects.features.pushNotificationSettings.api)
/** Core modules */
implementation(projects.core.configToggles)
/** Compose */
implementation(deps.compose.runtime)
/** DI */
implementation(deps.hilt.android)
kapt(deps.hilt.kapt)
}

View file

@ -0,0 +1,12 @@
package com.tangem.features.pushnotificationsettings
import com.tangem.core.configtoggle.FeatureToggles
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
internal class DefaultPushNotificationSettingsFeatureToggles(
private val featureTogglesManager: FeatureTogglesManager,
) : PushNotificationSettingsFeatureToggles {
override val isPushNotificationSettingsEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1403_PUSH_NOTIFICATION_SETTINGS_ENABLED)
}

View file

@ -0,0 +1,23 @@
package com.tangem.features.pushnotificationsettings.di
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.features.pushnotificationsettings.DefaultPushNotificationSettingsFeatureToggles
import com.tangem.features.pushnotificationsettings.PushNotificationSettingsFeatureToggles
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 PushNotificationSettingsFeatureModule {
@Provides
@Singleton
fun providePushNotificationSettingsFeatureToggles(
featureTogglesManager: FeatureTogglesManager,
): PushNotificationSettingsFeatureToggles {
return DefaultPushNotificationSettingsFeatureToggles(featureTogglesManager)
}
}

View file

@ -244,6 +244,9 @@ include(":features:push-notifications:impl")
include(":features:wallet-settings:api") include(":features:wallet-settings:api")
include(":features:wallet-settings:impl") include(":features:wallet-settings:impl")
include(":features:push-notification-settings:api")
include(":features:push-notification-settings:impl")
include(":features:markets:api") include(":features:markets:api")
include(":features:markets:impl") include(":features:markets:impl")