improvement(Android): Small redesign for Products to solve Play store issues

This commit is contained in:
Artem Chepurnoy 2024-09-02 11:11:02 +03:00
parent 7d1d927c4c
commit c046178df4
No known key found for this signature in database
GPG Key ID: FAC37D0CF674043E
1 changed files with 121 additions and 145 deletions

View File

@ -1,14 +1,13 @@
package com.artemchep.keyguard.feature.home.settings.component
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@ -18,7 +17,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Star
import androidx.compose.material3.Icon
@ -26,7 +24,6 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
@ -53,18 +50,12 @@ import com.artemchep.keyguard.feature.onboarding.onboardingItemsPremium
import com.artemchep.keyguard.platform.LocalLeContext
import com.artemchep.keyguard.res.Res
import com.artemchep.keyguard.res.*
import com.artemchep.keyguard.ui.Ah
import com.artemchep.keyguard.ui.DefaultEmphasisAlpha
import com.artemchep.keyguard.ui.ExpandedIfNotEmpty
import com.artemchep.keyguard.ui.FlatItemLayout
import com.artemchep.keyguard.ui.FlatItemTextContent
import com.artemchep.keyguard.ui.FlatSimpleNote
import com.artemchep.keyguard.ui.FlatTextFieldBadge
import com.artemchep.keyguard.ui.GridLayout
import com.artemchep.keyguard.ui.MediumEmphasisAlpha
import com.artemchep.keyguard.ui.SimpleNote
import com.artemchep.keyguard.ui.icons.ChevronIcon
import com.artemchep.keyguard.ui.shimmer.shimmer
import com.artemchep.keyguard.ui.skeleton.SkeletonText
import com.artemchep.keyguard.ui.theme.Dimens
import com.artemchep.keyguard.ui.theme.combineAlpha
@ -164,13 +155,7 @@ private fun SettingSubscriptions(
Section(text = stringResource(Res.string.pref_item_premium_membership_section_subscriptions_title))
loadableSubscriptions.fold(
ifLoading = {
GridLayout(
modifier = Modifier
.padding(horizontal = 8.dp),
columns = 2,
mainAxisSpacing = 8.dp,
crossAxisSpacing = 8.dp,
) {
SettingGroupLayout {
repeat(SubscriptionsCountDefault) {
SettingSubscriptionSkeletonItem(
modifier = Modifier,
@ -186,13 +171,7 @@ private fun SettingSubscriptions(
)
return@fold
}
GridLayout(
modifier = Modifier
.padding(horizontal = 8.dp),
columns = 2,
mainAxisSpacing = 8.dp,
crossAxisSpacing = 8.dp,
) {
SettingGroupLayout {
subscriptions.forEach { subscription ->
SettingSubscriptionItem(
modifier = Modifier,
@ -215,8 +194,10 @@ private fun SettingSubscriptions(
Section(text = stringResource(Res.string.pref_item_premium_membership_section_products_title))
loadableProducts.fold(
ifLoading = {
repeat(ProductsCountDefault) {
SettingSubscriptionSkeletonItem()
SettingGroupLayout {
repeat(ProductsCountDefault) {
SettingSubscriptionSkeletonItem()
}
}
},
ifOk = { products ->
@ -227,10 +208,12 @@ private fun SettingSubscriptions(
)
return@fold
}
products.forEach { product ->
SettingProductItem(
product = product,
)
SettingGroupLayout {
products.forEach { product ->
SettingProductItem(
product = product,
)
}
}
},
)
@ -241,28 +224,27 @@ private fun SettingSubscriptions(
private fun SettingSubscriptionSkeletonItem(
modifier: Modifier = Modifier,
) {
SettingSubscriptionContentItem(
modifier = modifier
.shimmer(),
SettingItemLayout(
modifier = modifier,
isActive = false,
) {
Column(
modifier = Modifier
.padding(8.dp),
) {
onClick = {
// Do nothing
},
title = {
SkeletonText(
modifier = Modifier
.fillMaxWidth(0.45f),
style = MaterialTheme.typography.titleSmall,
)
Spacer(modifier = Modifier.height(8.dp))
},
price = {
SkeletonText(
modifier = Modifier
.fillMaxWidth(0.45f),
style = MaterialTheme.typography.titleMedium,
)
}
}
},
)
}
@Composable
@ -271,44 +253,23 @@ private fun SettingSubscriptionItem(
subscription: Subscription,
) {
val context by rememberUpdatedState(LocalLeContext)
SettingSubscriptionContentItem(
val status = subscription.status
SettingItemLayout(
modifier = modifier,
isActive = subscription.status is Subscription.Status.Active,
) {
Column(
modifier = Modifier
.clickable(role = Role.Button) {
subscription.purchase(context)
}
.padding(8.dp),
) {
val localEmphasis = DefaultEmphasisAlpha
val localTextStyle = TextStyle(
color = LocalContentColor.current
.combineAlpha(localEmphasis),
)
CompositionLocalProvider(
LocalTextStyle provides MaterialTheme.typography.titleSmall
.merge(localTextStyle),
) {
Text(
subscription.title,
color = LocalContentColor.current
.combineAlpha(MediumEmphasisAlpha),
)
}
Spacer(modifier = Modifier.height(8.dp))
CompositionLocalProvider(
LocalTextStyle provides MaterialTheme.typography.titleMedium
.merge(localTextStyle),
) {
val text = "${subscription.price} / ${subscription.periodFormatted}"
Text(text)
}
Spacer(modifier = Modifier.height(8.dp))
val status = subscription.status
if (status is Subscription.Status.Inactive && status.trialPeriodFormatted != null) {
isActive = status is Subscription.Status.Active,
onClick = {
subscription.purchase(context)
},
title = {
Text(subscription.title)
},
price = {
val text = "${subscription.price} / ${subscription.periodFormatted}"
Text(text)
},
content = if (status is Subscription.Status.Inactive && status.trialPeriodFormatted != null) {
// composable
{
FlatTextFieldBadge(
type = TextFieldModel2.Vl.Type.INFO,
text = stringResource(
@ -317,15 +278,58 @@ private fun SettingSubscriptionItem(
),
)
}
}
} else {
null
},
)
}
@Composable
private fun SettingProductItem(
modifier: Modifier = Modifier,
product: Product,
) {
val context by rememberUpdatedState(LocalLeContext)
val status = product.status
SettingItemLayout(
modifier = modifier,
isActive = status is Product.Status.Active,
onClick = {
product.purchase(context)
},
title = {
Text(product.title)
},
price = {
Text(product.price)
},
)
}
@Composable
private fun SettingGroupLayout(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
GridLayout(
modifier = modifier
.padding(horizontal = 8.dp),
columns = 2,
mainAxisSpacing = 8.dp,
crossAxisSpacing = 8.dp,
) {
content()
}
}
@Composable
private fun SettingSubscriptionContentItem(
private fun SettingItemLayout(
modifier: Modifier = Modifier,
isActive: Boolean,
content: @Composable BoxScope.() -> Unit,
onClick: () -> Unit,
title: @Composable ColumnScope.() -> Unit,
price: @Composable ColumnScope.() -> Unit,
content: (@Composable ColumnScope.() -> Unit)? = null,
) {
val backgroundModifier = run {
val tintColor = MaterialTheme.colorScheme
@ -357,69 +361,41 @@ private fun SettingSubscriptionContentItem(
contentDescription = null,
)
}
content()
val updatedOnClick by rememberUpdatedState(onClick)
Column(
modifier = Modifier
.clickable(role = Role.Button) {
updatedOnClick()
}
.padding(8.dp),
) {
val localEmphasis = DefaultEmphasisAlpha
val localTitleTextStyle = TextStyle(
color = LocalContentColor.current
.combineAlpha(localEmphasis)
.combineAlpha(MediumEmphasisAlpha),
)
val localPriceTextStyle = TextStyle(
color = LocalContentColor.current
.combineAlpha(localEmphasis),
)
CompositionLocalProvider(
LocalTextStyle provides MaterialTheme.typography.titleSmall
.merge(localTitleTextStyle),
) {
title()
}
Spacer(modifier = Modifier.height(8.dp))
CompositionLocalProvider(
LocalTextStyle provides MaterialTheme.typography.titleMedium
.merge(localPriceTextStyle),
) {
price()
}
if (content != null) {
Spacer(modifier = Modifier.height(8.dp))
content()
}
}
}
}
@Composable
private fun SettingProductItem(
product: Product,
) {
val context by rememberUpdatedState(LocalLeContext)
FlatItemLayout(
leading = {
val backgroundColor = MaterialTheme.colorScheme.secondaryContainer
Box(
modifier = Modifier
.size(24.dp)
.background(backgroundColor, CircleShape)
.padding(4.dp),
) {
val targetContentColor = kotlin.run {
val active = product.status is Product.Status.Active
if (active) {
MaterialTheme.colorScheme.primary
} else {
contentColorFor(backgroundColor)
}
}
val contentColor by animateColorAsState(targetValue = targetContentColor)
Icon(
Icons.Outlined.Star,
contentDescription = null,
tint = contentColor,
)
}
},
elevation = 2.dp,
trailing = {
ChevronIcon()
},
content = {
FlatItemTextContent(
title = {
Text(product.price)
},
text = {
Text(product.title)
},
)
val statusOrNull = product.status as? Product.Status.Active
ExpandedIfNotEmpty(statusOrNull) {
Row(
modifier = Modifier
.padding(top = 4.dp),
) {
Ah(
score = 1f,
text = stringResource(Res.string.pref_item_premium_status_active),
)
}
}
},
onClick = {
product.purchase(context)
},
)
}