diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt index 63bab8fcdb..b8d8025916 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt @@ -35,7 +35,7 @@ internal sealed class SettingsItem( data class WalletConnect( override val onClick: () -> Unit, ) : SettingsItem( - iconResId = R.drawable.ic_walletconnect, + iconResId = R.drawable.ic_wallet_connect_24, title = resourceReference(R.string.wallet_connect_title), subtitle = resourceReference(R.string.wallet_connect_subtitle), isLarge = true, @@ -81,14 +81,14 @@ internal sealed class SettingsItem( data class Chat( override val onClick: () -> Unit, ) : SettingsItem( - iconResId = R.drawable.ic_chat, + iconResId = R.drawable.ic_chat_24, title = resourceReference(R.string.details_chat), ) data class SendFeedback( override val onClick: () -> Unit, ) : SettingsItem( - iconResId = R.drawable.ic_comment, + iconResId = R.drawable.ic_comment_24, title = resourceReference(R.string.details_row_title_contact_to_support), ) @@ -102,7 +102,7 @@ internal sealed class SettingsItem( data class TermsOfService( override val onClick: () -> Unit, ) : SettingsItem( - iconResId = R.drawable.ic_text, + iconResId = R.drawable.ic_text_24, title = resourceReference(R.string.disclaimer_title), ) @@ -125,15 +125,15 @@ internal sealed class EventError { } sealed class SocialNetwork(val id: String, val iconRes: Int) { - object Twitter : SocialNetwork("Twitter", R.drawable.ic_twitter) - object Telegram : SocialNetwork("Telegram", R.drawable.ic_telegram) - object Discord : SocialNetwork("Discord", R.drawable.ic_discord) - object Reddit : SocialNetwork("Reddit", R.drawable.ic_reddit) - object Instagram : SocialNetwork("Instagram", R.drawable.ic_instagram) - object GitHub : SocialNetwork("GitHub", R.drawable.ic_github) - object Facebook : SocialNetwork("Facebook", R.drawable.ic_facebook) - object LinkedIn : SocialNetwork("LinkedIn", R.drawable.ic_linkedin) - object YouTube : SocialNetwork("YouTube", R.drawable.ic_youtube) + object Twitter : SocialNetwork("Twitter", R.drawable.ic_twitter_24) + object Telegram : SocialNetwork("Telegram", R.drawable.ic_telegram_24) + object Discord : SocialNetwork("Discord", R.drawable.ic_discord_24) + object Reddit : SocialNetwork("Reddit", R.drawable.ic_reddit_24) + object Instagram : SocialNetwork("Instagram", R.drawable.ic_instagram_24) + object GitHub : SocialNetwork("GitHub", R.drawable.ic_github_24) + object Facebook : SocialNetwork("Facebook", R.drawable.ic_facebook_24) + object LinkedIn : SocialNetwork("LinkedIn", R.drawable.ic_linkedin_24) + object YouTube : SocialNetwork("YouTube", R.drawable.ic_youtube_24) } internal object TangemSocialAccounts { diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt index 79e8b38b23..7e5b3542cd 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt @@ -88,7 +88,7 @@ private fun EmptyScreen(state: WalletConnectScreenState) { horizontalAlignment = Alignment.CenterHorizontally, ) { Image( - painter = painterResource(id = R.drawable.ic_walletconnect), + painter = painterResource(id = R.drawable.ic_wallet_connect_24), contentDescription = "", colorFilter = ColorFilter.tint(TangemTheme.colors.icon.inactive), contentScale = ContentScale.FillWidth, diff --git a/app/src/main/res/drawable/ic_chat.xml b/core/ui/src/main/res/drawable/ic_chat_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_chat.xml rename to core/ui/src/main/res/drawable/ic_chat_24.xml diff --git a/app/src/main/res/drawable/ic_comment.xml b/core/ui/src/main/res/drawable/ic_comment_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_comment.xml rename to core/ui/src/main/res/drawable/ic_comment_24.xml diff --git a/app/src/main/res/drawable/ic_discord.xml b/core/ui/src/main/res/drawable/ic_discord_24.xml similarity index 97% rename from app/src/main/res/drawable/ic_discord.xml rename to core/ui/src/main/res/drawable/ic_discord_24.xml index 6502165e77..b1f5039116 100644 --- a/app/src/main/res/drawable/ic_discord.xml +++ b/core/ui/src/main/res/drawable/ic_discord_24.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> + android:fillColor="#000" /> diff --git a/app/src/main/res/drawable/ic_facebook.xml b/core/ui/src/main/res/drawable/ic_facebook_24.xml similarity index 94% rename from app/src/main/res/drawable/ic_facebook.xml rename to core/ui/src/main/res/drawable/ic_facebook_24.xml index 1db025e42c..eeb0ea2747 100644 --- a/app/src/main/res/drawable/ic_facebook.xml +++ b/core/ui/src/main/res/drawable/ic_facebook_24.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> + android:fillColor="#000" /> diff --git a/app/src/main/res/drawable/ic_github.xml b/core/ui/src/main/res/drawable/ic_github_24.xml similarity index 97% rename from app/src/main/res/drawable/ic_github.xml rename to core/ui/src/main/res/drawable/ic_github_24.xml index daa1de7021..8e105d74a6 100644 --- a/app/src/main/res/drawable/ic_github.xml +++ b/core/ui/src/main/res/drawable/ic_github_24.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> + android:fillColor="#000" /> diff --git a/app/src/main/res/drawable/ic_instagram.xml b/core/ui/src/main/res/drawable/ic_instagram_24.xml similarity index 95% rename from app/src/main/res/drawable/ic_instagram.xml rename to core/ui/src/main/res/drawable/ic_instagram_24.xml index 76744cf7f5..a1b00c2ca5 100644 --- a/app/src/main/res/drawable/ic_instagram.xml +++ b/core/ui/src/main/res/drawable/ic_instagram_24.xml @@ -8,12 +8,12 @@ android:pathData="M2.4,2.4h19.2v19.2h-19.2z"/> + android:fillColor="#000" /> + android:fillColor="#000" /> + android:fillColor="#000" /> diff --git a/app/src/main/res/drawable/ic_linkedin.xml b/core/ui/src/main/res/drawable/ic_linkedin_24.xml similarity index 95% rename from app/src/main/res/drawable/ic_linkedin.xml rename to core/ui/src/main/res/drawable/ic_linkedin_24.xml index 2df3cb834a..5f82e64300 100644 --- a/app/src/main/res/drawable/ic_linkedin.xml +++ b/core/ui/src/main/res/drawable/ic_linkedin_24.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> + android:fillColor="#000" /> diff --git a/app/src/main/res/drawable/ic_reddit.xml b/core/ui/src/main/res/drawable/ic_reddit_24.xml similarity index 98% rename from app/src/main/res/drawable/ic_reddit.xml rename to core/ui/src/main/res/drawable/ic_reddit_24.xml index 2a1e04a004..61919b1686 100644 --- a/app/src/main/res/drawable/ic_reddit.xml +++ b/core/ui/src/main/res/drawable/ic_reddit_24.xml @@ -5,6 +5,6 @@ android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_telegram.xml b/core/ui/src/main/res/drawable/ic_telegram_24.xml similarity index 95% rename from app/src/main/res/drawable/ic_telegram.xml rename to core/ui/src/main/res/drawable/ic_telegram_24.xml index 020ee3bc71..d2d923c5a3 100644 --- a/app/src/main/res/drawable/ic_telegram.xml +++ b/core/ui/src/main/res/drawable/ic_telegram_24.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> + android:fillColor="#000" /> diff --git a/app/src/main/res/drawable/ic_text.xml b/core/ui/src/main/res/drawable/ic_text_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_text.xml rename to core/ui/src/main/res/drawable/ic_text_24.xml diff --git a/app/src/main/res/drawable/ic_twitter.xml b/core/ui/src/main/res/drawable/ic_twitter_24.xml similarity index 92% rename from app/src/main/res/drawable/ic_twitter.xml rename to core/ui/src/main/res/drawable/ic_twitter_24.xml index 1c3cb6cfef..cd94ecb5b6 100644 --- a/app/src/main/res/drawable/ic_twitter.xml +++ b/core/ui/src/main/res/drawable/ic_twitter_24.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> + android:fillColor="#000" /> diff --git a/app/src/main/res/drawable/ic_walletconnect.xml b/core/ui/src/main/res/drawable/ic_wallet_connect_24.xml similarity index 96% rename from app/src/main/res/drawable/ic_walletconnect.xml rename to core/ui/src/main/res/drawable/ic_wallet_connect_24.xml index d4b4c99942..a4378111f1 100644 --- a/app/src/main/res/drawable/ic_walletconnect.xml +++ b/core/ui/src/main/res/drawable/ic_wallet_connect_24.xml @@ -2,6 +2,6 @@ android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> diff --git a/app/src/main/res/drawable/ic_youtube.xml b/core/ui/src/main/res/drawable/ic_youtube_24.xml similarity index 95% rename from app/src/main/res/drawable/ic_youtube.xml rename to core/ui/src/main/res/drawable/ic_youtube_24.xml index 6d5ade9d08..7eb2833038 100644 --- a/app/src/main/res/drawable/ic_youtube.xml +++ b/core/ui/src/main/res/drawable/ic_youtube_24.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> + android:fillColor="#000" /> diff --git a/features/details/impl/build.gradle.kts b/features/details/impl/build.gradle.kts index 76cfca8bdc..4f9498a097 100644 --- a/features/details/impl/build.gradle.kts +++ b/features/details/impl/build.gradle.kts @@ -26,6 +26,7 @@ dependencies { /* AndroidX */ implementation(deps.androidx.fragment.ktx) + implementation(deps.androidx.activity.compose) implementation(deps.lifecycle.compose) /* Compose */ diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt index c0c9d5492c..59a69914fd 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt @@ -3,12 +3,36 @@ package com.tangem.features.details.component.preview import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.tangem.features.details.component.DetailsComponent +import com.tangem.features.details.entity.DetailsFooterUM +import com.tangem.features.details.entity.DetailsUM +import com.tangem.features.details.ui.DetailsScreen +import com.tangem.features.details.utils.ItemsBuilder +import com.tangem.features.details.utils.SocialsBuilder +import kotlinx.coroutines.runBlocking internal class PreviewDetailsComponent : DetailsComponent { + private val previewBlocks = runBlocking { + ItemsBuilder( + walletConnectComponent = PreviewWalletConnectComponent(), + userWalletListComponent = PreviewUserWalletListComponent(), + ).buldAll() + } + + private val previewFooter = DetailsFooterUM( + socials = SocialsBuilder(urlOpener = { /* no-op */ }).buildAll(), + appVersion = "1.0.0-preview", + ) + + val previewState = DetailsUM( + items = previewBlocks, + footer = previewFooter, + popBack = { /* no-op */ }, + ) + @Composable @Suppress("TopLevelComposableFunctions") // TODO: Remove this check override fun View(modifier: Modifier) { - TODO("Will be implemented in [REDACTED_TASK_KEY]") + DetailsScreen(state = previewState, modifier = modifier) } } \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt index 8341d24070..c7628c2619 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt @@ -2,13 +2,63 @@ package com.tangem.features.details.component.preview import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.details.component.UserWalletListComponent +import com.tangem.features.details.entity.UserWalletListUM +import com.tangem.features.details.impl.R +import com.tangem.features.details.ui.UserWalletListBlock +import kotlinx.collections.immutable.persistentListOf internal class PreviewUserWalletListComponent : UserWalletListComponent { + private val previewState = UserWalletListUM( + userWallets = persistentListOf( + UserWalletListUM.UserWalletUM( + id = UserWalletId("user_wallet_1".encodeToByteArray()), + name = "My Wallet", + information = getInformation(3, "4 496,75 $"), + imageResId = R.drawable.ill_card_wallet_2_211_343, + onClick = {}, + ), + UserWalletListUM.UserWalletUM( + id = UserWalletId("user_wallet_2".encodeToByteArray()), + name = "Old wallet", + information = getInformation(3, "4 496,75 $"), + imageResId = R.drawable.ill_card_note_eth_211_343, + onClick = {}, + ), + UserWalletListUM.UserWalletUM( + id = UserWalletId("user_wallet_3".encodeToByteArray()), + name = "Multi Card", + information = getInformation(3, "4 496,75 $"), + imageResId = R.drawable.ill_card_note_bnb_211_343, + onClick = {}, + ), + ), + addNewWalletText = resourceReference(R.string.user_wallet_list_add_button), + isWalletSavingInProgress = false, + onAddNewWalletClick = {}, + ) + @Composable @Suppress("TopLevelComposableFunctions") // TODO: Remove this check override fun View(modifier: Modifier) { - TODO("Will be implemented in [REDACTED_TASK_KEY]") + UserWalletListBlock(state = previewState, modifier = modifier) + } + + private fun getInformation(cardCount: Int, totalBalance: String): TextReference { + val t1 = TextReference.PluralRes( + id = R.plurals.card_label_card_count, + count = cardCount, + formatArgs = wrappedList(cardCount), + ) + val divider = stringReference(value = " • ") + val t2 = stringReference(totalBalance) + + return TextReference.Combined(wrappedList(t1, divider, t2)) } } \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewWalletConnectComponent.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewWalletConnectComponent.kt index 6a4aa2df28..4f94585d78 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewWalletConnectComponent.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewWalletConnectComponent.kt @@ -3,6 +3,7 @@ package com.tangem.features.details.component.preview import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.tangem.features.details.component.WalletConnectComponent +import com.tangem.features.details.ui.WalletConnectBlock internal class PreviewWalletConnectComponent : WalletConnectComponent { @@ -11,6 +12,6 @@ internal class PreviewWalletConnectComponent : WalletConnectComponent { @Composable @Suppress("TopLevelComposableFunctions") // TODO: Remove this check override fun View(modifier: Modifier) { - TODO("Will be implemented in [REDACTED_TASK_KEY]") + WalletConnectBlock(onClick = { /* no-op */ }, modifier = modifier) } } \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/DetailsItemUM.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/DetailsItemUM.kt index 0dabab81bd..1aa5a52ab5 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/DetailsItemUM.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/DetailsItemUM.kt @@ -18,6 +18,7 @@ internal sealed class DetailsItemUM { ) : DetailsItemUM() { data class Item( + val id: String, val title: TextReference, @DrawableRes val iconRes: Int, diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/UserWalletListUM.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/UserWalletListUM.kt index 6848e0e77b..d6f947b063 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/UserWalletListUM.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/UserWalletListUM.kt @@ -7,6 +7,7 @@ import kotlinx.collections.immutable.ImmutableList internal data class UserWalletListUM( val userWallets: ImmutableList, + val isWalletSavingInProgress: Boolean, val addNewWalletText: TextReference, val onAddNewWalletClick: () -> Unit, ) { diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/BlockCard.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/BlockCard.kt new file mode 100644 index 0000000000..e11a41c41e --- /dev/null +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/BlockCard.kt @@ -0,0 +1,36 @@ +package com.tangem.features.details.ui + +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.material3.Card +import androidx.compose.material3.CardColors +import androidx.compose.runtime.Composable +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.ui.Modifier +import com.tangem.core.ui.res.TangemTheme + +@Composable +internal fun BlockCard( + modifier: Modifier = Modifier, + enabled: Boolean = true, + onClick: () -> Unit = {}, + content: @Composable ColumnScope.() -> Unit = {}, +) { + Card( + modifier = modifier, + onClick = onClick, + shape = TangemTheme.shapes.roundedCornersXMedium, + colors = BlockColors, + enabled = enabled, + content = content, + ) +} + +private val BlockColors: CardColors + @Composable + @ReadOnlyComposable + get() = CardColors( + containerColor = TangemTheme.colors.background.primary, + contentColor = TangemTheme.colors.text.primary1, + disabledContainerColor = TangemTheme.colors.button.disabled, + disabledContentColor = TangemTheme.colors.text.disabled, + ) \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/BlockItem.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/BlockItem.kt new file mode 100644 index 0000000000..80d99b3b20 --- /dev/null +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/BlockItem.kt @@ -0,0 +1,45 @@ +package com.tangem.features.details.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextOverflow +import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.details.entity.DetailsItemUM + +@Composable +internal fun BlockItem(model: DetailsItemUM.Basic.Item, modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier, + onClick = model.onClick, + ) { + Row( + modifier = Modifier.padding(all = TangemTheme.dimens.spacing12), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12, Alignment.Start), + ) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = model.iconRes), + tint = TangemTheme.colors.icon.secondary, + contentDescription = null, + ) + + Text( + text = model.title.resolveReference(), + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } +} \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/DetailsScreen.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/DetailsScreen.kt new file mode 100644 index 0000000000..ff67ebbd9e --- /dev/null +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/DetailsScreen.kt @@ -0,0 +1,221 @@ +package com.tangem.features.details.ui + +import android.content.res.Configuration +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.scrollable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.rememberScrollState +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.SystemBarsEffect +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.details.component.preview.PreviewDetailsComponent +import com.tangem.features.details.entity.DetailsFooterUM +import com.tangem.features.details.entity.DetailsItemUM +import com.tangem.features.details.entity.DetailsUM +import com.tangem.features.details.impl.R + +private const val COLLAPSED_APP_BAR_THRESHOLD = 0.4f + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun DetailsScreen(state: DetailsUM, modifier: Modifier = Modifier) { + val backgroundColor = TangemTheme.colors.background.secondary + val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() + + SystemBarsEffect { + setSystemBarsColor(backgroundColor) + } + + BackHandler(onBack = state.popBack) + + Scaffold( + modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + containerColor = backgroundColor, + topBar = { TopBar(state, scrollBehavior) }, + ) { paddingValues -> + Content( + modifier = Modifier.padding(paddingValues), + state = state, + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun TopBar(state: DetailsUM, scrollBehavior: TopAppBarScrollBehavior, modifier: Modifier = Modifier) { + MediumTopAppBar( + modifier = modifier, + scrollBehavior = scrollBehavior, + colors = TopAppBarColors( + containerColor = TangemTheme.colors.background.secondary, + scrolledContainerColor = TangemTheme.colors.background.secondary, + navigationIconContentColor = TangemTheme.colors.icon.primary1, + titleContentColor = TangemTheme.colors.text.primary1, + actionIconContentColor = TangemTheme.colors.icon.primary1, + ), + title = { + val collapsedStyle = TangemTheme.typography.subtitle1 + val expandedStyle = TangemTheme.typography.h1 + val style by remember(scrollBehavior.state.collapsedFraction) { + derivedStateOf { + if (scrollBehavior.state.collapsedFraction >= COLLAPSED_APP_BAR_THRESHOLD) { + collapsedStyle + } else { + expandedStyle + } + } + } + + Text( + text = stringResource(id = R.string.details_title), + style = style, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + }, + navigationIcon = { + IconButton( + modifier = Modifier.size(TangemTheme.dimens.size32), + onClick = state.popBack, + ) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = R.drawable.ic_back_24), + contentDescription = null, + ) + } + }, + ) +} + +@Composable +private fun Content(state: DetailsUM, modifier: Modifier = Modifier) { + LazyColumn( + modifier = modifier, + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16), + contentPadding = PaddingValues( + top = TangemTheme.dimens.spacing16, + bottom = TangemTheme.dimens.spacing16, + ), + ) { + items( + items = state.items, + key = DetailsItemUM::id, + ) { block -> + Block( + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16), + model = block, + ) + } + + item(key = "footer") { + Footer( + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing12), + model = state.footer, + ) + } + } +} + +@Composable +private fun Block(model: DetailsItemUM, modifier: Modifier = Modifier) { + Column( + modifier = modifier + .fillMaxWidth() + .background( + shape = TangemTheme.shapes.roundedCornersXMedium, + color = TangemTheme.colors.background.primary, + ), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top, + ) { + when (model) { + is DetailsItemUM.Basic -> { + model.items.forEach { item -> + key(item.id) { + BlockItem( + modifier = Modifier.fillMaxWidth(), + model = item, + ) + } + } + } + is DetailsItemUM.Component -> { + model.content( + modifier = Modifier.fillMaxWidth(), + ) + } + } + } +} + +@Composable +private fun Footer(model: DetailsFooterUM, modifier: Modifier = Modifier) { + Column( + modifier = modifier + .padding( + top = TangemTheme.dimens.spacing12, + bottom = TangemTheme.dimens.spacing16, + ) + .fillMaxWidth(), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16), + ) { + val socialsScrollState = rememberScrollState() + + Row( + modifier = Modifier + .fillMaxWidth() + .scrollable(socialsScrollState, orientation = Orientation.Horizontal), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), + ) { + model.socials.forEach { social -> + key(social.id) { + IconButton( + modifier = Modifier.size(TangemTheme.dimens.size32), + onClick = social.onClick, + ) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = social.iconResId), + tint = TangemTheme.colors.icon.informative, + contentDescription = null, + ) + } + } + } + } + + Text( + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing6), + text = model.appVersion, + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + ) + } +} + +// region Preview +@Composable +@Preview(showBackground = true, widthDp = 360) +@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun Preview_DetailsScreen() { + TangemThemePreview { + PreviewDetailsComponent().View(modifier = Modifier.fillMaxSize()) + } +} +// endregion Preview \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/UserWalletListBlock.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/UserWalletListBlock.kt new file mode 100644 index 0000000000..254c434047 --- /dev/null +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/UserWalletListBlock.kt @@ -0,0 +1,121 @@ +package com.tangem.features.details.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.key +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextOverflow +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.details.entity.UserWalletListUM +import com.tangem.features.details.impl.R + +@Composable +internal fun UserWalletListBlock(state: UserWalletListUM, modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier, + ) { + state.userWallets.forEach { model -> + key(model.id) { + UserWalletItem( + modifier = Modifier.fillMaxWidth(), + model = model, + ) + } + } + AddWalletButton( + text = state.addNewWalletText, + isInProgress = state.isWalletSavingInProgress, + onClick = state.onAddNewWalletClick, + ) + } +} + +@Composable +private fun UserWalletItem(model: UserWalletListUM.UserWalletUM, modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier, + onClick = model.onClick, + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .heightIn(min = TangemTheme.dimens.size68) + .padding(all = TangemTheme.dimens.spacing12), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), + ) { + Image( + modifier = Modifier + .width(TangemTheme.dimens.size24) + .height(TangemTheme.dimens.size36), + painter = painterResource(id = model.imageResId), + contentScale = ContentScale.FillBounds, + contentDescription = null, + ) + + Column( + modifier = Modifier.heightIn(min = TangemTheme.dimens.size40), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.SpaceEvenly, + ) { + Text( + text = model.name, + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + Text( + text = model.information.resolveReference(), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } + } +} + +@Composable +private fun AddWalletButton( + text: TextReference, + isInProgress: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + BlockCard( + modifier = modifier, + onClick = onClick, + enabled = !isInProgress, + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(all = TangemTheme.dimens.spacing12), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), + ) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = R.drawable.ic_plus_24), + tint = TangemTheme.colors.icon.accent, + contentDescription = null, + ) + + Text( + text = text.resolveReference(), + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.accent, + ) + } + } +} \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/WalletConnectBlock.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/WalletConnectBlock.kt new file mode 100644 index 0000000000..11a28b3a75 --- /dev/null +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/WalletConnectBlock.kt @@ -0,0 +1,51 @@ +package com.tangem.features.details.ui + +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import com.tangem.core.ui.res.TangemColorPalette +import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.details.impl.R + +@Composable +internal fun WalletConnectBlock(onClick: () -> Unit, modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier, + onClick = onClick, + ) { + Row( + modifier = Modifier.padding(all = TangemTheme.dimens.spacing12), + verticalAlignment = Alignment.Top, + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), + ) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = R.drawable.ic_wallet_connect_24), + tint = TangemColorPalette.Azure, + contentDescription = null, + ) + + Column( + modifier = Modifier.heightIn(min = TangemTheme.dimens.size48), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.SpaceAround, + ) { + Text( + text = stringResource(id = R.string.wallet_connect_title), + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + ) + Text( + text = stringResource(id = R.string.wallet_connect_subtitle), + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.secondary, + ) + } + } + } +} \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt new file mode 100644 index 0000000000..9ef2760ab6 --- /dev/null +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt @@ -0,0 +1,97 @@ +package com.tangem.features.details.utils + +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.features.details.component.UserWalletListComponent +import com.tangem.features.details.component.WalletConnectComponent +import com.tangem.features.details.entity.DetailsItemUM +import com.tangem.features.details.impl.BuildConfig +import com.tangem.features.details.impl.R +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList + +internal class ItemsBuilder( + private val walletConnectComponent: WalletConnectComponent, + private val userWalletListComponent: UserWalletListComponent, +) { + + suspend fun buldAll(): ImmutableList = buildList { + buildWalletConnectBlock()?.let(::add) + buildUserWalletListBlock().let(::add) + buildShopBlock().let(::add) + buildSettingsBlock().let(::add) + buildSupportBlock().let(::add) + }.toImmutableList() + + private suspend fun buildWalletConnectBlock(): DetailsItemUM? { + return if (walletConnectComponent.checkIsAvailable()) { + DetailsItemUM.Component( + id = "wallet_connect", + content = { + walletConnectComponent.View(modifier = it) + }, + ) + } else { + null + } + } + + fun buildUserWalletListBlock(): DetailsItemUM = DetailsItemUM.Component( + id = "user_wallet_list", + content = { + userWalletListComponent.View(modifier = it) + }, + ) + + private fun buildShopBlock(): DetailsItemUM = DetailsItemUM.Basic( + id = "shop", + items = persistentListOf( + DetailsItemUM.Basic.Item( + id = "buy_tangem_wallet", + title = stringReference("Buy Tangem Wallet"), // TODO: Move to resources in [REDACTED_TASK_KEY] + iconRes = R.drawable.ic_tangem_24, + onClick = { /* [REDACTED_TODO_COMMENT] */ }, + ), + ), + ) + + private fun buildSettingsBlock(): DetailsItemUM = DetailsItemUM.Basic( + id = "settings", + items = buildList { + DetailsItemUM.Basic.Item( + id = "app_settings", + title = resourceReference(R.string.app_settings_title), + iconRes = R.drawable.ic_settings_24, + onClick = { /* [REDACTED_TODO_COMMENT] */ }, + ).let(::add) + + if (BuildConfig.TESTER_MENU_ENABLED) { + DetailsItemUM.Basic.Item( + id = "tester_menu", + title = stringReference(value = "Tester menu"), + iconRes = R.drawable.ic_alert_24, + onClick = { /* [REDACTED_TODO_COMMENT] */ }, + ).let(::add) + } + }.toImmutableList(), + ) + + private fun buildSupportBlock(): DetailsItemUM = DetailsItemUM.Basic( + id = "support", + items = persistentListOf( + DetailsItemUM.Basic.Item( + id = "send_feedback", + title = stringReference("Send feedback"), // TODO: Move to resources in [REDACTED_TASK_KEY] + iconRes = R.drawable.ic_comment_24, + onClick = { /* [REDACTED_TODO_COMMENT] */ }, + ), + DetailsItemUM.Basic.Item( + id = "disclaimer", + title = resourceReference(R.string.disclaimer_title), + iconRes = R.drawable.ic_text_24, + onClick = { /* [REDACTED_TODO_COMMENT] */ }, + ), + ), + ) +} \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/SocialsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/SocialsBuilder.kt new file mode 100644 index 0000000000..d2666a03e7 --- /dev/null +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/SocialsBuilder.kt @@ -0,0 +1,84 @@ +package com.tangem.features.details.utils + +import androidx.compose.ui.text.intl.Locale +import com.tangem.features.details.entity.DetailsFooterUM +import com.tangem.features.details.impl.R +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList + +internal class SocialsBuilder( + private val urlOpener: (url: String) -> Unit, +) { + + fun buildAll(): ImmutableList = Social.all.map { social -> + DetailsFooterUM.Social( + id = social.name, + iconResId = social.iconResId, + onClick = { openUrl(social) }, + ) + }.toImmutableList() + + private fun openUrl(social: Social) { + val locale = Locale.current.region + + if (locale == RUSSIA_LOCALE && social.urlRu != null) { + urlOpener(social.urlRu) + } else { + urlOpener(social.url) + } + } + + private enum class Social( + val iconResId: Int, + val url: String, + val urlRu: String? = null, + ) { + X( + iconResId = R.drawable.ic_twitter_24, + url = "https://x.com/tangem", + ), + TELEGRAM( + iconResId = R.drawable.ic_telegram_24, + url = "https://t.me/tangem_chat", + urlRu = "https://t.me/tangem_chat_ru", + ), + DISCORD( + iconResId = R.drawable.ic_discord_24, + url = "https://discord.gg/tangem", + ), + REDDIT( + iconResId = R.drawable.ic_reddit_24, + url = "https://www.reddit.com/r/Tangem/", + ), + INSTAGRAM( + iconResId = R.drawable.ic_instagram_24, + url = "https://www.instagram.com/tangemwallet", + ), + GIT_HUB( + iconResId = R.drawable.ic_github_24, + url = "https://github.com/tangem", + ), + FACEBOOK( + iconResId = R.drawable.ic_facebook_24, + url = "https://www.facebook.com/tangemwallet", + ), + LINKEDIN( + iconResId = R.drawable.ic_linkedin_24, + url = "https://www.linkedin.com/company/tangem", + ), + YOUTUBE( + iconResId = R.drawable.ic_youtube_24, + url = "https://youtube.com/@tangem_official", + ), + ; + + companion object { + + val all = values() + } + } + + private companion object { + const val RUSSIA_LOCALE = "ru" + } +} \ No newline at end of file diff --git a/features/details/impl/src/main/res/drawable/ill_card_note_bnb_211_343.png b/features/details/impl/src/main/res/drawable/ill_card_note_bnb_211_343.png new file mode 100644 index 0000000000..033efd2699 Binary files /dev/null and b/features/details/impl/src/main/res/drawable/ill_card_note_bnb_211_343.png differ diff --git a/features/details/impl/src/main/res/drawable/ill_card_note_eth_211_343.png b/features/details/impl/src/main/res/drawable/ill_card_note_eth_211_343.png new file mode 100644 index 0000000000..b338ee1eb5 Binary files /dev/null and b/features/details/impl/src/main/res/drawable/ill_card_note_eth_211_343.png differ diff --git a/features/details/impl/src/main/res/drawable/ill_card_wallet_2_211_343.png b/features/details/impl/src/main/res/drawable/ill_card_wallet_2_211_343.png new file mode 100644 index 0000000000..9625b941a1 Binary files /dev/null and b/features/details/impl/src/main/res/drawable/ill_card_wallet_2_211_343.png differ