Updated on 2026-08-14

This commit is contained in:
Tangem 2023-02-07 17:32:08 +08:00
parent e5876470de
commit 91c52c039c
17 changed files with 398 additions and 13 deletions

View file

@ -4,19 +4,23 @@ plugins {
id("io.gitlab.arturbosch.detekt")
}
tasks.withType<Detekt> {
detekt {
parallel = true
ignoreFailures = false
autoCorrect = true
buildUponDefaultConfig = true
config.setFrom(rootProject.files("config/detekt/detekt.yml"))
}
tasks.withType<Detekt> {
include("**/*.kt")
exclude("**/resources/**", "**/build/**")
reports {
sarif {
required.set(false)
}
txt {
required.set(true)
outputLocation.set(rootProject.file("build/reports/detekt.txt"))
}
}

View file

@ -10,13 +10,21 @@ processors:
console-reports:
active: true
exclude:
- 'ProjectStatisticsReport'
- 'ComplexityReport'
- 'NotificationReport'
- 'FindingsReport'
- 'FileBasedFindingsReport'
# - 'LiteFindingsReport'
output-reports:
active: true
exclude:
# - 'TxtOutputReport'
- 'XmlOutputReport'
- 'HtmlOutputReport'
# - 'TxtOutputReport'
- 'XmlOutputReport'
- 'SarifOutputReport'
- 'MdOutputReport'
comments:

View file

@ -104,9 +104,9 @@ fun TextInputDialog(
confirmButton: DialogButton,
onDismissDialog: () -> Unit,
onValueChange: (TextFieldValue) -> Unit,
textFieldParams: AdditionalTextInputDialogParams,
title: String? = null,
dismissButton: DialogButton? = null,
textFieldParams: AdditionalTextInputDialogParams,
) {
TangemDialog(
type = DialogType.TextInput(
@ -160,8 +160,8 @@ private fun TangemDialog(
@Composable
private fun DialogContent(
modifier: Modifier = Modifier,
type: DialogType,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
@ -197,9 +197,9 @@ private fun DialogContent(
@Composable
private fun DialogButtons(
modifier: Modifier = Modifier,
confirmButton: DialogButton,
dismissButton: DialogButton?,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier.fillMaxWidth(),
@ -227,11 +227,11 @@ private fun DialogButtons(
@Composable
private fun DialogButton(
modifier: Modifier = Modifier,
text: String,
warning: Boolean,
enabled: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Box(modifier = modifier) {
if (warning) {

View file

@ -22,8 +22,10 @@ import com.tangem.core.ui.res.TangemTheme
/**
* App bar with back button and optional title
*
* @param text optional title
* @param onBackClick the lambda to be invoked when this icon is pressed
* @param modifier modifier
* @param text optional title
* @param iconRes icon res id
*
* @see <a href = "https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?node-id=123%3A287&t=WdN5XpixzZLlQAZO-4"
* >Figma component</a>
@ -31,11 +33,12 @@ import com.tangem.core.ui.res.TangemTheme
@Composable
fun AppBarWithBackButton(
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
text: String? = null,
@DrawableRes iconRes: Int? = null,
) {
Row(
modifier = Modifier
modifier = modifier
.background(color = TangemTheme.colors.background.secondary)
.fillMaxWidth()
.padding(all = dimensionResource(R.dimen.spacing16)),

View file

@ -74,6 +74,7 @@ data class TangemDimens internal constructor(
val spacing12: Dp = 12.dp,
val spacing14: Dp = 14.dp,
val spacing16: Dp = 16.dp,
val spacing18: Dp = 18.dp,
val spacing20: Dp = 20.dp,
val spacing24: Dp = 24.dp,
val spacing28: Dp = 28.dp,

View file

@ -54,8 +54,7 @@ internal class SwapRepositoryImpl @Inject constructor(
networkId: String,
fromTokenAddress: String,
toTokenAddress: String,
amount:
String,
amount: String,
): AggregatedSwapDataModel<QuoteModel> {
return withContext(coroutineDispatcher.io) {
try {

1
features/tester/impl/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,65 @@
plugins {
id("com.android.library")
kotlin("android")
kotlin("kapt")
id("com.google.dagger.hilt.android")
}
android {
defaultConfig {
compileSdk = AppConfig.compileSdkVersion
minSdk = AppConfig.minSdkVersion
targetSdk = AppConfig.targetSdkVersion
vectorDrawables {
useSupportLibrary = true
}
}
kotlinOptions {
jvmTarget = "1.8"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildTypes {
create("debug_beta") {
initWith(getByName("release"))
BuildConfigFieldFactory(
fields = listOf(
Field.Environment("release"),
Field.TestActionEnabled(true),
Field.LogEnabled(true),
),
builder = ::buildConfigField,
).create()
}
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = Versions.compose
}
}
dependencies {
/** AndroidX */
implementation(AndroidX.activityCompose)
/** Compose */
implementation(Compose.material)
implementation(Compose.ui)
implementation(Compose.uiTooling)
/** DI */
implementation(Library.hilt)
kapt(Library.hiltKapt)
/** Core modules */
implementation(project(":core:ui"))
}

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tangem.feature.tester.impl">
<application>
<activity
android:name="com.tangem.feature.tester.presentation.TesterActivity"
android:exported="false" />
</application>
</manifest>

View file

@ -0,0 +1,17 @@
package com.tangem.feature.tester.presentation
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import dagger.hilt.android.AndroidEntryPoint
/** Activity for testers */
@AndroidEntryPoint
internal class TesterActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// TODO("2949") add logic to screens
}
}
}

View file

@ -0,0 +1,14 @@
package com.tangem.feature.tester.presentation.featuretoggles.models
/**
* Presentation model of feature toggle
*
* @property name name
* @property isEnabled availability
*
[REDACTED_AUTHOR]
*/
data class TesterFeatureToggle(
val name: String,
val isEnabled: Boolean
)

View file

@ -0,0 +1,24 @@
package com.tangem.feature.tester.presentation.featuretoggles.state
import com.tangem.feature.tester.presentation.featuretoggles.models.TesterFeatureToggle
/**
* State holder of feature toggles screen
*
[REDACTED_AUTHOR]
*/
sealed interface FeatureTogglesStateHolder {
/**
* Content
*
* @property featureToggles feature toggles list
* @property onToggleValueChange the lambda to be invoked when switch button is pressed
* @property onBackClicked the lambda to be invoked when back button is pressed
*/
data class Content(
val onBackClicked: () -> Unit,
val featureToggles: List<TesterFeatureToggle>,
val onToggleValueChange: (String, Boolean) -> Unit,
) : FeatureTogglesStateHolder
}

View file

@ -0,0 +1,119 @@
package com.tangem.feature.tester.presentation.featuretoggles.ui
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Switch
import androidx.compose.material.SwitchDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.tester.impl.R
import com.tangem.feature.tester.presentation.featuretoggles.models.TesterFeatureToggle
import com.tangem.feature.tester.presentation.featuretoggles.state.FeatureTogglesStateHolder
/**
* Screen with feature toggles list
*
* @param stateHolder screen state
*/
@Composable
fun FeatureTogglesScreen(stateHolder: FeatureTogglesStateHolder) {
when (stateHolder) {
is FeatureTogglesStateHolder.Content -> FeatureTogglesContent(content = stateHolder)
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun FeatureTogglesContent(content: FeatureTogglesStateHolder.Content) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.background(TangemTheme.colors.background.secondary),
) {
stickyHeader {
AppBarWithBackButton(
onBackClick = content.onBackClicked,
text = stringResource(id = R.string.feature_toggles),
)
}
items(content.featureToggles) { featureToggle ->
FeatureToggleItem(
toggle = featureToggle,
onCheckedChange = { isChange -> content.onToggleValueChange(featureToggle.name, isChange) },
)
}
}
}
@Composable
private fun FeatureToggleItem(toggle: TesterFeatureToggle, onCheckedChange: (Boolean) -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing18),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = toggle.name,
color = TangemTheme.colors.text.primary1,
maxLines = 1,
style = TangemTheme.typography.body1,
)
Switch(
checked = toggle.isEnabled,
onCheckedChange = onCheckedChange,
colors = SwitchDefaults.colors(
checkedThumbColor = TangemTheme.colors.control.checked,
uncheckedThumbColor = TangemTheme.colors.control.unchecked,
),
)
}
}
@Preview
@Composable
private fun PreviewFeatureTogglesScreen_InLightTheme() {
TangemTheme(isDark = false) {
FeatureTogglesScreen(
stateHolder = FeatureTogglesStateHolder.Content(
featureToggles = listOf(
TesterFeatureToggle(name = "FEATURE_TOGGLE_1", isEnabled = true),
TesterFeatureToggle(name = "FEATURE_TOGGLE_2", isEnabled = false),
),
onToggleValueChange = { _, _ -> },
onBackClicked = {},
),
)
}
}
@Preview
@Composable
private fun PreviewFeatureTogglesScreen_InDarkTheme() {
TangemTheme(isDark = true) {
FeatureTogglesScreen(
stateHolder = FeatureTogglesStateHolder.Content(
featureToggles = listOf(
TesterFeatureToggle(name = "FEATURE_TOGGLE_1", isEnabled = true),
TesterFeatureToggle(name = "FEATURE_TOGGLE_2", isEnabled = false),
),
onToggleValueChange = { _, _ -> },
onBackClicked = {},
),
)
}
}

View file

@ -0,0 +1,20 @@
package com.tangem.feature.tester.presentation.menu.state
/**
* State holder of tester menu screen
*
[REDACTED_AUTHOR]
*/
sealed interface TesterMenuStateHolder {
/**
* Content
*
* @property onBackClicked the lambda to be invoked when back button is pressed
* @property onFeatureTogglesClicked the lambda to be invoked when feature toggles button is pressed
*/
data class Content(
val onBackClicked: () -> Unit,
val onFeatureTogglesClicked: () -> Unit
) : TesterMenuStateHolder
}

View file

@ -0,0 +1,92 @@
package com.tangem.feature.tester.presentation.menu.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.tester.impl.R
import com.tangem.feature.tester.presentation.menu.state.TesterMenuStateHolder
/**
* Screen with functionality for testers
*
* @param stateHolder screen state
*/
@Composable
fun TesterMenuScreen(stateHolder: TesterMenuStateHolder) {
when (stateHolder) {
is TesterMenuStateHolder.Content -> TesterMenuContent(content = stateHolder)
}
}
@Composable
private fun TesterMenuContent(content: TesterMenuStateHolder.Content) {
Column(
modifier = Modifier
.fillMaxSize()
.background(TangemTheme.colors.background.secondary),
) {
AppBarWithBackButton(
onBackClick = content.onBackClicked,
text = stringResource(id = R.string.tester_menu),
)
Column(
modifier = Modifier
.padding(
horizontal = TangemTheme.dimens.spacing18,
vertical = TangemTheme.dimens.spacing8,
)
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
) {
PrimaryButton(
text = stringResource(R.string.feature_toggles),
onClick = content.onFeatureTogglesClicked,
modifier = Modifier.fillMaxWidth(),
)
PrimaryButton(
text = stringResource(R.string.stand_toggles),
onClick = content.onFeatureTogglesClicked,
modifier = Modifier.fillMaxWidth(),
enabled = false,
)
}
}
}
@Preview
@Composable
private fun PreviewTesterMenuScreen_InLightTheme() {
TangemTheme(isDark = false) {
TesterMenuScreen(
stateHolder = TesterMenuStateHolder.Content(
onBackClicked = {},
onFeatureTogglesClicked = {},
),
)
}
}
@Preview
@Composable
private fun PreviewTesterMenuScreen_InDarkTheme() {
TangemTheme(isDark = true) {
TesterMenuScreen(
stateHolder = TesterMenuStateHolder.Content(
onBackClicked = {},
onFeatureTogglesClicked = {},
),
)
}
}

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="tester_menu" translatable="false">Tester menu</string>
<string name="feature_toggles" translatable="false">Feature toggles</string>
<string name="stand_toggles" translatable="false">Stand toggles</string>
</resources>

View file

@ -22,4 +22,6 @@ include(":features:referral:presentation")
include(":features:swap:data")
include(":features:swap:domain")
include(":features:swap:presentation")
include(":features:tester:impl")
// endregion Feature modules