Updated on 2026-08-14
This commit is contained in:
parent
3752cb060c
commit
9e932a5bee
8 changed files with 506 additions and 1 deletions
|
|
@ -30,6 +30,8 @@ import com.tangem.feature.tester.presentation.navigation.InnerTesterRouter
|
|||
import com.tangem.feature.tester.presentation.navigation.TesterScreen
|
||||
import com.tangem.feature.tester.presentation.providers.ui.BlockchainProvidersScreen
|
||||
import com.tangem.feature.tester.presentation.providers.viewmodel.BlockchainProvidersViewModel
|
||||
import com.tangem.feature.tester.presentation.testpush.ui.TestPushScreen
|
||||
import com.tangem.feature.tester.presentation.testpush.viewmodel.TestPushViewModel
|
||||
import com.tangem.features.tester.api.TesterRouter
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.collections.immutable.persistentSetOf
|
||||
|
|
@ -66,7 +68,7 @@ internal class TesterActivity : ComposeActivity() {
|
|||
TesterNavHost()
|
||||
}
|
||||
|
||||
@Suppress("TopLevelComposableFunctions")
|
||||
@Suppress("TopLevelComposableFunctions", "LongMethod")
|
||||
@Composable
|
||||
private fun TesterNavHost() {
|
||||
val navController = rememberNavController().also { innerTesterRouter.setNavController(it) }
|
||||
|
|
@ -82,6 +84,7 @@ internal class TesterActivity : ComposeActivity() {
|
|||
ButtonUM.ENVIRONMENT_TOGGLES,
|
||||
ButtonUM.BLOCKCHAIN_PROVIDERS,
|
||||
ButtonUM.TESTER_ACTIONS,
|
||||
ButtonUM.TEST_PUSHES,
|
||||
),
|
||||
onButtonClick = {
|
||||
val route = when (it) {
|
||||
|
|
@ -90,6 +93,7 @@ internal class TesterActivity : ComposeActivity() {
|
|||
ButtonUM.ENVIRONMENT_TOGGLES -> TesterScreen.ENVIRONMENTS_TOGGLES
|
||||
ButtonUM.BLOCKCHAIN_PROVIDERS -> TesterScreen.BLOCKCHAIN_PROVIDERS
|
||||
ButtonUM.TESTER_ACTIONS -> TesterScreen.TESTER_ACTIONS
|
||||
ButtonUM.TEST_PUSHES -> TesterScreen.TEST_PUSHES
|
||||
}
|
||||
|
||||
innerTesterRouter.open(route)
|
||||
|
|
@ -141,6 +145,15 @@ internal class TesterActivity : ComposeActivity() {
|
|||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
BlockchainProvidersScreen(state)
|
||||
}
|
||||
|
||||
composable(route = TesterScreen.TEST_PUSHES.name) {
|
||||
val viewModel = hiltViewModel<TestPushViewModel>().apply {
|
||||
setupNavigation(innerTesterRouter)
|
||||
}
|
||||
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
TestPushScreen(state, viewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ data class TesterMenuUM(
|
|||
ENVIRONMENT_TOGGLES(R.string.environment_toggles),
|
||||
BLOCKCHAIN_PROVIDERS(R.string.blockchain_providers),
|
||||
TESTER_ACTIONS(R.string.tester_actions),
|
||||
TEST_PUSHES(R.string.test_push),
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,4 +12,5 @@ internal enum class TesterScreen {
|
|||
TESTER_ACTIONS,
|
||||
EXCLUDED_BLOCKCHAINS,
|
||||
BLOCKCHAIN_PROVIDERS,
|
||||
TEST_PUSHES,
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.feature.tester.presentation.testpush.entity
|
||||
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
|
||||
interface TestPushClickIntents {
|
||||
fun onTitleChange(value: TextFieldValue)
|
||||
fun onMessageChange(value: TextFieldValue)
|
||||
fun onDataKeyChange(index: Int, value: TextFieldValue)
|
||||
fun onDataValueChange(index: Int, value: TextFieldValue)
|
||||
fun onDataAdd()
|
||||
fun onDataRemove(index: Int)
|
||||
fun onBackClick()
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.feature.tester.presentation.testpush.entity
|
||||
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
|
||||
internal data class TestPushUM(
|
||||
val fcmToken: String,
|
||||
val title: TextFieldValue,
|
||||
val message: TextFieldValue,
|
||||
val data: List<Pair<TextFieldValue, TextFieldValue>>,
|
||||
)
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
package com.tangem.feature.tester.presentation.testpush.ui
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context.NOTIFICATION_SERVICE
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.OutlineTextField
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.tester.presentation.testpush.entity.TestPushClickIntents
|
||||
import com.tangem.feature.tester.presentation.testpush.entity.TestPushUM
|
||||
|
||||
private const val SWIPE_THRESHOLD = 0.25f
|
||||
|
||||
@Composable
|
||||
internal fun TestPushScreen(testPushUM: TestPushUM, testPushClickIntents: TestPushClickIntents) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppBarWithBackButton(onBackClick = testPushClickIntents::onBackClick)
|
||||
},
|
||||
bottomBar = {
|
||||
SendLocalPushButton(testPushUM)
|
||||
},
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.padding(it)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
tokenData(fcmToken = testPushUM.fcmToken)
|
||||
contentData(testPushUM = testPushUM, testPushClickIntents = testPushClickIntents)
|
||||
extraData(testPushUM = testPushUM, testPushClickIntents = testPushClickIntents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.tokenData(fcmToken: String) {
|
||||
item("token_key") {
|
||||
val clipboard = LocalClipboardManager.current
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(16.dp)
|
||||
.animateItem(),
|
||||
) {
|
||||
Text(
|
||||
text = "FCM Token",
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp)
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(TangemTheme.colors.background.tertiary)
|
||||
.clickable {
|
||||
clipboard.setText(AnnotatedString(fcmToken))
|
||||
}
|
||||
.padding(8.dp),
|
||||
) {
|
||||
Text(
|
||||
text = fcmToken,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
modifier = Modifier
|
||||
.padding(end = 8.dp)
|
||||
.weight(1f),
|
||||
)
|
||||
Icon(
|
||||
painter = rememberVectorPainter(
|
||||
ImageVector.vectorResource(R.drawable.ic_copy_24),
|
||||
),
|
||||
tint = TangemTheme.colors.icon.secondary,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.contentData(testPushUM: TestPushUM, testPushClickIntents: TestPushClickIntents) {
|
||||
item("content_key") {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp)
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(16.dp)
|
||||
.animateItem(),
|
||||
) {
|
||||
Text(
|
||||
text = "Content",
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
OutlineTextField(
|
||||
label = "Title",
|
||||
value = testPushUM.title,
|
||||
onValueChange = testPushClickIntents::onTitleChange,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
OutlineTextField(
|
||||
label = "Message",
|
||||
value = testPushUM.message,
|
||||
onValueChange = testPushClickIntents::onMessageChange,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.extraData(testPushUM: TestPushUM, testPushClickIntents: TestPushClickIntents) {
|
||||
item("data_key") {
|
||||
Text(
|
||||
text = "Data",
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp)
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(topEnd = 16.dp, topStart = 16.dp))
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(16.dp)
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
|
||||
itemsIndexed(
|
||||
items = testPushUM.data,
|
||||
key = { index, _ -> index },
|
||||
contentType = { _, item -> item::class },
|
||||
) { index, (key, value) ->
|
||||
EnterPushData(
|
||||
key = key,
|
||||
value = value,
|
||||
index = index,
|
||||
testPushClickIntents = testPushClickIntents,
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(horizontal = 16.dp)
|
||||
.animateItem(),
|
||||
)
|
||||
}
|
||||
|
||||
item("data_add_key") {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(bottomStart = 16.dp, bottomEnd = 16.dp))
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(top = 8.dp, bottom = 16.dp, start = 16.dp, end = 16.dp)
|
||||
.animateItem(),
|
||||
) {
|
||||
PrimaryButton(
|
||||
text = "Add param",
|
||||
onClick = testPushClickIntents::onDataAdd,
|
||||
size = TangemButtonSize.Action,
|
||||
modifier = Modifier.align(Alignment.CenterEnd),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EnterPushData(
|
||||
key: TextFieldValue,
|
||||
value: TextFieldValue,
|
||||
index: Int,
|
||||
testPushClickIntents: TestPushClickIntents,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val swipeToDelete = rememberSwipeToDismissBoxState(
|
||||
positionalThreshold = { it * SWIPE_THRESHOLD },
|
||||
)
|
||||
|
||||
SwipeToDismissBox(
|
||||
modifier = modifier,
|
||||
state = swipeToDelete,
|
||||
enableDismissFromStartToEnd = false,
|
||||
backgroundContent = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(1.dp)
|
||||
.background(Color.Red),
|
||||
) {
|
||||
Text(
|
||||
text = "Remove",
|
||||
style = TangemTheme.typography.caption1,
|
||||
color = TangemTheme.colors.text.constantWhite,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.padding(8.dp),
|
||||
)
|
||||
}
|
||||
},
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.background(TangemTheme.colors.background.action),
|
||||
) {
|
||||
if (index != 0) {
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
)
|
||||
}
|
||||
OutlineTextField(
|
||||
label = "Key",
|
||||
value = key,
|
||||
onValueChange = {
|
||||
testPushClickIntents.onDataKeyChange(index, it)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
OutlineTextField(
|
||||
label = "Value",
|
||||
value = value,
|
||||
onValueChange = {
|
||||
testPushClickIntents.onDataValueChange(index, it)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
when (swipeToDelete.currentValue) {
|
||||
SwipeToDismissBoxValue.EndToStart -> {
|
||||
LaunchedEffect(swipeToDelete) {
|
||||
testPushClickIntents.onDataRemove(index)
|
||||
swipeToDelete.snapTo(SwipeToDismissBoxValue.Settled)
|
||||
}
|
||||
}
|
||||
SwipeToDismissBoxValue.StartToEnd -> {}
|
||||
SwipeToDismissBoxValue.Settled -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SendLocalPushButton(testPushUM: TestPushUM) {
|
||||
val context = LocalContext.current
|
||||
|
||||
PrimaryButton(
|
||||
text = "Send test push",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
onClick = {
|
||||
val channelId = "Test Tangem Channel"
|
||||
|
||||
val intent = Intent(context, Class.forName("com.tangem.tap.MainActivity")).apply {
|
||||
testPushUM.data.forEach { (key, value) ->
|
||||
putExtra(key.text, value.text)
|
||||
}
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
}
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
/* context = */ context,
|
||||
/* requestCode = */ 1,
|
||||
/* intent = */ intent,
|
||||
/* flags = */ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
|
||||
)
|
||||
|
||||
val notificationBuilder =
|
||||
NotificationCompat.Builder(context.applicationContext, channelId)
|
||||
.setSmallIcon(com.tangem.feature.tester.impl.R.drawable.ic_tangem_24)
|
||||
.setContentTitle(testPushUM.title.text)
|
||||
.setContentText(testPushUM.message.text)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent)
|
||||
|
||||
val notificationManager =
|
||||
context.applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val notificationChannel = NotificationChannel(
|
||||
channelId,
|
||||
ContextCompat.getString(
|
||||
context.applicationContext,
|
||||
R.string.common_tangem_wallet,
|
||||
),
|
||||
NotificationManager.IMPORTANCE_HIGH,
|
||||
)
|
||||
notificationManager.createNotificationChannel(notificationChannel)
|
||||
}
|
||||
|
||||
// Generating unique notification id
|
||||
val uniqueId = (System.currentTimeMillis() % Integer.MAX_VALUE).toInt()
|
||||
|
||||
notificationManager.notify(
|
||||
/* id = */ uniqueId,
|
||||
/* notification = */ notificationBuilder.build(),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun TestPushScreen_Preview(@PreviewParameter(TestPushScreenPreviewProvider::class) params: TestPushUM) {
|
||||
TangemThemePreview {
|
||||
TestPushScreen(
|
||||
testPushUM = params,
|
||||
testPushClickIntents = object : TestPushClickIntents {
|
||||
override fun onTitleChange(value: TextFieldValue) {}
|
||||
override fun onMessageChange(value: TextFieldValue) {}
|
||||
override fun onDataKeyChange(index: Int, value: TextFieldValue) {}
|
||||
override fun onDataValueChange(index: Int, value: TextFieldValue) {}
|
||||
override fun onDataAdd() {}
|
||||
override fun onDataRemove(index: Int) {}
|
||||
override fun onBackClick() {}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class TestPushScreenPreviewProvider : PreviewParameterProvider<TestPushUM> {
|
||||
override val values: Sequence<TestPushUM>
|
||||
get() = sequenceOf(
|
||||
TestPushUM(
|
||||
fcmToken = "qwertyuiopoiuytrewqwertyuiopoiuytrewqertyuiop",
|
||||
title = TextFieldValue("Test push"),
|
||||
message = TextFieldValue("Test push"),
|
||||
data = listOf(
|
||||
TextFieldValue("deeplink") to TextFieldValue("tangem://main"),
|
||||
TextFieldValue("") to TextFieldValue(""),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.tangem.feature.tester.presentation.testpush.viewmodel
|
||||
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.feature.tester.presentation.navigation.InnerTesterRouter
|
||||
import com.tangem.feature.tester.presentation.testpush.entity.TestPushClickIntents
|
||||
import com.tangem.feature.tester.presentation.testpush.entity.TestPushUM
|
||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
internal class TestPushViewModel @Inject constructor(
|
||||
private val pushNotificationsTokenProvider: PushNotificationsTokenProvider,
|
||||
) : ViewModel(), TestPushClickIntents {
|
||||
|
||||
val uiState: StateFlow<TestPushUM>
|
||||
field = MutableStateFlow(
|
||||
TestPushUM(
|
||||
fcmToken = "",
|
||||
title = TextFieldValue(""),
|
||||
message = TextFieldValue(""),
|
||||
data = listOf(TextFieldValue("") to TextFieldValue("")),
|
||||
),
|
||||
)
|
||||
|
||||
private var router: InnerTesterRouter? = null
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
val fcmToken = pushNotificationsTokenProvider.getToken()
|
||||
uiState.update { it.copy(fcmToken = fcmToken) }
|
||||
}
|
||||
}
|
||||
|
||||
fun setupNavigation(router: InnerTesterRouter) {
|
||||
this.router = router
|
||||
}
|
||||
|
||||
override fun onTitleChange(value: TextFieldValue) {
|
||||
uiState.update { it.copy(title = value) }
|
||||
}
|
||||
|
||||
override fun onMessageChange(value: TextFieldValue) {
|
||||
uiState.update { it.copy(message = value) }
|
||||
}
|
||||
|
||||
override fun onDataKeyChange(index: Int, value: TextFieldValue) {
|
||||
val mutableData = uiState.value.data.toMutableList()
|
||||
val updated = mutableData[index].copy(first = value)
|
||||
mutableData.set(index = index, updated)
|
||||
|
||||
uiState.update {
|
||||
it.copy(data = mutableData)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDataValueChange(index: Int, value: TextFieldValue) {
|
||||
val mutableData = uiState.value.data.toMutableList()
|
||||
val updated = mutableData[index].copy(second = value)
|
||||
mutableData.set(index = index, updated)
|
||||
|
||||
uiState.update {
|
||||
it.copy(data = mutableData)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDataAdd() {
|
||||
uiState.update {
|
||||
it.copy(
|
||||
data = it.data.plus(TextFieldValue("") to TextFieldValue("")),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDataRemove(index: Int) {
|
||||
uiState.update {
|
||||
it.copy(
|
||||
data = it.data.toMutableList().apply {
|
||||
removeAt(index = index)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackClick() {
|
||||
router?.back()
|
||||
}
|
||||
}
|
||||
|
|
@ -14,4 +14,5 @@
|
|||
<string name="excluded_blockchains_search_placeholder" translatable="false">Filter by name or symbol</string>
|
||||
<string name="blockchain_providers" translatable="false">Blockchain providers</string>
|
||||
<string name="share_logs" translatable="false">Share logs</string>
|
||||
<string name="test_push" translatable="false">Test push</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue