Updated on 2026-08-14
This commit is contained in:
parent
e5876470de
commit
91c52c039c
17 changed files with 398 additions and 13 deletions
|
|
@ -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"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
1
features/tester/impl/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
65
features/tester/impl/build.gradle.kts
Normal file
65
features/tester/impl/build.gradle.kts
Normal 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"))
|
||||
}
|
||||
10
features/tester/impl/src/main/AndroidManifest.xml
Normal file
10
features/tester/impl/src/main/AndroidManifest.xml
Normal 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>
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
6
features/tester/impl/src/main/res/values/strings.xml
Normal file
6
features/tester/impl/src/main/res/values/strings.xml
Normal 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>
|
||||
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue