Updated on 2026-08-14
This commit is contained in:
parent
34ee61553d
commit
aecd523c70
25 changed files with 1720 additions and 935 deletions
|
|
@ -1,27 +1,13 @@
|
||||||
package com.tangem.core.ui.ds2.button
|
package com.tangem.core.ui.ds2.button
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.*
|
||||||
import androidx.compose.animation.EnterTransition
|
|
||||||
import androidx.compose.animation.ExitTransition
|
|
||||||
import androidx.compose.animation.core.Spring
|
import androidx.compose.animation.core.Spring
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.core.spring
|
import androidx.compose.animation.core.spring
|
||||||
import androidx.compose.animation.expandHorizontally
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.foundation.text.TextAutoSize
|
||||||
import androidx.compose.animation.fadeOut
|
|
||||||
import androidx.compose.animation.shrinkHorizontally
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.widthIn
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
|
@ -38,11 +24,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.ui.ds.image.TangemIcon
|
import com.tangem.core.ui.ds.image.TangemIcon
|
||||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||||
import com.tangem.core.ui.ds2.loader.TangemLoader
|
import com.tangem.core.ui.ds2.loader.TangemLoader
|
||||||
import com.tangem.core.ui.extensions.ColorReference2
|
import com.tangem.core.ui.extensions.*
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
|
||||||
import com.tangem.core.ui.extensions.conditionalCompose
|
|
||||||
import com.tangem.core.ui.extensions.rememberLastNonNull
|
|
||||||
import com.tangem.core.ui.extensions.resolveReference
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -168,6 +150,10 @@ private fun ContentRow(
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
softWrap = false,
|
softWrap = false,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
autoSize = TextAutoSize.StepBased(
|
||||||
|
minFontSize = TangemTheme.typography3.caption.medium.fontSize,
|
||||||
|
maxFontSize = TangemTheme.typography3.body.medium.fontSize,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="20dp"
|
android:width="20dp"
|
||||||
android:height="20dp"
|
android:height="20dp"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="20dp"
|
android:width="20dp"
|
||||||
android:height="20dp"
|
android:height="20dp"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="20dp"
|
android:width="20dp"
|
||||||
android:height="20dp"
|
android:height="20dp"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="20dp"
|
android:width="20dp"
|
||||||
android:height="20dp"
|
android:height="20dp"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="32" android:viewportWidth="32" android:width="24dp">
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="32" android:viewportWidth="32" android:width="24dp">
|
||||||
|
|
||||||
<path android:fillColor="#EBEBEB" android:pathData="M16,23.697L22.663,27.802C23.715,28.45 25.011,27.488 24.733,26.268L22.964,18.528L28.852,13.321C29.78,12.5 29.284,10.944 28.061,10.838L20.31,10.167L17.278,2.864C16.799,1.712 15.201,1.712 14.722,2.864L11.69,10.167L3.939,10.838C2.716,10.944 2.22,12.5 3.148,13.321L9.036,18.528L7.267,26.268C6.988,27.488 8.285,28.45 9.336,27.802L16,23.697Z"/>
|
<path android:fillColor="#EBEBEB" android:pathData="M16,23.697L22.663,27.802C23.715,28.45 25.011,27.488 24.733,26.268L22.964,18.528L28.852,13.321C29.78,12.5 29.284,10.944 28.061,10.838L20.31,10.167L17.278,2.864C16.799,1.712 15.201,1.712 14.722,2.864L11.69,10.167L3.939,10.838C2.716,10.944 2.22,12.5 3.148,13.321L9.036,18.528L7.267,26.268C6.988,27.488 8.285,28.45 9.336,27.802L16,23.697Z"/>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:width="128dp"
|
android:width="128dp"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="22dp"
|
android:width="22dp"
|
||||||
android:height="8dp"
|
android:height="8dp"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2026 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="20dp"
|
android:width="20dp"
|
||||||
android:height="20dp"
|
android:height="20dp"
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,12 @@ import com.tangem.core.decompose.context.childByContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||||
import com.tangem.features.tokenreceive.model.TokenReceiveModel
|
import com.tangem.features.tokenreceive.model.TokenReceiveModel
|
||||||
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveContentSheet
|
import com.tangem.features.tokenreceive.ui.TokenReceiveContentSheet
|
||||||
|
import com.tangem.features.tokenreceive.ui.TokenReceiveContentSheetLegacy
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
|
|
@ -43,13 +45,21 @@ internal class DefaultTokenReceiveComponent @AssistedInject constructor(
|
||||||
override fun BottomSheet() {
|
override fun BottomSheet() {
|
||||||
val content by contentStack.subscribeAsState()
|
val content by contentStack.subscribeAsState()
|
||||||
val currentRoute = content.active.configuration
|
val currentRoute = content.active.configuration
|
||||||
|
if (LocalRedesignEnabled.current) {
|
||||||
TokenReceiveContentSheet(
|
TokenReceiveContentSheet(
|
||||||
route = currentRoute,
|
route = currentRoute,
|
||||||
onCloseClick = ::dismiss,
|
onCloseClick = ::dismiss,
|
||||||
onBackClick = ::onChildBack,
|
onBackClick = ::onChildBack,
|
||||||
contentStack = content,
|
contentStack = content,
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
TokenReceiveContentSheetLegacy(
|
||||||
|
route = currentRoute,
|
||||||
|
onCloseClick = ::dismiss,
|
||||||
|
onBackClick = ::onChildBack,
|
||||||
|
contentStack = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dismiss() = model.params.onDismiss()
|
override fun dismiss() = model.params.onDismiss()
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@ import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||||
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
|
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
|
||||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||||
import com.tangem.features.tokenreceive.model.TokenReceiveAssetsModel
|
import com.tangem.features.tokenreceive.model.TokenReceiveAssetsModel
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveAssetsContent
|
import com.tangem.features.tokenreceive.ui.TokenReceiveAssetsContent
|
||||||
|
import com.tangem.features.tokenreceive.ui.TokenReceiveAssetsContentLegacy
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
internal class TokenReceiveAssetsComponent(
|
internal class TokenReceiveAssetsComponent(
|
||||||
|
|
@ -25,7 +27,11 @@ internal class TokenReceiveAssetsComponent(
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.state.collectAsStateWithLifecycle()
|
val state by model.state.collectAsStateWithLifecycle()
|
||||||
TokenReceiveAssetsContent(assetsUM = state)
|
if (LocalRedesignEnabled.current) {
|
||||||
|
TokenReceiveAssetsContent(assetsUM = state)
|
||||||
|
} else {
|
||||||
|
TokenReceiveAssetsContentLegacy(assetsUM = state)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface TokenReceiveAssetsModelCallback {
|
internal interface TokenReceiveAssetsModelCallback {
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||||
import com.tangem.domain.models.TokenReceiveType
|
import com.tangem.domain.models.TokenReceiveType
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
|
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
|
||||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||||
import com.tangem.features.tokenreceive.model.TokenReceiveQrCodeModel
|
import com.tangem.features.tokenreceive.model.TokenReceiveQrCodeModel
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveQrCodeContent
|
import com.tangem.features.tokenreceive.ui.TokenReceiveQrCodeContent
|
||||||
|
import com.tangem.features.tokenreceive.ui.TokenReceiveQrCodeContentLegacy
|
||||||
|
|
||||||
internal class TokenReceiveQrCodeComponent(
|
internal class TokenReceiveQrCodeComponent(
|
||||||
appComponentContext: AppComponentContext,
|
appComponentContext: AppComponentContext,
|
||||||
|
|
@ -24,7 +26,11 @@ internal class TokenReceiveQrCodeComponent(
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.state.collectAsStateWithLifecycle()
|
val state by model.state.collectAsStateWithLifecycle()
|
||||||
TokenReceiveQrCodeContent(qrCodeUM = state)
|
if (LocalRedesignEnabled.current) {
|
||||||
|
TokenReceiveQrCodeContent(qrCodeUM = state)
|
||||||
|
} else {
|
||||||
|
TokenReceiveQrCodeContentLegacy(qrCodeUM = state)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface TokenReceiveQrCodeModelCallback {
|
internal interface TokenReceiveQrCodeModelCallback {
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@ import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.features.tokenreceive.model.TokenReceiveWarningModel
|
import com.tangem.features.tokenreceive.model.TokenReceiveWarningModel
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveWarningContent
|
import com.tangem.features.tokenreceive.ui.TokenReceiveWarningContent
|
||||||
|
import com.tangem.features.tokenreceive.ui.TokenReceiveWarningContentLegacy
|
||||||
|
|
||||||
internal class TokenReceiveWarningComponent(
|
internal class TokenReceiveWarningComponent(
|
||||||
appComponentContext: AppComponentContext,
|
appComponentContext: AppComponentContext,
|
||||||
|
|
@ -22,7 +24,11 @@ internal class TokenReceiveWarningComponent(
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.state.collectAsStateWithLifecycle()
|
val state by model.state.collectAsStateWithLifecycle()
|
||||||
TokenReceiveWarningContent(warningUM = state)
|
if (LocalRedesignEnabled.current) {
|
||||||
|
TokenReceiveWarningContent(warningUM = state)
|
||||||
|
} else {
|
||||||
|
TokenReceiveWarningContentLegacy(warningUM = state)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface TokenReceiveWarningModelCallback {
|
internal interface TokenReceiveWarningModelCallback {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ internal data class ReceiveAddress(
|
||||||
sealed interface Type {
|
sealed interface Type {
|
||||||
data object Ens : Type
|
data object Ens : Type
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface Primary : Type {
|
sealed interface Primary : Type {
|
||||||
|
|
||||||
val displayName: TextReference
|
val displayName: TextReference
|
||||||
|
|
|
||||||
|
|
@ -1,97 +1,379 @@
|
||||||
package com.tangem.features.tokenreceive.ui
|
package com.tangem.features.tokenreceive.ui
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.animation.animateColorAsState
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.TextAutoSize
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.key
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
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.ImageVector
|
||||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.compose.ui.util.fastFilter
|
import androidx.compose.ui.util.fastFilter
|
||||||
import androidx.compose.ui.util.fastForEach
|
import androidx.compose.ui.util.fastForEach
|
||||||
import com.tangem.common.ui.notifications.NotificationUM
|
import com.tangem.common.ui.notifications.NotificationUM
|
||||||
import com.tangem.core.res.getStringSafe
|
|
||||||
import com.tangem.core.ui.R
|
import com.tangem.core.ui.R
|
||||||
import com.tangem.core.ui.components.*
|
import com.tangem.core.ui.components.SpacerH
|
||||||
import com.tangem.core.ui.components.atoms.text.EllipsisText
|
import com.tangem.core.ui.components.SpacerH8
|
||||||
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
import com.tangem.core.ui.components.SpacerW
|
||||||
import com.tangem.core.ui.components.buttons.actions.ActionBaseButton
|
|
||||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
|
||||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonContent
|
|
||||||
import com.tangem.core.ui.components.buttons.small.TangemIconButton
|
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
import com.tangem.core.ui.components.notifications.Notification
|
import com.tangem.core.ui.ds.TangemPagerIndicator
|
||||||
|
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||||
|
import com.tangem.core.ui.ds.message.TangemMessage
|
||||||
|
import com.tangem.core.ui.ds2.badge.TangemBadge
|
||||||
|
import com.tangem.core.ui.ds2.button.TangemButton
|
||||||
|
import com.tangem.core.ui.ds2.loader.TangemLoader
|
||||||
|
import com.tangem.core.ui.ds2.loader.TangemLoaderSize
|
||||||
import com.tangem.core.ui.extensions.*
|
import com.tangem.core.ui.extensions.*
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
|
||||||
import com.tangem.core.ui.res.LocalTopSnackbarHostState
|
import com.tangem.core.ui.res.LocalTopSnackbarHostState
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||||
|
import com.tangem.core.ui.res.generated.icons.Icons
|
||||||
|
import com.tangem.core.ui.res.generated.icons.ic_copy_24
|
||||||
|
import com.tangem.core.ui.res.generated.icons.ic_share_android_24
|
||||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||||
import com.tangem.features.tokenreceive.ui.state.ReceiveAssetsUM
|
import com.tangem.features.tokenreceive.ui.state.ReceiveAssetsUM
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TokenReceiveAssetsContent(assetsUM: ReceiveAssetsUM) {
|
internal fun TokenReceiveAssetsContent(assetsUM: ReceiveAssetsUM) {
|
||||||
val snackbarHostState = remember(::SnackbarHostState)
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
if (assetsUM.isEnsResultLoading) {
|
||||||
|
LoadingBlock(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.padding(bottom = 8.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AddressBlock(assetsUM = assetsUM)
|
||||||
|
SpacerH(16.dp)
|
||||||
|
Info(
|
||||||
|
showMemoDisclaimer = assetsUM.showMemoDisclaimer,
|
||||||
|
notificationConfigs = assetsUM.notificationConfigs,
|
||||||
|
currencyIconState = assetsUM.currencyIconState,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ContainerWithSnackbarHost(snackbarHostState = snackbarHostState) {
|
@Composable
|
||||||
Column(
|
private fun LoadingBlock(modifier: Modifier = Modifier) {
|
||||||
|
Card(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(24.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors3.bg.opaque.primary),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(color = TangemTheme.colors.background.tertiary)
|
.heightIn(min = 68.dp),
|
||||||
.padding(bottom = 16.dp),
|
contentAlignment = Alignment.Center,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
) {
|
||||||
AddressBlock(
|
TangemLoader(
|
||||||
assetsUM = assetsUM,
|
color = TangemTheme.colors3.icon.secondary,
|
||||||
snackbarHostState = snackbarHostState,
|
size = TangemLoaderSize.X28,
|
||||||
)
|
|
||||||
|
|
||||||
if (assetsUM.isEnsResultLoading) {
|
|
||||||
SpacerH8()
|
|
||||||
LoadingBlock(modifier = Modifier.padding(horizontal = 16.dp))
|
|
||||||
}
|
|
||||||
|
|
||||||
SpacerH12()
|
|
||||||
|
|
||||||
Info(
|
|
||||||
showMemoDisclaimer = assetsUM.showMemoDisclaimer,
|
|
||||||
notificationConfigs = assetsUM.notificationConfigs,
|
|
||||||
currencyIconState = assetsUM.currencyIconState,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun AddressBlock(assetsUM: ReceiveAssetsUM) {
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
||||||
|
|
||||||
|
assetsUM.addresses
|
||||||
|
.fastFilter { it.type is ReceiveAddress.Type.Ens }
|
||||||
|
.fastForEach { address ->
|
||||||
|
key(address.value) {
|
||||||
|
EnsItem(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
onCopyClick = {
|
||||||
|
assetsUM.onCopyClick(address)
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
coroutineScope.launch {
|
||||||
|
topSnackbarHostState.showSnackbar(
|
||||||
|
SnackbarMessage(
|
||||||
|
startIconId = R.drawable.ic_check_24,
|
||||||
|
message = resourceReference(R.string.wallet_notification_address_copied),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
address = address.value,
|
||||||
|
)
|
||||||
|
SpacerH8()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimaryAddressesItems(
|
||||||
|
addresses = assetsUM.addresses.fastFilter { it.type is ReceiveAddress.Type.Primary }.toImmutableList(),
|
||||||
|
currencyIconState = assetsUM.currencyIconState,
|
||||||
|
onShareClick = {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
assetsUM.onShareClick(it)
|
||||||
|
},
|
||||||
|
onCopyClick = { address ->
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
coroutineScope.launch {
|
||||||
|
topSnackbarHostState.showSnackbar(
|
||||||
|
SnackbarMessage(message = resourceReference(R.string.wallet_notification_address_copied)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
assetsUM.onCopyClick(address)
|
||||||
|
},
|
||||||
|
onOpenQrCodeClick = { address ->
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
assetsUM.onOpenQrCodeClick(address)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
@Composable
|
||||||
|
private fun PrimaryAddressesItems(
|
||||||
|
addresses: ImmutableList<ReceiveAddress>,
|
||||||
|
currencyIconState: CurrencyIconState,
|
||||||
|
onShareClick: (String) -> Unit,
|
||||||
|
onCopyClick: (ReceiveAddress) -> Unit,
|
||||||
|
onOpenQrCodeClick: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
if (addresses.isEmpty()) return
|
||||||
|
val pagerState = rememberPagerState(
|
||||||
|
initialPage = 0,
|
||||||
|
initialPageOffsetFraction = 0f,
|
||||||
|
pageCount = addresses::count,
|
||||||
|
)
|
||||||
|
|
||||||
|
HorizontalPager(
|
||||||
|
state = pagerState,
|
||||||
|
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||||
|
pageSpacing = 16.dp,
|
||||||
|
) { page ->
|
||||||
|
val address = addresses[page]
|
||||||
|
AddressItem(
|
||||||
|
currencyIconState = currencyIconState,
|
||||||
|
onOpenQrCodeClick = { onOpenQrCodeClick(address.value) },
|
||||||
|
onCopyClick = { onCopyClick(address) },
|
||||||
|
onShareClick = { onShareClick(address.value) },
|
||||||
|
primaryType = address.type as ReceiveAddress.Type.Primary,
|
||||||
|
address = address.value,
|
||||||
|
isDynamicAddress = address.type is ReceiveAddress.Type.Primary.Dynamic,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SpacerH(8.dp)
|
||||||
|
if (addresses.size > 1) {
|
||||||
|
TangemPagerIndicator(pagerState = pagerState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
@Composable
|
||||||
|
private fun AddressItem(
|
||||||
|
currencyIconState: CurrencyIconState,
|
||||||
|
onOpenQrCodeClick: () -> Unit,
|
||||||
|
onCopyClick: () -> Unit,
|
||||||
|
onShareClick: () -> Unit,
|
||||||
|
primaryType: ReceiveAddress.Type.Primary,
|
||||||
|
address: String,
|
||||||
|
isDynamicAddress: Boolean,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickableSingle(onClick = onOpenQrCodeClick)
|
||||||
|
.padding(horizontal = 12.dp, vertical = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
CurrencyIcon(
|
||||||
|
modifier = Modifier.size(60.dp),
|
||||||
|
state = currencyIconState,
|
||||||
|
shouldDisplayNetwork = true,
|
||||||
|
iconSize = 56.dp,
|
||||||
|
networkBadgeSize = 20.dp,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(12.dp)
|
||||||
|
|
||||||
|
if (isDynamicAddress) {
|
||||||
|
DynamicAddressBadge(modifier = Modifier.padding(vertical = 4.dp))
|
||||||
|
SpacerH(12.dp)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = primaryType.displayName.resolveReference(),
|
||||||
|
color = TangemTheme.colors3.text.primary,
|
||||||
|
style = TangemTheme.typography3.body.medium,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(4.dp)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.heightIn(min = 40.dp)
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
text = address,
|
||||||
|
color = TangemTheme.colors3.text.secondary,
|
||||||
|
style = TangemTheme.typography3.caption.medium,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(8.dp)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickableSingle(onClick = onOpenQrCodeClick)
|
||||||
|
.padding(10.dp),
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
imageVector = ImageVector.vectorResource(R.drawable.ic_qrcode_new_24),
|
||||||
|
tint = TangemTheme.colors3.icon.primary,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerW(6.dp)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResourceSafe(R.string.token_receive_show_qr_code_title),
|
||||||
|
style = TangemTheme.typography3.body.medium,
|
||||||
|
color = TangemTheme.colors3.text.primary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH(20.dp)
|
||||||
|
|
||||||
|
ButtonsBlock(
|
||||||
|
onCopyClick = onCopyClick,
|
||||||
|
onShareClick = onShareClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ButtonsBlock(onCopyClick: () -> Unit, onShareClick: () -> Unit) {
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.width(IntrinsicSize.Min),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
TangemButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = {
|
||||||
|
onCopyClick()
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
coroutineScope.launch {
|
||||||
|
topSnackbarHostState.showSnackbar(
|
||||||
|
SnackbarMessage(
|
||||||
|
startIconId = R.drawable.ic_check_24,
|
||||||
|
message = resourceReference(R.string.wallet_notification_address_copied),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
iconStart = TangemIconUM.Icon(imageVector = Icons.ic_copy_24),
|
||||||
|
variant = TangemButton.Variant.Secondary,
|
||||||
|
size = TangemButton.Size.X12,
|
||||||
|
text = TextReference.Res(id = R.string.common_copy),
|
||||||
|
)
|
||||||
|
|
||||||
|
TangemButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
onShareClick()
|
||||||
|
},
|
||||||
|
iconStart = TangemIconUM.Icon(imageVector = Icons.ic_share_android_24),
|
||||||
|
variant = TangemButton.Variant.Secondary,
|
||||||
|
size = TangemButton.Size.X12,
|
||||||
|
text = TextReference.Res(id = R.string.common_share),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun EnsItem(onCopyClick: () -> Unit, address: String, modifier: Modifier = Modifier) {
|
||||||
|
Card(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(24.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors3.bg.opaque.primary),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
modifier = Modifier.size(36.dp),
|
||||||
|
imageVector = ImageVector.vectorResource(R.drawable.ic_ens_36),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
SpacerW(12.dp)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
text = address,
|
||||||
|
color = TangemTheme.colors3.text.primary,
|
||||||
|
style = TangemTheme.typography3.body.medium,
|
||||||
|
overflow = TextOverflow.MiddleEllipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
TangemButton(
|
||||||
|
modifier = Modifier.padding(start = 12.dp),
|
||||||
|
onClick = onCopyClick,
|
||||||
|
iconStart = TangemIconUM.Icon(imageVector = Icons.ic_share_android_24),
|
||||||
|
size = TangemButton.Size.X9,
|
||||||
|
variant = TangemButton.Variant.Secondary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DynamicAddressBadge(modifier: Modifier = Modifier) {
|
||||||
|
TangemBadge(
|
||||||
|
modifier = modifier,
|
||||||
|
text = resourceReference(R.string.dynamic_addresses_receive_badge),
|
||||||
|
iconStart = TangemIconUM.Icon(iconRes = R.drawable.ic_dynamic_addresses_badge_16),
|
||||||
|
status = TangemBadge.Status.Info,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Info(
|
private fun Info(
|
||||||
currencyIconState: CurrencyIconState,
|
currencyIconState: CurrencyIconState,
|
||||||
|
|
@ -110,227 +392,52 @@ private fun Info(
|
||||||
.padding(horizontal = 18.dp)
|
.padding(horizontal = 18.dp)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
text = stringResourceSafe(R.string.receive_bottom_sheet_no_memo_required_message),
|
text = stringResourceSafe(R.string.receive_bottom_sheet_no_memo_required_message),
|
||||||
style = TangemTheme.typography.caption1,
|
style = TangemTheme.typography3.caption.medium,
|
||||||
color = TangemTheme.colors.text.tertiary,
|
color = TangemTheme.colors3.text.tertiary,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationConfigs.fastForEach { notificationConfig ->
|
notificationConfigs.fastForEach { notificationConfig ->
|
||||||
key(notificationConfig.hashCode()) {
|
key(notificationConfig.hashCode()) {
|
||||||
// TODO remove after new design system
|
|
||||||
if (notificationConfig is NotificationUM.Warning.YieldSupplyIsActive) {
|
if (notificationConfig is NotificationUM.Warning.YieldSupplyIsActive) {
|
||||||
YieldSupplyDepositedWarning(
|
TangemMessage(
|
||||||
currencyIconState = currencyIconState,
|
title = resourceReference(
|
||||||
title = stringResourceSafe(
|
id = R.string.yield_module_balance_info_sheet_title,
|
||||||
R.string.yield_module_balance_info_sheet_title,
|
formatArgs = wrappedList(notificationConfig.tokenName),
|
||||||
notificationConfig.tokenName,
|
|
||||||
),
|
),
|
||||||
subtitle = stringResourceSafe(R.string.yield_module_balance_info_sheet_subtitle),
|
subtitle = resourceReference(R.string.yield_module_balance_info_sheet_subtitle),
|
||||||
)
|
leadingContent = {
|
||||||
} else {
|
Box(
|
||||||
Notification(config = notificationConfig.config)
|
modifier = Modifier
|
||||||
}
|
.height(22.dp)
|
||||||
}
|
.width(22.dp),
|
||||||
}
|
contentAlignment = Alignment.TopStart,
|
||||||
}
|
) {
|
||||||
}
|
CurrencyIcon(
|
||||||
|
modifier = Modifier
|
||||||
@Composable
|
.align(Alignment.TopStart)
|
||||||
private fun YieldSupplyDepositedWarning(
|
.size(13.dp),
|
||||||
currencyIconState: CurrencyIconState,
|
state = currencyIconState,
|
||||||
title: String,
|
shouldDisplayNetwork = false,
|
||||||
subtitle: String,
|
iconSize = 13.dp,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
Surface(
|
|
||||||
modifier = modifier
|
|
||||||
.defaultMinSize(minHeight = TangemTheme.dimens.size44)
|
|
||||||
.fillMaxWidth(),
|
|
||||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
|
||||||
color = TangemTheme.colors.button.disabled,
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(all = TangemTheme.dimens.spacing12),
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.height(22.dp)
|
|
||||||
.width(22.dp),
|
|
||||||
contentAlignment = Alignment.TopStart,
|
|
||||||
) {
|
|
||||||
CurrencyIcon(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.TopStart)
|
|
||||||
.size(13.dp),
|
|
||||||
state = currencyIconState,
|
|
||||||
shouldDisplayNetwork = false,
|
|
||||||
iconSize = 13.dp,
|
|
||||||
)
|
|
||||||
|
|
||||||
Image(
|
|
||||||
modifier = Modifier
|
|
||||||
.background(TangemTheme.colors.background.tertiary, RoundedCornerShape(15.dp))
|
|
||||||
.padding(1.dp)
|
|
||||||
.size(15.dp)
|
|
||||||
.align(Alignment.BottomEnd),
|
|
||||||
imageVector = ImageVector.vectorResource(R.drawable.img_aave_22),
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SpacerW(width = TangemTheme.dimens.spacing8)
|
|
||||||
|
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
color = TangemTheme.colors.text.primary1,
|
|
||||||
style = TangemTheme.typography.button,
|
|
||||||
)
|
|
||||||
|
|
||||||
SpacerH(height = TangemTheme.dimens.spacing2)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = subtitle,
|
|
||||||
color = TangemTheme.colors.text.tertiary,
|
|
||||||
style = TangemTheme.typography.caption2,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun AddressBlock(assetsUM: ReceiveAssetsUM, snackbarHostState: SnackbarHostState) {
|
|
||||||
val hapticFeedback = LocalHapticFeedback.current
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val context = LocalContext.current
|
|
||||||
val resources = context.resources
|
|
||||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
|
||||||
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
|
||||||
|
|
||||||
assetsUM.addresses
|
|
||||||
.fastFilter { it.type is ReceiveAddress.Type.Ens }
|
|
||||||
.fastForEach { address ->
|
|
||||||
key(address.value) {
|
|
||||||
EnsItem(
|
|
||||||
modifier = Modifier.padding(horizontal = 16.dp),
|
|
||||||
onCopyClick = {
|
|
||||||
assetsUM.onCopyClick(address)
|
|
||||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
|
||||||
coroutineScope.launch {
|
|
||||||
if (isRedesignEnabled) {
|
|
||||||
topSnackbarHostState.showSnackbar(
|
|
||||||
SnackbarMessage(
|
|
||||||
startIconId = R.drawable.ic_check_24,
|
|
||||||
message = resourceReference(R.string.wallet_notification_address_copied),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
} else {
|
Image(
|
||||||
snackbarHostState.showSnackbar(
|
modifier = Modifier
|
||||||
message = resources.getStringSafe(
|
.background(TangemTheme.colors.background.tertiary, RoundedCornerShape(15.dp))
|
||||||
R.string.wallet_notification_address_copied,
|
.padding(1.dp)
|
||||||
),
|
.size(15.dp)
|
||||||
|
.align(Alignment.BottomEnd),
|
||||||
|
imageVector = ImageVector.vectorResource(R.drawable.img_aave_22),
|
||||||
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
|
||||||
address = address.value,
|
|
||||||
)
|
|
||||||
SpacerH8()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimaryAddressesItems(
|
|
||||||
addresses = assetsUM.addresses.fastFilter { it.type is ReceiveAddress.Type.Primary }.toImmutableList(),
|
|
||||||
currencyIconState = assetsUM.currencyIconState,
|
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
onShareClick = {
|
|
||||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
|
||||||
assetsUM.onShareClick(it)
|
|
||||||
},
|
|
||||||
onCopyClick = {
|
|
||||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
|
||||||
coroutineScope.launch {
|
|
||||||
snackbarHostState.showSnackbar(
|
|
||||||
message = resources.getStringSafe(
|
|
||||||
R.string.wallet_notification_address_copied,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
assetsUM.onCopyClick(it)
|
|
||||||
},
|
|
||||||
onOpenQrCodeClick = {
|
|
||||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
|
||||||
assetsUM.onOpenQrCodeClick(it)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
@Composable
|
|
||||||
private fun PrimaryAddressesItems(
|
|
||||||
addresses: ImmutableList<ReceiveAddress>,
|
|
||||||
currencyIconState: CurrencyIconState,
|
|
||||||
snackbarHostState: SnackbarHostState,
|
|
||||||
onShareClick: (String) -> Unit,
|
|
||||||
onCopyClick: (ReceiveAddress) -> Unit,
|
|
||||||
onOpenQrCodeClick: (String) -> Unit,
|
|
||||||
) {
|
|
||||||
if (addresses.isEmpty()) return
|
|
||||||
var selectedAddress by remember { mutableStateOf(addresses.first()) }
|
|
||||||
val pagerState = rememberPagerState(
|
|
||||||
initialPage = 0,
|
|
||||||
initialPageOffsetFraction = 0f,
|
|
||||||
pageCount = addresses::count,
|
|
||||||
)
|
|
||||||
LaunchedEffect(key1 = pagerState.currentPage) {
|
|
||||||
selectedAddress = addresses[pagerState.currentPage]
|
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalPager(
|
|
||||||
state = pagerState,
|
|
||||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
|
||||||
pageSpacing = 16.dp,
|
|
||||||
) {
|
|
||||||
AddressItem(
|
|
||||||
currencyIconState = currencyIconState,
|
|
||||||
onOpenQrCodeClick = { onOpenQrCodeClick(selectedAddress.value) },
|
|
||||||
onCopyClick = { onCopyClick(selectedAddress) },
|
|
||||||
onShareClick = { onShareClick(selectedAddress.value) },
|
|
||||||
primaryType = selectedAddress.type as ReceiveAddress.Type.Primary,
|
|
||||||
address = selectedAddress.value,
|
|
||||||
isDynamicAddress = selectedAddress.type is ReceiveAddress.Type.Primary.Dynamic,
|
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SpacerH(4.dp)
|
|
||||||
|
|
||||||
if (pagerState.pageCount > 1) {
|
|
||||||
val indicatorState = rememberLazyListState()
|
|
||||||
val selectedColor = TangemTheme.colors.icon.primary1
|
|
||||||
val unselectedColor = TangemTheme.colors.icon.informative
|
|
||||||
|
|
||||||
LazyRow(
|
|
||||||
modifier = Modifier.height(20.dp),
|
|
||||||
state = indicatorState,
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
repeat(pagerState.pageCount) { iteration ->
|
|
||||||
item(key = iteration) {
|
|
||||||
val color by animateColorAsState(
|
|
||||||
targetValue = if (pagerState.currentPage == iteration) selectedColor else unselectedColor,
|
|
||||||
label = "",
|
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
Box(
|
TangemMessage(
|
||||||
modifier = Modifier
|
config = notificationConfig.config,
|
||||||
.padding(horizontal = 4.dp, vertical = 6.dp)
|
contentColor = Color.Transparent,
|
||||||
.background(color = color, shape = CircleShape)
|
|
||||||
.size(7.dp),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -338,308 +445,13 @@ private fun PrimaryAddressesItems(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
@Composable
|
|
||||||
private fun AddressItem(
|
|
||||||
currencyIconState: CurrencyIconState,
|
|
||||||
onOpenQrCodeClick: () -> Unit,
|
|
||||||
onCopyClick: () -> Unit,
|
|
||||||
onShareClick: () -> Unit,
|
|
||||||
primaryType: ReceiveAddress.Type.Primary,
|
|
||||||
address: String,
|
|
||||||
isDynamicAddress: Boolean,
|
|
||||||
snackbarHostState: SnackbarHostState,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
Card(
|
|
||||||
modifier = modifier.fillMaxWidth(),
|
|
||||||
shape = RoundedCornerShape(16.dp),
|
|
||||||
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors.background.action),
|
|
||||||
onClick = onOpenQrCodeClick,
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 12.dp, vertical = 32.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
CurrencyIcon(
|
|
||||||
modifier = Modifier.size(56.dp),
|
|
||||||
state = currencyIconState,
|
|
||||||
shouldDisplayNetwork = true,
|
|
||||||
iconSize = 56.dp,
|
|
||||||
)
|
|
||||||
|
|
||||||
SpacerH(12.dp)
|
|
||||||
|
|
||||||
if (isDynamicAddress) {
|
|
||||||
DynamicAddressBadge()
|
|
||||||
SpacerH(8.dp)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = primaryType.displayName.resolveReference(),
|
|
||||||
color = TangemTheme.colors.text.primary1,
|
|
||||||
style = TangemTheme.typography.subtitle1,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.heightIn(min = 40.dp)
|
|
||||||
.padding(horizontal = 16.dp),
|
|
||||||
text = address,
|
|
||||||
color = TangemTheme.colors.text.tertiary,
|
|
||||||
style = TangemTheme.typography.body2,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
|
|
||||||
SpacerH8()
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.clip(RoundedCornerShape(16.dp))
|
|
||||||
.clickable(onClick = onOpenQrCodeClick)
|
|
||||||
.padding(vertical = 6.dp, horizontal = 12.dp),
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier.size(16.dp),
|
|
||||||
imageVector = ImageVector.vectorResource(R.drawable.ic_qrcode_new_24),
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
SpacerW(4.dp)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = stringResourceSafe(R.string.token_receive_show_qr_code_title),
|
|
||||||
style = TangemTheme.typography.caption1,
|
|
||||||
color = TangemTheme.colors.text.secondary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SpacerH(20.dp)
|
|
||||||
|
|
||||||
ButtonsBlock(
|
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
onCopyClick = onCopyClick,
|
|
||||||
onShareClick = onShareClick,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ButtonsBlock(snackbarHostState: SnackbarHostState, onCopyClick: () -> Unit, onShareClick: () -> Unit) {
|
|
||||||
val hapticFeedback = LocalHapticFeedback.current
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val context = LocalContext.current
|
|
||||||
val resources = context.resources
|
|
||||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
|
||||||
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.width(IntrinsicSize.Min),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
) {
|
|
||||||
ActionButtonWithResizableText(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
config = ActionButtonConfig(
|
|
||||||
text = TextReference.Res(id = R.string.common_copy),
|
|
||||||
iconResId = R.drawable.ic_copy_new_24,
|
|
||||||
onClick = {
|
|
||||||
onCopyClick()
|
|
||||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
|
||||||
coroutineScope.launch {
|
|
||||||
if (isRedesignEnabled) {
|
|
||||||
topSnackbarHostState.showSnackbar(
|
|
||||||
SnackbarMessage(
|
|
||||||
startIconId = R.drawable.ic_check_24,
|
|
||||||
message = resourceReference(R.string.wallet_notification_address_copied),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
snackbarHostState.showSnackbar(
|
|
||||||
message = resources.getStringSafe(R.string.wallet_notification_address_copied),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
ActionButtonWithResizableText(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
config = ActionButtonConfig(
|
|
||||||
text = TextReference.Res(id = R.string.common_share),
|
|
||||||
iconResId = R.drawable.ic_share_24,
|
|
||||||
onClick = {
|
|
||||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
|
||||||
onShareClick()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun EnsItem(onCopyClick: () -> Unit, address: String, modifier: Modifier = Modifier) {
|
|
||||||
Card(
|
|
||||||
modifier = modifier.fillMaxWidth(),
|
|
||||||
shape = RoundedCornerShape(16.dp),
|
|
||||||
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors.background.action),
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 14.dp, horizontal = 12.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier.size(36.dp),
|
|
||||||
imageVector = ImageVector.vectorResource(R.drawable.ic_ens_36),
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
SpacerW12()
|
|
||||||
|
|
||||||
EllipsisText(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
text = address,
|
|
||||||
ellipsis = TextEllipsis.Middle,
|
|
||||||
color = TangemTheme.colors.text.primary1,
|
|
||||||
style = TangemTheme.typography.subtitle1,
|
|
||||||
)
|
|
||||||
|
|
||||||
TangemIconButton(
|
|
||||||
modifier = Modifier.size(TangemTheme.dimens.size28),
|
|
||||||
iconRes = R.drawable.ic_share_24,
|
|
||||||
innerPadding = 6.dp,
|
|
||||||
onClick = onCopyClick,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun LoadingBlock(modifier: Modifier = Modifier) {
|
|
||||||
Card(
|
|
||||||
modifier = modifier.fillMaxWidth(),
|
|
||||||
shape = RoundedCornerShape(16.dp),
|
|
||||||
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors.background.action),
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.heightIn(min = 64.dp),
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
|
||||||
CircularProgressIndicator(
|
|
||||||
color = TangemTheme.colors.icon.informative,
|
|
||||||
modifier = Modifier.padding(TangemTheme.dimens.spacing8),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ActionButtonWithResizableText(config: ActionButtonConfig, modifier: Modifier = Modifier) {
|
|
||||||
ActionBaseButton(
|
|
||||||
config = config,
|
|
||||||
shape = RoundedCornerShape(size = TangemTheme.dimens.radius24),
|
|
||||||
content = { contentModifier ->
|
|
||||||
ActionButtonContent(
|
|
||||||
config = config,
|
|
||||||
text = { color ->
|
|
||||||
Text(
|
|
||||||
text = config.text.resolveReference(),
|
|
||||||
autoSize = TextAutoSize.StepBased(
|
|
||||||
minFontSize = 10.sp,
|
|
||||||
maxFontSize = TangemTheme.typography.button.fontSize,
|
|
||||||
),
|
|
||||||
color = color,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
maxLines = 1,
|
|
||||||
style = TangemTheme.typography.button,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = contentModifier.padding(horizontal = 16.dp),
|
|
||||||
paddingBetweenIconAndText = 4.dp,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = modifier,
|
|
||||||
color = TangemTheme.colors.button.secondary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun DynamicAddressBadge(modifier: Modifier = Modifier) {
|
|
||||||
Row(
|
|
||||||
modifier = modifier
|
|
||||||
.background(
|
|
||||||
color = TangemTheme.colors.text.accent.copy(alpha = 0.1f),
|
|
||||||
shape = RoundedCornerShape(percent = 50),
|
|
||||||
)
|
|
||||||
.padding(horizontal = 12.dp, vertical = 4.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(
|
|
||||||
id = R.drawable.ic_dynamic_addresses_badge_16,
|
|
||||||
),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.size(16.dp),
|
|
||||||
tint = TangemTheme.colors.icon.accent,
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = stringResourceSafe(R.string.dynamic_addresses_receive_badge),
|
|
||||||
style = TangemTheme.typography.caption1,
|
|
||||||
color = TangemTheme.colors.text.accent,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@Preview(showBackground = true, widthDp = 360)
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
private fun Preview_TokenReceiveAssetsContent(
|
private fun Preview_TokenReceiveAssetsContent(
|
||||||
@PreviewParameter(TokenReceiveAssetsContentProvider::class) params: ReceiveAssetsUM,
|
@PreviewParameter(TokenReceiveAssetsContentProvider::class) params: ReceiveAssetsUM,
|
||||||
) {
|
) {
|
||||||
TangemThemePreview {
|
TangemThemePreviewRedesign {
|
||||||
TokenReceiveAssetsContent(assetsUM = params)
|
TokenReceiveAssetsContent(assetsUM = params)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class TokenReceiveAssetsContentProvider : PreviewParameterProvider<ReceiveAssetsUM> {
|
|
||||||
val address = ReceiveAddress(
|
|
||||||
value = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
|
|
||||||
type = ReceiveAddress.Type.Primary.Default(
|
|
||||||
displayName = stringReference("Etherium address"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
private val config = ReceiveAssetsUM(
|
|
||||||
notificationConfigs =
|
|
||||||
persistentListOf(
|
|
||||||
NotificationUM.Warning(
|
|
||||||
title = stringReference("Send only XLM on the Ethereum network"),
|
|
||||||
subtitle = resourceReference(R.string.receive_bottom_sheet_warning_message_description),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
addresses = persistentListOf(
|
|
||||||
address,
|
|
||||||
address,
|
|
||||||
address.copy(type = ReceiveAddress.Type.Ens, value = "papasha.eth"),
|
|
||||||
),
|
|
||||||
showMemoDisclaimer = false,
|
|
||||||
onCopyClick = {},
|
|
||||||
onOpenQrCodeClick = {},
|
|
||||||
isEnsResultLoading = true,
|
|
||||||
network = "USDT",
|
|
||||||
currencyIconState = CurrencyIconState.Locked,
|
|
||||||
onShareClick = {},
|
|
||||||
)
|
|
||||||
|
|
||||||
override val values: Sequence<ReceiveAssetsUM>
|
|
||||||
get() = sequenceOf(config)
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,672 @@
|
||||||
|
package com.tangem.features.tokenreceive.ui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.animation.animateColorAsState
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.TextAutoSize
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
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.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.util.fastFilter
|
||||||
|
import androidx.compose.ui.util.fastForEach
|
||||||
|
import com.tangem.common.ui.notifications.NotificationUM
|
||||||
|
import com.tangem.core.res.getStringSafe
|
||||||
|
import com.tangem.core.ui.R
|
||||||
|
import com.tangem.core.ui.components.*
|
||||||
|
import com.tangem.core.ui.components.atoms.text.EllipsisText
|
||||||
|
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
||||||
|
import com.tangem.core.ui.components.buttons.actions.ActionBaseButton
|
||||||
|
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||||
|
import com.tangem.core.ui.components.buttons.actions.ActionButtonContent
|
||||||
|
import com.tangem.core.ui.components.buttons.small.TangemIconButton
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
|
import com.tangem.core.ui.components.notifications.Notification
|
||||||
|
import com.tangem.core.ui.extensions.*
|
||||||
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
|
import com.tangem.core.ui.res.*
|
||||||
|
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||||
|
import com.tangem.features.tokenreceive.ui.state.ReceiveAssetsUM
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun TokenReceiveAssetsContentLegacy(assetsUM: ReceiveAssetsUM) {
|
||||||
|
val snackbarHostState = remember(::SnackbarHostState)
|
||||||
|
|
||||||
|
ContainerWithSnackbarHost(snackbarHostState = snackbarHostState) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(color = TangemTheme.colors.background.tertiary)
|
||||||
|
.padding(bottom = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
AddressBlock(
|
||||||
|
assetsUM = assetsUM,
|
||||||
|
snackbarHostState = snackbarHostState,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (assetsUM.isEnsResultLoading) {
|
||||||
|
SpacerH8()
|
||||||
|
LoadingBlock(modifier = Modifier.padding(horizontal = 16.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH12()
|
||||||
|
|
||||||
|
Info(
|
||||||
|
showMemoDisclaimer = assetsUM.showMemoDisclaimer,
|
||||||
|
notificationConfigs = assetsUM.notificationConfigs,
|
||||||
|
currencyIconState = assetsUM.currencyIconState,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Info(
|
||||||
|
currencyIconState: CurrencyIconState,
|
||||||
|
notificationConfigs: ImmutableList<NotificationUM>,
|
||||||
|
showMemoDisclaimer: Boolean,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier.padding(horizontal = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||||
|
) {
|
||||||
|
if (showMemoDisclaimer) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 18.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
text = stringResourceSafe(R.string.receive_bottom_sheet_no_memo_required_message),
|
||||||
|
style = TangemTheme.typography.caption1,
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationConfigs.fastForEach { notificationConfig ->
|
||||||
|
key(notificationConfig.hashCode()) {
|
||||||
|
if (notificationConfig is NotificationUM.Warning.YieldSupplyIsActive) {
|
||||||
|
YieldSupplyDepositedWarning(
|
||||||
|
currencyIconState = currencyIconState,
|
||||||
|
title = stringResourceSafe(
|
||||||
|
R.string.yield_module_balance_info_sheet_title,
|
||||||
|
notificationConfig.tokenName,
|
||||||
|
),
|
||||||
|
subtitle = stringResourceSafe(R.string.yield_module_balance_info_sheet_subtitle),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Notification(config = notificationConfig.config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun YieldSupplyDepositedWarning(
|
||||||
|
currencyIconState: CurrencyIconState,
|
||||||
|
title: String,
|
||||||
|
subtitle: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
modifier = modifier
|
||||||
|
.defaultMinSize(minHeight = TangemTheme.dimens.size44)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||||
|
color = TangemTheme.colors.button.disabled,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(all = TangemTheme.dimens.spacing12),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(22.dp)
|
||||||
|
.width(22.dp),
|
||||||
|
contentAlignment = Alignment.TopStart,
|
||||||
|
) {
|
||||||
|
CurrencyIcon(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.TopStart)
|
||||||
|
.size(13.dp),
|
||||||
|
state = currencyIconState,
|
||||||
|
shouldDisplayNetwork = false,
|
||||||
|
iconSize = 13.dp,
|
||||||
|
)
|
||||||
|
|
||||||
|
Image(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(TangemTheme.colors.background.tertiary, RoundedCornerShape(15.dp))
|
||||||
|
.padding(1.dp)
|
||||||
|
.size(15.dp)
|
||||||
|
.align(Alignment.BottomEnd),
|
||||||
|
imageVector = ImageVector.vectorResource(R.drawable.img_aave_22),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerW(width = TangemTheme.dimens.spacing8)
|
||||||
|
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
style = TangemTheme.typography.button,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(height = TangemTheme.dimens.spacing2)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = subtitle,
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
style = TangemTheme.typography.caption2,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun AddressBlock(assetsUM: ReceiveAssetsUM, snackbarHostState: SnackbarHostState) {
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val context = LocalContext.current
|
||||||
|
val resources = context.resources
|
||||||
|
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||||
|
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
||||||
|
|
||||||
|
assetsUM.addresses
|
||||||
|
.fastFilter { it.type is ReceiveAddress.Type.Ens }
|
||||||
|
.fastForEach { address ->
|
||||||
|
key(address.value) {
|
||||||
|
EnsItem(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
onCopyClick = {
|
||||||
|
assetsUM.onCopyClick(address)
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
coroutineScope.launch {
|
||||||
|
if (isRedesignEnabled) {
|
||||||
|
topSnackbarHostState.showSnackbar(
|
||||||
|
SnackbarMessage(
|
||||||
|
startIconId = R.drawable.ic_check_24,
|
||||||
|
message = resourceReference(R.string.wallet_notification_address_copied),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
snackbarHostState.showSnackbar(
|
||||||
|
message = resources.getStringSafe(
|
||||||
|
R.string.wallet_notification_address_copied,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
address = address.value,
|
||||||
|
)
|
||||||
|
SpacerH8()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimaryAddressesItems(
|
||||||
|
addresses = assetsUM.addresses.fastFilter { it.type is ReceiveAddress.Type.Primary }.toImmutableList(),
|
||||||
|
currencyIconState = assetsUM.currencyIconState,
|
||||||
|
snackbarHostState = snackbarHostState,
|
||||||
|
onShareClick = { address ->
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
assetsUM.onShareClick(address)
|
||||||
|
},
|
||||||
|
onCopyClick = { address ->
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
coroutineScope.launch {
|
||||||
|
snackbarHostState.showSnackbar(
|
||||||
|
message = resources.getStringSafe(
|
||||||
|
R.string.wallet_notification_address_copied,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
assetsUM.onCopyClick(address)
|
||||||
|
},
|
||||||
|
onOpenQrCodeClick = { address ->
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
assetsUM.onOpenQrCodeClick(address)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
@Composable
|
||||||
|
private fun PrimaryAddressesItems(
|
||||||
|
addresses: ImmutableList<ReceiveAddress>,
|
||||||
|
currencyIconState: CurrencyIconState,
|
||||||
|
snackbarHostState: SnackbarHostState,
|
||||||
|
onShareClick: (String) -> Unit,
|
||||||
|
onCopyClick: (ReceiveAddress) -> Unit,
|
||||||
|
onOpenQrCodeClick: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
if (addresses.isEmpty()) return
|
||||||
|
var selectedAddress by remember { mutableStateOf(addresses.first()) }
|
||||||
|
val pagerState = rememberPagerState(
|
||||||
|
initialPage = 0,
|
||||||
|
initialPageOffsetFraction = 0f,
|
||||||
|
pageCount = addresses::count,
|
||||||
|
)
|
||||||
|
LaunchedEffect(key1 = pagerState.currentPage) {
|
||||||
|
selectedAddress = addresses[pagerState.currentPage]
|
||||||
|
}
|
||||||
|
|
||||||
|
HorizontalPager(
|
||||||
|
state = pagerState,
|
||||||
|
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||||
|
pageSpacing = 16.dp,
|
||||||
|
) {
|
||||||
|
AddressItem(
|
||||||
|
currencyIconState = currencyIconState,
|
||||||
|
onOpenQrCodeClick = { onOpenQrCodeClick(selectedAddress.value) },
|
||||||
|
onCopyClick = { onCopyClick(selectedAddress) },
|
||||||
|
onShareClick = { onShareClick(selectedAddress.value) },
|
||||||
|
primaryType = selectedAddress.type as ReceiveAddress.Type.Primary,
|
||||||
|
address = selectedAddress.value,
|
||||||
|
isDynamicAddress = selectedAddress.type is ReceiveAddress.Type.Primary.Dynamic,
|
||||||
|
snackbarHostState = snackbarHostState,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH(4.dp)
|
||||||
|
|
||||||
|
if (pagerState.pageCount > 1) {
|
||||||
|
val indicatorState = rememberLazyListState()
|
||||||
|
val selectedColor = TangemTheme.colors.icon.primary1
|
||||||
|
val unselectedColor = TangemTheme.colors.icon.informative
|
||||||
|
|
||||||
|
LazyRow(
|
||||||
|
modifier = Modifier.height(20.dp),
|
||||||
|
state = indicatorState,
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
repeat(pagerState.pageCount) { iteration ->
|
||||||
|
item(key = iteration) {
|
||||||
|
val color by animateColorAsState(
|
||||||
|
targetValue = if (pagerState.currentPage == iteration) selectedColor else unselectedColor,
|
||||||
|
label = "",
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp, vertical = 6.dp)
|
||||||
|
.background(color = color, shape = CircleShape)
|
||||||
|
.size(7.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
@Composable
|
||||||
|
private fun AddressItem(
|
||||||
|
currencyIconState: CurrencyIconState,
|
||||||
|
onOpenQrCodeClick: () -> Unit,
|
||||||
|
onCopyClick: () -> Unit,
|
||||||
|
onShareClick: () -> Unit,
|
||||||
|
primaryType: ReceiveAddress.Type.Primary,
|
||||||
|
address: String,
|
||||||
|
isDynamicAddress: Boolean,
|
||||||
|
snackbarHostState: SnackbarHostState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors.background.action),
|
||||||
|
onClick = onOpenQrCodeClick,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 12.dp, vertical = 32.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
CurrencyIcon(
|
||||||
|
modifier = Modifier.size(56.dp),
|
||||||
|
state = currencyIconState,
|
||||||
|
shouldDisplayNetwork = true,
|
||||||
|
iconSize = 56.dp,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(12.dp)
|
||||||
|
|
||||||
|
if (isDynamicAddress) {
|
||||||
|
DynamicAddressBadge()
|
||||||
|
SpacerH(8.dp)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = primaryType.displayName.resolveReference(),
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
style = TangemTheme.typography.subtitle1,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.heightIn(min = 40.dp)
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
text = address,
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
style = TangemTheme.typography.body2,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH8()
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.clickable(onClick = onOpenQrCodeClick)
|
||||||
|
.padding(vertical = 6.dp, horizontal = 12.dp),
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
imageVector = ImageVector.vectorResource(R.drawable.ic_qrcode_new_24),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerW(4.dp)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResourceSafe(R.string.token_receive_show_qr_code_title),
|
||||||
|
style = TangemTheme.typography.caption1,
|
||||||
|
color = TangemTheme.colors.text.secondary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH(20.dp)
|
||||||
|
|
||||||
|
ButtonsBlock(
|
||||||
|
snackbarHostState = snackbarHostState,
|
||||||
|
onCopyClick = onCopyClick,
|
||||||
|
onShareClick = onShareClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ButtonsBlock(snackbarHostState: SnackbarHostState, onCopyClick: () -> Unit, onShareClick: () -> Unit) {
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val context = LocalContext.current
|
||||||
|
val resources = context.resources
|
||||||
|
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||||
|
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.width(IntrinsicSize.Min),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
ActionButtonWithResizableText(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
config = ActionButtonConfig(
|
||||||
|
text = TextReference.Res(id = R.string.common_copy),
|
||||||
|
iconResId = R.drawable.ic_copy_new_24,
|
||||||
|
onClick = {
|
||||||
|
onCopyClick()
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
coroutineScope.launch {
|
||||||
|
if (isRedesignEnabled) {
|
||||||
|
topSnackbarHostState.showSnackbar(
|
||||||
|
SnackbarMessage(
|
||||||
|
startIconId = R.drawable.ic_check_24,
|
||||||
|
message = resourceReference(R.string.wallet_notification_address_copied),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
snackbarHostState.showSnackbar(
|
||||||
|
message = resources.getStringSafe(R.string.wallet_notification_address_copied),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
ActionButtonWithResizableText(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
config = ActionButtonConfig(
|
||||||
|
text = TextReference.Res(id = R.string.common_share),
|
||||||
|
iconResId = R.drawable.ic_share_24,
|
||||||
|
onClick = {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
onShareClick()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun EnsItem(onCopyClick: () -> Unit, address: String, modifier: Modifier = Modifier) {
|
||||||
|
Card(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors.background.action),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 14.dp, horizontal = 12.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
modifier = Modifier.size(36.dp),
|
||||||
|
imageVector = ImageVector.vectorResource(R.drawable.ic_ens_36),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerW12()
|
||||||
|
|
||||||
|
EllipsisText(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
text = address,
|
||||||
|
ellipsis = TextEllipsis.Middle,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
style = TangemTheme.typography.subtitle1,
|
||||||
|
)
|
||||||
|
|
||||||
|
TangemIconButton(
|
||||||
|
modifier = Modifier.size(TangemTheme.dimens.size28),
|
||||||
|
iconRes = R.drawable.ic_share_24,
|
||||||
|
innerPadding = 6.dp,
|
||||||
|
onClick = onCopyClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun LoadingBlock(modifier: Modifier = Modifier) {
|
||||||
|
Card(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors.background.action),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.heightIn(min = 64.dp),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
color = TangemTheme.colors.icon.informative,
|
||||||
|
modifier = Modifier.padding(TangemTheme.dimens.spacing8),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ActionButtonWithResizableText(config: ActionButtonConfig, modifier: Modifier = Modifier) {
|
||||||
|
ActionBaseButton(
|
||||||
|
config = config,
|
||||||
|
shape = RoundedCornerShape(size = TangemTheme.dimens.radius24),
|
||||||
|
content = { contentModifier ->
|
||||||
|
ActionButtonContent(
|
||||||
|
config = config,
|
||||||
|
text = { color ->
|
||||||
|
Text(
|
||||||
|
text = config.text.resolveReference(),
|
||||||
|
autoSize = TextAutoSize.StepBased(
|
||||||
|
minFontSize = 10.sp,
|
||||||
|
maxFontSize = TangemTheme.typography.button.fontSize,
|
||||||
|
),
|
||||||
|
color = color,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
style = TangemTheme.typography.button,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = contentModifier.padding(horizontal = 16.dp),
|
||||||
|
paddingBetweenIconAndText = 4.dp,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = modifier,
|
||||||
|
color = TangemTheme.colors.button.secondary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DynamicAddressBadge(modifier: Modifier = Modifier) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.background(
|
||||||
|
color = TangemTheme.colors.text.accent.copy(alpha = 0.1f),
|
||||||
|
shape = RoundedCornerShape(percent = 50),
|
||||||
|
)
|
||||||
|
.padding(horizontal = 12.dp, vertical = 4.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(
|
||||||
|
id = R.drawable.ic_dynamic_addresses_badge_16,
|
||||||
|
),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
tint = TangemTheme.colors.icon.accent,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResourceSafe(R.string.dynamic_addresses_receive_badge),
|
||||||
|
style = TangemTheme.typography.caption1,
|
||||||
|
color = TangemTheme.colors.text.accent,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
private fun Preview_TokenReceiveAssetsContent(
|
||||||
|
@PreviewParameter(TokenReceiveAssetsContentProvider::class) params: ReceiveAssetsUM,
|
||||||
|
) {
|
||||||
|
TangemThemePreview {
|
||||||
|
TokenReceiveAssetsContentLegacy(assetsUM = params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TokenReceiveAssetsContentProvider : PreviewParameterProvider<ReceiveAssetsUM> {
|
||||||
|
val address = ReceiveAddress(
|
||||||
|
value = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
|
||||||
|
type = ReceiveAddress.Type.Primary.Default(
|
||||||
|
displayName = stringReference("Etherium address"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
private val dynamicAddress = ReceiveAddress(
|
||||||
|
value = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
||||||
|
type = ReceiveAddress.Type.Primary.Dynamic(
|
||||||
|
displayName = stringReference("Ethereum address"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
private val tokenIconState = CurrencyIconState.TokenIcon(
|
||||||
|
url = null,
|
||||||
|
topBadgeIconResId = null,
|
||||||
|
fallbackTint = TangemColorPalette.Black,
|
||||||
|
fallbackBackground = TangemColorPalette.Meadow,
|
||||||
|
isGrayscale = false,
|
||||||
|
shouldShowCustomBadge = false,
|
||||||
|
)
|
||||||
|
private val config = ReceiveAssetsUM(
|
||||||
|
notificationConfigs =
|
||||||
|
persistentListOf(
|
||||||
|
NotificationUM.Warning(
|
||||||
|
title = stringReference("Send only XLM on the Ethereum network"),
|
||||||
|
subtitle = resourceReference(R.string.receive_bottom_sheet_warning_message_description),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
addresses = persistentListOf(
|
||||||
|
address,
|
||||||
|
address,
|
||||||
|
address.copy(type = ReceiveAddress.Type.Ens, value = "papasha.eth"),
|
||||||
|
),
|
||||||
|
showMemoDisclaimer = false,
|
||||||
|
onCopyClick = {},
|
||||||
|
onOpenQrCodeClick = {},
|
||||||
|
isEnsResultLoading = true,
|
||||||
|
network = "USDT",
|
||||||
|
currencyIconState = CurrencyIconState.Locked,
|
||||||
|
onShareClick = {},
|
||||||
|
)
|
||||||
|
private val yieldSupplyIsActiveConfig = config.copy(
|
||||||
|
notificationConfigs = persistentListOf(
|
||||||
|
NotificationUM.Warning.YieldSupplyIsActive(tokenName = "USDT"),
|
||||||
|
),
|
||||||
|
isEnsResultLoading = false,
|
||||||
|
currencyIconState = tokenIconState,
|
||||||
|
)
|
||||||
|
private val dynamicAddressConfig = config.copy(
|
||||||
|
addresses = persistentListOf(
|
||||||
|
dynamicAddress,
|
||||||
|
address,
|
||||||
|
address.copy(type = ReceiveAddress.Type.Ens, value = "papasha.eth"),
|
||||||
|
),
|
||||||
|
isEnsResultLoading = false,
|
||||||
|
notificationConfigs = persistentListOf(),
|
||||||
|
currencyIconState = tokenIconState,
|
||||||
|
)
|
||||||
|
|
||||||
|
override val values: Sequence<ReceiveAssetsUM>
|
||||||
|
get() = sequenceOf(config, yieldSupplyIsActiveConfig, dynamicAddressConfig)
|
||||||
|
}
|
||||||
|
|
@ -2,22 +2,32 @@ package com.tangem.features.tokenreceive.ui
|
||||||
|
|
||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.Children
|
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.fade
|
import com.arkivanov.decompose.extensions.compose.stack.animation.fade
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
||||||
import com.arkivanov.decompose.router.stack.ChildStack
|
import com.arkivanov.decompose.router.stack.ChildStack
|
||||||
import com.tangem.core.ui.R
|
import com.tangem.core.ui.R
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetType
|
||||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||||
|
import com.tangem.core.ui.ds.topbar.TangemTopBar
|
||||||
|
import com.tangem.core.ui.ds.topbar.TangemTopBarType
|
||||||
|
import com.tangem.core.ui.ds2.button.TangemButton
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.core.ui.res.LocalHazeState
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.generated.icons.Icons
|
||||||
|
import com.tangem.core.ui.res.generated.icons.ic_chevron_left_24
|
||||||
|
import com.tangem.core.ui.res.generated.icons.ic_cross_24
|
||||||
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
||||||
|
import dev.chrisbanes.haze.rememberHazeState
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TokenReceiveContentSheet(
|
internal fun TokenReceiveContentSheet(
|
||||||
|
|
@ -26,59 +36,89 @@ internal fun TokenReceiveContentSheet(
|
||||||
onBackClick: () -> Unit,
|
onBackClick: () -> Unit,
|
||||||
contentStack: ChildStack<TokenReceiveRoutes, ComposableContentComponent>,
|
contentStack: ChildStack<TokenReceiveRoutes, ComposableContentComponent>,
|
||||||
) {
|
) {
|
||||||
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
CompositionLocalProvider(LocalHazeState provides rememberHazeState()) {
|
||||||
config = TangemBottomSheetConfig(
|
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||||
isShown = true,
|
type = TangemBottomSheetType.Modal,
|
||||||
onDismissRequest = onCloseClick,
|
onBack = onBackClick,
|
||||||
content = TangemBottomSheetConfigContent.Empty,
|
config = TangemBottomSheetConfig(
|
||||||
),
|
isShown = true,
|
||||||
onBack = onBackClick,
|
onDismissRequest = onCloseClick,
|
||||||
containerColor = TangemTheme.colors.background.tertiary,
|
content = TangemBottomSheetConfigContent.Empty,
|
||||||
title = {
|
),
|
||||||
Title(
|
containerColor = TangemTheme.colors3.bg.secondary,
|
||||||
route = route,
|
title = {
|
||||||
onBackClick = onBackClick,
|
Title(
|
||||||
onCloseClick = onCloseClick,
|
route = route,
|
||||||
)
|
onBackClick = onBackClick,
|
||||||
},
|
onCloseClick = onCloseClick,
|
||||||
content = {
|
)
|
||||||
TokenReceiveContent(
|
},
|
||||||
stackState = contentStack,
|
content = {
|
||||||
modifier = Modifier,
|
TokenReceiveContent(
|
||||||
)
|
stackState = contentStack,
|
||||||
},
|
modifier = Modifier,
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Title(route: TokenReceiveRoutes, onBackClick: () -> Unit, onCloseClick: () -> Unit) {
|
private fun Title(route: TokenReceiveRoutes, onBackClick: () -> Unit, onCloseClick: () -> Unit) {
|
||||||
when (route) {
|
when (route) {
|
||||||
is TokenReceiveRoutes.QrCode -> {
|
is TokenReceiveRoutes.QrCode -> {
|
||||||
TangemModalBottomSheetTitle(
|
TangemTopBar(
|
||||||
startIconRes = R.drawable.ic_back_24,
|
type = TangemTopBarType.BottomSheet,
|
||||||
onStartClick = onBackClick,
|
endContent = {
|
||||||
endIconRes = R.drawable.ic_close_24,
|
TangemButton(
|
||||||
onEndClick = onCloseClick,
|
iconStart = TangemIconUM.Icon(Icons.ic_cross_24),
|
||||||
|
onClick = onCloseClick,
|
||||||
|
size = TangemButton.Size.X11,
|
||||||
|
variant = TangemButton.Variant.Material,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
startContent = {
|
||||||
|
TangemButton(
|
||||||
|
iconStart = TangemIconUM.Icon(imageVector = Icons.ic_chevron_left_24),
|
||||||
|
onClick = onBackClick,
|
||||||
|
size = TangemButton.Size.X11,
|
||||||
|
variant = TangemButton.Variant.Material,
|
||||||
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TokenReceiveRoutes.ReceiveAssets -> {
|
TokenReceiveRoutes.ReceiveAssets -> {
|
||||||
TangemModalBottomSheetTitle(
|
TangemTopBar(
|
||||||
title = resourceReference(R.string.domain_receive_assets_navigation_title),
|
title = resourceReference(R.string.domain_receive_assets_navigation_title),
|
||||||
endIconRes = R.drawable.ic_close_24,
|
type = TangemTopBarType.BottomSheet,
|
||||||
onEndClick = onCloseClick,
|
endContent = {
|
||||||
|
TangemButton(
|
||||||
|
iconStart = TangemIconUM.Icon(Icons.ic_cross_24),
|
||||||
|
onClick = onCloseClick,
|
||||||
|
size = TangemButton.Size.X11,
|
||||||
|
variant = TangemButton.Variant.Material,
|
||||||
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TokenReceiveRoutes.Warning -> {
|
TokenReceiveRoutes.Warning -> {
|
||||||
TangemModalBottomSheetTitle(
|
TangemTopBar(
|
||||||
endIconRes = R.drawable.ic_close_24,
|
type = TangemTopBarType.BottomSheet,
|
||||||
onEndClick = onCloseClick,
|
endContent = {
|
||||||
|
TangemButton(
|
||||||
|
iconStart = TangemIconUM.Icon(Icons.ic_cross_24),
|
||||||
|
onClick = onCloseClick,
|
||||||
|
size = TangemButton.Size.X11,
|
||||||
|
variant = TangemButton.Variant.Material,
|
||||||
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TokenReceiveContent(
|
private fun TokenReceiveContent(
|
||||||
stackState: ChildStack<TokenReceiveRoutes, ComposableContentComponent>,
|
stackState: ChildStack<TokenReceiveRoutes, ComposableContentComponent>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
|
@ -86,9 +126,9 @@ internal fun TokenReceiveContent(
|
||||||
stack = stackState,
|
stack = stackState,
|
||||||
animation = stackAnimation(fade(animationSpec = tween(durationMillis = 100))),
|
animation = stackAnimation(fade(animationSpec = tween(durationMillis = 100))),
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
.fillMaxWidth()
|
||||||
.animateContentSize(),
|
.animateContentSize(),
|
||||||
) {
|
) {
|
||||||
it.instance.Content(Modifier.fillMaxSize())
|
it.instance.Content(Modifier.fillMaxWidth())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package com.tangem.features.tokenreceive.ui
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateContentSize
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||||
|
import com.arkivanov.decompose.extensions.compose.stack.animation.fade
|
||||||
|
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
||||||
|
import com.arkivanov.decompose.router.stack.ChildStack
|
||||||
|
import com.tangem.core.ui.R
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||||
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun TokenReceiveContentSheetLegacy(
|
||||||
|
route: TokenReceiveRoutes,
|
||||||
|
onCloseClick: () -> Unit,
|
||||||
|
onBackClick: () -> Unit,
|
||||||
|
contentStack: ChildStack<TokenReceiveRoutes, ComposableContentComponent>,
|
||||||
|
) {
|
||||||
|
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||||
|
config = TangemBottomSheetConfig(
|
||||||
|
isShown = true,
|
||||||
|
onDismissRequest = onCloseClick,
|
||||||
|
content = TangemBottomSheetConfigContent.Empty,
|
||||||
|
),
|
||||||
|
onBack = onBackClick,
|
||||||
|
containerColor = TangemTheme.colors.background.tertiary,
|
||||||
|
title = {
|
||||||
|
Title(
|
||||||
|
route = route,
|
||||||
|
onBackClick = onBackClick,
|
||||||
|
onCloseClick = onCloseClick,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
content = {
|
||||||
|
TokenReceiveContent(
|
||||||
|
stackState = contentStack,
|
||||||
|
modifier = Modifier,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Title(route: TokenReceiveRoutes, onBackClick: () -> Unit, onCloseClick: () -> Unit) {
|
||||||
|
when (route) {
|
||||||
|
is TokenReceiveRoutes.QrCode -> {
|
||||||
|
TangemModalBottomSheetTitle(
|
||||||
|
startIconRes = R.drawable.ic_back_24,
|
||||||
|
onStartClick = onBackClick,
|
||||||
|
endIconRes = R.drawable.ic_close_24,
|
||||||
|
onEndClick = onCloseClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TokenReceiveRoutes.ReceiveAssets -> {
|
||||||
|
TangemModalBottomSheetTitle(
|
||||||
|
title = resourceReference(R.string.domain_receive_assets_navigation_title),
|
||||||
|
endIconRes = R.drawable.ic_close_24,
|
||||||
|
onEndClick = onCloseClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TokenReceiveRoutes.Warning -> {
|
||||||
|
TangemModalBottomSheetTitle(
|
||||||
|
endIconRes = R.drawable.ic_close_24,
|
||||||
|
onEndClick = onCloseClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TokenReceiveContent(
|
||||||
|
stackState: ChildStack<TokenReceiveRoutes, ComposableContentComponent>,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Children(
|
||||||
|
stack = stackState,
|
||||||
|
animation = stackAnimation(fade(animationSpec = tween(durationMillis = 100))),
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.animateContentSize(),
|
||||||
|
) {
|
||||||
|
it.instance.Content(Modifier.fillMaxSize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,11 +2,9 @@ package com.tangem.features.tokenreceive.ui
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
|
@ -18,24 +16,25 @@ import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.res.getStringSafe
|
import com.tangem.core.ui.components.SpacerH
|
||||||
import com.tangem.core.ui.components.*
|
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||||
|
import com.tangem.core.ui.ds2.button.TangemButton
|
||||||
import com.tangem.core.ui.extensions.*
|
import com.tangem.core.ui.extensions.*
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
|
||||||
import com.tangem.core.ui.res.LocalTopSnackbarHostState
|
import com.tangem.core.ui.res.LocalTopSnackbarHostState
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||||
|
import com.tangem.core.ui.res.generated.icons.Icons
|
||||||
|
import com.tangem.core.ui.res.generated.icons.ic_copy_24
|
||||||
|
import com.tangem.core.ui.res.generated.icons.ic_share_android_24
|
||||||
import com.tangem.core.ui.test.TokenReceiveQrCodeBottomSheetTestTags
|
import com.tangem.core.ui.test.TokenReceiveQrCodeBottomSheetTestTags
|
||||||
import com.tangem.features.tokenreceive.impl.R
|
import com.tangem.features.tokenreceive.impl.R
|
||||||
import com.tangem.features.tokenreceive.ui.state.QrCodeUM
|
import com.tangem.features.tokenreceive.ui.state.QrCodeUM
|
||||||
|
|
@ -43,34 +42,28 @@ import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TokenReceiveQrCodeContent(qrCodeUM: QrCodeUM) {
|
internal fun TokenReceiveQrCodeContent(qrCodeUM: QrCodeUM) {
|
||||||
val snackbarHostState = remember(::SnackbarHostState)
|
|
||||||
val qrCodePainter = rememberQrPainter(content = qrCodeUM.addressValue)
|
val qrCodePainter = rememberQrPainter(content = qrCodeUM.addressValue)
|
||||||
|
|
||||||
ContainerWithSnackbarHost(snackbarHostState = snackbarHostState) {
|
Column(
|
||||||
Column(
|
modifier = Modifier
|
||||||
modifier = Modifier
|
.fillMaxWidth()
|
||||||
.fillMaxWidth()
|
.padding(bottom = 16.dp, start = 16.dp, end = 16.dp),
|
||||||
.background(color = TangemTheme.colors.background.tertiary)
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
.padding(bottom = 16.dp)
|
) {
|
||||||
.padding(horizontal = 16.dp),
|
QrCodePage(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
addressFullName = qrCodeUM.addressName,
|
||||||
) {
|
addressValue = qrCodeUM.addressValue,
|
||||||
SpacerH8()
|
network = qrCodeUM.network,
|
||||||
|
qrCodePainter = qrCodePainter,
|
||||||
|
)
|
||||||
|
|
||||||
QrCodePage(
|
SpacerH(24.dp)
|
||||||
addressFullName = qrCodeUM.addressName,
|
|
||||||
addressValue = qrCodeUM.addressValue,
|
|
||||||
network = qrCodeUM.network,
|
|
||||||
qrCodePainter = qrCodePainter,
|
|
||||||
)
|
|
||||||
SpacerH24()
|
|
||||||
|
|
||||||
Buttons(
|
Buttons(
|
||||||
onShareClick = { qrCodeUM.onShareClick(qrCodeUM.addressValue) },
|
modifier = Modifier.padding(top = 8.dp),
|
||||||
onCopyClick = qrCodeUM.onCopyClick,
|
onShareClick = { qrCodeUM.onShareClick(qrCodeUM.addressValue) },
|
||||||
snackbarHostState = snackbarHostState,
|
onCopyClick = qrCodeUM.onCopyClick,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,7 +74,12 @@ private fun QrCodePage(addressFullName: TextReference, addressValue: String, net
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.size36),
|
modifier = Modifier.padding(
|
||||||
|
start = 16.dp,
|
||||||
|
end = 16.dp,
|
||||||
|
top = 24.dp,
|
||||||
|
bottom = 16.dp,
|
||||||
|
),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -90,22 +88,22 @@ private fun QrCodePage(addressFullName: TextReference, addressValue: String, net
|
||||||
addressFullName.resolveReference(),
|
addressFullName.resolveReference(),
|
||||||
network,
|
network,
|
||||||
),
|
),
|
||||||
color = TangemTheme.colors.text.primary1,
|
color = TangemTheme.colors3.text.primary,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
style = TangemTheme.typography.h3,
|
style = TangemTheme.typography3.heading.small,
|
||||||
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.TITLE),
|
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.TITLE),
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH(20.dp)
|
SpacerH(32.dp)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.border(
|
.border(
|
||||||
width = 8.dp,
|
width = 16.dp,
|
||||||
color = TangemTheme.colors.icon.constant,
|
color = TangemTheme.colors3.bg.secondary,
|
||||||
shape = RoundedCornerShape(8.dp),
|
shape = RoundedCornerShape(12.dp),
|
||||||
)
|
)
|
||||||
.padding(8.dp)
|
.padding(16.dp)
|
||||||
.testTag(TokenReceiveQrCodeBottomSheetTestTags.QR_CODE),
|
.testTag(TokenReceiveQrCodeBottomSheetTestTags.QR_CODE),
|
||||||
|
|
||||||
) {
|
) {
|
||||||
|
|
@ -116,79 +114,66 @@ private fun QrCodePage(addressFullName: TextReference, addressValue: String, net
|
||||||
modifier = Modifier.sizeIn(minWidth = 148.dp),
|
modifier = Modifier.sizeIn(minWidth = 148.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SpacerH24()
|
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
text = stringResourceSafe(R.string.wc_common_address),
|
text = stringResourceSafe(R.string.wc_common_address),
|
||||||
color = TangemTheme.colors.text.tertiary,
|
color = TangemTheme.colors3.text.secondary,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
style = TangemTheme.typography.subtitle2,
|
style = TangemTheme.typography3.caption.medium,
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH2()
|
SpacerH(4.dp)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = addressValue,
|
text = addressValue,
|
||||||
color = TangemTheme.colors.text.primary1,
|
color = TangemTheme.colors3.text.primary,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
style = TangemTheme.typography.subtitle1,
|
style = TangemTheme.typography3.body.medium,
|
||||||
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.ADDRESS),
|
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.ADDRESS),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Buttons(
|
private fun Buttons(onShareClick: () -> Unit, onCopyClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||||
snackbarHostState: SnackbarHostState,
|
|
||||||
onShareClick: () -> Unit,
|
|
||||||
onCopyClick: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
val hapticFeedback = LocalHapticFeedback.current
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
|
||||||
val resources = context.resources
|
|
||||||
|
|
||||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
|
||||||
val tangemTopSnackbarHostState = LocalTopSnackbarHostState.current
|
val tangemTopSnackbarHostState = LocalTopSnackbarHostState.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
SecondaryButtonIconStart(
|
TangemButton(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
text = stringResourceSafe(id = R.string.common_copy),
|
|
||||||
iconResId = R.drawable.ic_copy_24,
|
|
||||||
onClick = {
|
onClick = {
|
||||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
onCopyClick()
|
onCopyClick()
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
if (isRedesignEnabled) {
|
tangemTopSnackbarHostState.showSnackbar(
|
||||||
tangemTopSnackbarHostState.showSnackbar(
|
SnackbarMessage(
|
||||||
SnackbarMessage(
|
startIconId = R.drawable.ic_check_24,
|
||||||
startIconId = R.drawable.ic_check_24,
|
message = resourceReference(R.string.wallet_notification_address_copied),
|
||||||
message = resourceReference(R.string.wallet_notification_address_copied),
|
),
|
||||||
),
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
snackbarHostState.showSnackbar(
|
|
||||||
message = resources.getStringSafe(R.string.wallet_notification_address_copied),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
text = resourceReference(R.string.common_copy),
|
||||||
|
iconStart = TangemIconUM.Icon(Icons.ic_copy_24),
|
||||||
|
size = TangemButton.Size.X12,
|
||||||
|
variant = TangemButton.Variant.Secondary,
|
||||||
)
|
)
|
||||||
|
|
||||||
SecondaryButtonIconStart(
|
TangemButton(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
text = stringResourceSafe(id = R.string.common_share),
|
|
||||||
iconResId = R.drawable.ic_share_24,
|
|
||||||
onClick = {
|
onClick = {
|
||||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
onShareClick()
|
onShareClick()
|
||||||
},
|
},
|
||||||
|
text = resourceReference(R.string.common_share),
|
||||||
|
iconStart = TangemIconUM.Icon(Icons.ic_share_android_24),
|
||||||
|
size = TangemButton.Size.X12,
|
||||||
|
variant = TangemButton.Variant.Secondary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -212,20 +197,7 @@ private fun rememberQrPainter(content: String, size: Dp = 248.dp, padding: Dp =
|
||||||
private fun Preview_TokenReceiveQrCodeContent(
|
private fun Preview_TokenReceiveQrCodeContent(
|
||||||
@PreviewParameter(TokenReceiveQrCodeContentPreviewProvider::class) qrCodeUM: QrCodeUM,
|
@PreviewParameter(TokenReceiveQrCodeContentPreviewProvider::class) qrCodeUM: QrCodeUM,
|
||||||
) {
|
) {
|
||||||
TangemThemePreview {
|
TangemThemePreviewRedesign {
|
||||||
TokenReceiveQrCodeContent(qrCodeUM = qrCodeUM)
|
TokenReceiveQrCodeContent(qrCodeUM = qrCodeUM)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class TokenReceiveQrCodeContentPreviewProvider : PreviewParameterProvider<QrCodeUM> {
|
|
||||||
private val config = QrCodeUM(
|
|
||||||
network = "Ethereum",
|
|
||||||
addressName = stringReference("Etherium"),
|
|
||||||
addressValue = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
|
|
||||||
onCopyClick = {},
|
|
||||||
onShareClick = {},
|
|
||||||
)
|
|
||||||
|
|
||||||
override val values: Sequence<QrCodeUM>
|
|
||||||
get() = sequenceOf(config)
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
package com.tangem.features.tokenreceive.ui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
|
import androidx.compose.ui.platform.testTag
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
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.compose.ui.unit.dp
|
||||||
|
import com.tangem.core.res.getStringSafe
|
||||||
|
import com.tangem.core.ui.components.*
|
||||||
|
import com.tangem.core.ui.extensions.*
|
||||||
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
|
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||||
|
import com.tangem.core.ui.res.LocalTopSnackbarHostState
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
|
import com.tangem.core.ui.test.TokenReceiveQrCodeBottomSheetTestTags
|
||||||
|
import com.tangem.features.tokenreceive.impl.R
|
||||||
|
import com.tangem.features.tokenreceive.ui.state.QrCodeUM
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun TokenReceiveQrCodeContentLegacy(qrCodeUM: QrCodeUM) {
|
||||||
|
val snackbarHostState = remember(::SnackbarHostState)
|
||||||
|
val qrCodePainter = rememberQrPainter(content = qrCodeUM.addressValue)
|
||||||
|
|
||||||
|
ContainerWithSnackbarHost(snackbarHostState = snackbarHostState) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(color = TangemTheme.colors.background.tertiary)
|
||||||
|
.padding(bottom = 16.dp)
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
SpacerH8()
|
||||||
|
|
||||||
|
QrCodePage(
|
||||||
|
addressFullName = qrCodeUM.addressName,
|
||||||
|
addressValue = qrCodeUM.addressValue,
|
||||||
|
network = qrCodeUM.network,
|
||||||
|
qrCodePainter = qrCodePainter,
|
||||||
|
)
|
||||||
|
SpacerH24()
|
||||||
|
|
||||||
|
Buttons(
|
||||||
|
onShareClick = { qrCodeUM.onShareClick(qrCodeUM.addressValue) },
|
||||||
|
onCopyClick = qrCodeUM.onCopyClick,
|
||||||
|
snackbarHostState = snackbarHostState,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun QrCodePage(addressFullName: TextReference, addressValue: String, network: String, qrCodePainter: Painter) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(horizontal = TangemTheme.dimens.size36),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResourceSafe(
|
||||||
|
R.string.receive_bottom_sheet_warning_message_compact,
|
||||||
|
addressFullName.resolveReference(),
|
||||||
|
network,
|
||||||
|
),
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = TangemTheme.typography.h3,
|
||||||
|
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.TITLE),
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(20.dp)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
width = 8.dp,
|
||||||
|
color = TangemTheme.colors.icon.constant,
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
)
|
||||||
|
.padding(8.dp)
|
||||||
|
.testTag(TokenReceiveQrCodeBottomSheetTestTags.QR_CODE),
|
||||||
|
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = qrCodePainter,
|
||||||
|
contentDescription = null,
|
||||||
|
contentScale = ContentScale.Fit,
|
||||||
|
modifier = Modifier.sizeIn(minWidth = 148.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH24()
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = stringResourceSafe(R.string.wc_common_address),
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = TangemTheme.typography.subtitle2,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH2()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = addressValue,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = TangemTheme.typography.subtitle1,
|
||||||
|
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.ADDRESS),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Buttons(
|
||||||
|
snackbarHostState: SnackbarHostState,
|
||||||
|
onShareClick: () -> Unit,
|
||||||
|
onCopyClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val context = LocalContext.current
|
||||||
|
val resources = context.resources
|
||||||
|
|
||||||
|
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||||
|
val tangemTopSnackbarHostState = LocalTopSnackbarHostState.current
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = modifier,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
) {
|
||||||
|
SecondaryButtonIconStart(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
text = stringResourceSafe(id = R.string.common_copy),
|
||||||
|
iconResId = R.drawable.ic_copy_24,
|
||||||
|
onClick = {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
onCopyClick()
|
||||||
|
coroutineScope.launch {
|
||||||
|
if (isRedesignEnabled) {
|
||||||
|
tangemTopSnackbarHostState.showSnackbar(
|
||||||
|
SnackbarMessage(
|
||||||
|
startIconId = R.drawable.ic_check_24,
|
||||||
|
message = resourceReference(R.string.wallet_notification_address_copied),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
snackbarHostState.showSnackbar(
|
||||||
|
message = resources.getStringSafe(R.string.wallet_notification_address_copied),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
SecondaryButtonIconStart(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
text = stringResourceSafe(id = R.string.common_share),
|
||||||
|
iconResId = R.drawable.ic_share_24,
|
||||||
|
onClick = {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
onShareClick()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun rememberQrPainter(content: String, size: Dp = 248.dp, padding: Dp = 0.dp): BitmapPainter {
|
||||||
|
val density = LocalDensity.current
|
||||||
|
return remember(content) {
|
||||||
|
BitmapPainter(
|
||||||
|
content.toQrCode(
|
||||||
|
sizePx = with(density) { size.roundToPx() },
|
||||||
|
paddingPx = with(density) { padding.roundToPx() },
|
||||||
|
).asImageBitmap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
private fun Preview_TokenReceiveQrCodeContent(
|
||||||
|
@PreviewParameter(TokenReceiveQrCodeContentPreviewProvider::class) qrCodeUM: QrCodeUM,
|
||||||
|
) {
|
||||||
|
TangemThemePreview {
|
||||||
|
TokenReceiveQrCodeContentLegacy(qrCodeUM = qrCodeUM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TokenReceiveQrCodeContentPreviewProvider : PreviewParameterProvider<QrCodeUM> {
|
||||||
|
private val config = QrCodeUM(
|
||||||
|
network = "Ethereum",
|
||||||
|
addressName = stringReference("Etherium"),
|
||||||
|
addressValue = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
|
||||||
|
onCopyClick = {},
|
||||||
|
onShareClick = {},
|
||||||
|
)
|
||||||
|
|
||||||
|
override val values: Sequence<QrCodeUM>
|
||||||
|
get() = sequenceOf(config)
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package com.tangem.features.tokenreceive.ui
|
package com.tangem.features.tokenreceive.ui
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -13,19 +15,14 @@ import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.ui.components.SecondaryButton
|
|
||||||
import com.tangem.core.ui.components.SpacerH
|
import com.tangem.core.ui.components.SpacerH
|
||||||
import com.tangem.core.ui.components.SpacerH12
|
|
||||||
import com.tangem.core.ui.components.SpacerH24
|
|
||||||
import com.tangem.core.ui.components.SpacerW6
|
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
import com.tangem.core.ui.ds2.button.TangemButton
|
||||||
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
import com.tangem.core.ui.res.TangemColorPalette
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||||
import com.tangem.core.ui.test.TokenReceiveWarningBottomSheetTestTags
|
import com.tangem.core.ui.test.TokenReceiveWarningBottomSheetTestTags
|
||||||
import com.tangem.features.tokenreceive.impl.R
|
import com.tangem.features.tokenreceive.impl.R
|
||||||
import com.tangem.features.tokenreceive.ui.state.WarningUM
|
import com.tangem.features.tokenreceive.ui.state.WarningUM
|
||||||
|
|
@ -37,51 +34,51 @@ internal fun TokenReceiveWarningContent(warningUM: WarningUM) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(color = TangemTheme.colors.background.tertiary)
|
|
||||||
.padding(
|
.padding(
|
||||||
|
top = 28.dp,
|
||||||
start = 16.dp,
|
start = 16.dp,
|
||||||
end = 16.dp,
|
end = 16.dp,
|
||||||
bottom = 16.dp,
|
bottom = 16.dp,
|
||||||
).testTag(TokenReceiveWarningBottomSheetTestTags.BOTTOM_SHEET),
|
)
|
||||||
|
.testTag(TokenReceiveWarningBottomSheetTestTags.BOTTOM_SHEET),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
CurrencyIcon(
|
CurrencyIcon(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(8.dp)
|
.size(size = 76.dp),
|
||||||
.size(size = 64.dp),
|
|
||||||
state = warningUM.iconState,
|
state = warningUM.iconState,
|
||||||
shouldDisplayNetwork = true,
|
shouldDisplayNetwork = true,
|
||||||
iconSize = 56.dp,
|
networkBadgeSize = 24.dp,
|
||||||
|
iconSize = 72.dp,
|
||||||
)
|
)
|
||||||
|
SpacerH(32.dp)
|
||||||
SpacerH24()
|
|
||||||
|
|
||||||
WarningBlock(networkName = warningUM.network)
|
WarningBlock(networkName = warningUM.network)
|
||||||
|
SpacerH(8.dp)
|
||||||
SpacerH12()
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_description),
|
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_description),
|
||||||
style = TangemTheme.typography.body2,
|
style = TangemTheme.typography3.subheading.medium,
|
||||||
color = TangemTheme.colors.text.secondary,
|
color = TangemTheme.colors3.text.secondary,
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH(48.dp)
|
SpacerH(48.dp)
|
||||||
|
TangemButton(
|
||||||
SecondaryButton(
|
modifier = Modifier
|
||||||
modifier = Modifier.fillMaxWidth(),
|
.fillMaxWidth()
|
||||||
text = stringResourceSafe(R.string.common_got_it),
|
.padding(top = 16.dp),
|
||||||
|
variant = TangemButton.Variant.Secondary,
|
||||||
|
text = resourceReference(R.string.common_got_it),
|
||||||
onClick = {
|
onClick = {
|
||||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
warningUM.onWarningAcknowledged()
|
warningUM.onWarningAcknowledged()
|
||||||
},
|
},
|
||||||
|
size = TangemButton.Size.X12,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WarningBlock(networkName: String, modifier: Modifier = Modifier) {
|
private fun WarningBlock(networkName: String, modifier: Modifier = Modifier) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxWidth(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
|
@ -89,17 +86,15 @@ fun WarningBlock(networkName: String, modifier: Modifier = Modifier) {
|
||||||
Text(
|
Text(
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_title),
|
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_title),
|
||||||
style = TangemTheme.typography.h3,
|
style = TangemTheme.typography3.heading.small,
|
||||||
color = TangemTheme.colors.text.primary1,
|
color = TangemTheme.colors3.text.primary,
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerW6()
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_network_name, networkName),
|
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_network_name, networkName),
|
||||||
style = TangemTheme.typography.h3,
|
style = TangemTheme.typography3.heading.small,
|
||||||
color = TangemTheme.colors.text.primary1,
|
color = TangemTheme.colors3.text.primary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,27 +105,7 @@ fun WarningBlock(networkName: String, modifier: Modifier = Modifier) {
|
||||||
private fun Preview_TokenReceiveWarningContent(
|
private fun Preview_TokenReceiveWarningContent(
|
||||||
@PreviewParameter(TokenReceiveWarningContentProvider::class) warningUM: WarningUM,
|
@PreviewParameter(TokenReceiveWarningContentProvider::class) warningUM: WarningUM,
|
||||||
) {
|
) {
|
||||||
TangemThemePreview {
|
TangemThemePreviewRedesign {
|
||||||
TokenReceiveWarningContent(warningUM = warningUM)
|
TokenReceiveWarningContent(warningUM = warningUM)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class TokenReceiveWarningContentProvider : PreviewParameterProvider<WarningUM> {
|
|
||||||
val iconState = CurrencyIconState.TokenIcon(
|
|
||||||
url = null,
|
|
||||||
topBadgeIconResId = null,
|
|
||||||
fallbackTint = TangemColorPalette.Black,
|
|
||||||
fallbackBackground = TangemColorPalette.Meadow,
|
|
||||||
isGrayscale = false,
|
|
||||||
shouldShowCustomBadge = false,
|
|
||||||
)
|
|
||||||
|
|
||||||
override val values: Sequence<WarningUM>
|
|
||||||
get() = sequenceOf(
|
|
||||||
WarningUM(
|
|
||||||
iconState = iconState,
|
|
||||||
onWarningAcknowledged = {},
|
|
||||||
network = "Etherium",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
package com.tangem.features.tokenreceive.ui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
|
import androidx.compose.ui.platform.testTag
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
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 com.tangem.core.ui.components.SecondaryButton
|
||||||
|
import com.tangem.core.ui.components.SpacerH
|
||||||
|
import com.tangem.core.ui.components.SpacerH12
|
||||||
|
import com.tangem.core.ui.components.SpacerH24
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
|
import com.tangem.core.ui.res.TangemColorPalette
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
|
import com.tangem.core.ui.test.TokenReceiveWarningBottomSheetTestTags
|
||||||
|
import com.tangem.features.tokenreceive.impl.R
|
||||||
|
import com.tangem.features.tokenreceive.ui.state.WarningUM
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun TokenReceiveWarningContentLegacy(warningUM: WarningUM) {
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(color = TangemTheme.colors.background.tertiary)
|
||||||
|
.padding(
|
||||||
|
start = 16.dp,
|
||||||
|
end = 16.dp,
|
||||||
|
bottom = 16.dp,
|
||||||
|
)
|
||||||
|
.testTag(TokenReceiveWarningBottomSheetTestTags.BOTTOM_SHEET),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
CurrencyIcon(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.size(size = 64.dp),
|
||||||
|
state = warningUM.iconState,
|
||||||
|
shouldDisplayNetwork = true,
|
||||||
|
iconSize = 56.dp,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH24()
|
||||||
|
|
||||||
|
WarningBlock(networkName = warningUM.network)
|
||||||
|
|
||||||
|
SpacerH12()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_description),
|
||||||
|
style = TangemTheme.typography.body2,
|
||||||
|
color = TangemTheme.colors.text.secondary,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(48.dp)
|
||||||
|
|
||||||
|
SecondaryButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = stringResourceSafe(R.string.common_got_it),
|
||||||
|
onClick = {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
warningUM.onWarningAcknowledged()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun WarningBlock(networkName: String, modifier: Modifier = Modifier) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_title),
|
||||||
|
style = TangemTheme.typography.h3,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(6.dp)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_network_name, networkName),
|
||||||
|
style = TangemTheme.typography.h3,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
private fun Preview_TokenReceiveWarningContent(
|
||||||
|
@PreviewParameter(TokenReceiveWarningContentProvider::class) warningUM: WarningUM,
|
||||||
|
) {
|
||||||
|
TangemThemePreview {
|
||||||
|
TokenReceiveWarningContentLegacy(warningUM = warningUM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TokenReceiveWarningContentProvider : PreviewParameterProvider<WarningUM> {
|
||||||
|
val iconState = CurrencyIconState.TokenIcon(
|
||||||
|
url = null,
|
||||||
|
topBadgeIconResId = null,
|
||||||
|
fallbackTint = TangemColorPalette.Black,
|
||||||
|
fallbackBackground = TangemColorPalette.Meadow,
|
||||||
|
isGrayscale = false,
|
||||||
|
shouldShowCustomBadge = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
override val values: Sequence<WarningUM>
|
||||||
|
get() = sequenceOf(
|
||||||
|
WarningUM(
|
||||||
|
iconState = iconState,
|
||||||
|
onWarningAcknowledged = {},
|
||||||
|
network = "Etherium",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue