Skip to content

Instantly share code, notes, and snippets.

@AlexGladkov
Last active August 28, 2024 18:21
Show Gist options
  • Save AlexGladkov/b7e32217881afd357dd0da265c3e4f16 to your computer and use it in GitHub Desktop.
Save AlexGladkov/b7e32217881afd357dd0da265c3e4f16 to your computer and use it in GitHub Desktop.
ProductDetails + Jetpack Compose
def composeVersion = "1.0.0-beta01"
implementation "androidx.compose.ui:ui:$composeVersion"
// Tooling support (Previews, etc.)
implementation "androidx.compose.ui:ui-tooling:$composeVersion"
// Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
implementation "androidx.compose.foundation:foundation:$composeVersion"
// Material Design
implementation "androidx.compose.material:material:$composeVersion"
// Material design icons
implementation "androidx.compose.material:material-icons-core:$composeVersion"
implementation "androidx.compose.material:material-icons-extended:$composeVersion"
// Integration with observables
implementation "androidx.compose.runtime:runtime-livedata:$composeVersion"
implementation "androidx.compose.runtime:runtime-rxjava2:$composeVersion"
// Integration with ViewModels
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha02'
// Integration with activities
implementation 'androidx.activity:activity-compose:1.3.0-alpha03'
package ru.leroymerlin.library_sdk.screens.product_details
import android.media.Rating
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Color.Companion.Gray
import androidx.compose.ui.graphics.Color.Companion.White
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import ru.leroymerlin.library_sdk.screens.base.LightColors
val brownGreyColor = Color(0xFF959595)
val whiteTwo = Color(0xFFf9f9f9)
val veryLightPink = Color(0xFFeaeaea)
@ExperimentalFoundationApi
@Preview
@Composable
fun ComposablePreview() {
MaterialTheme(
colors = LightColors
) {
ProductScreen()
}
}
@Composable
fun Subtitle5(text: String, modifier: Modifier = Modifier) = Text(
modifier = modifier,
text = text,
style = TextStyle(color = Color.Black, fontSize = 14.sp, fontWeight = FontWeight.Normal)
)
@Composable
fun Caption(text: String, modifier: Modifier = Modifier) = Text(
modifier = modifier,
text = text,
style = TextStyle(color = brownGreyColor, fontSize = 12.sp, fontWeight = FontWeight.Normal)
)
@ExperimentalFoundationApi
@Composable
fun ProductScreen(productViewModel: ProductViewModel = viewModel()) {
val sku by productViewModel.sku.observeAsState()
val title by productViewModel.title.observeAsState()
LazyColumn(
content = {
stickyHeader {
Toolbar()
}
item { ImageHeader() }
item {
Text(
sku.orEmpty(), modifier = Modifier.padding(top = 24.dp, start = 16.dp),
style = TextStyle(color = brownGreyColor),
fontWeight = FontWeight.Normal,
fontSize = 12.sp
)
}
item {
Text(
title.orEmpty(),
modifier = Modifier.padding(top = 4.dp, start = 16.dp, end = 24.dp),
style = TextStyle(
color = Color.Black,
fontWeight = FontWeight.Medium,
fontSize = 20.sp
)
)
}
item { RatingRowView() }
item { PriceView(productViewModel = productViewModel) }
item { CountView(productViewModel = productViewModel) }
item { HeaderView(height = 68.dp, title = "Способы получения") }
item { DeliveryPickupView(productViewModel = productViewModel) }
item { HeaderView(height = 68.dp, title = "Характеристики") }
item { CharacteristicsView(productViewModel = productViewModel) }
},
modifier = Modifier.fillMaxSize()
)
}
@Composable
fun CharacteristicsView(productViewModel: ProductViewModel) {
val characteristics by productViewModel.characteristics.observeAsState(mutableListOf())
Column(modifier = Modifier.fillMaxWidth()) {
characteristics.map { CharacteristicCell(model = it) }
}
}
@Composable
fun CharacteristicCell(model: CharacteristicModel) {
Column {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 24.dp)
.height(60.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
model.title,
modifier = Modifier.weight(0.6f),
style = TextStyle(color = brownGreyColor)
)
Text(
model.value, modifier = Modifier
.weight(0.4f)
.padding(8.dp), style = TextStyle(color = Color.Black)
)
}
Divider(color = veryLightPink)
}
}
@Composable
fun DeliveryPickupView(productViewModel: ProductViewModel) {
val pickupStoresCount by productViewModel.pickupStoresCount.observeAsState(0)
Row(Modifier.padding(start = 16.dp, end = 24.dp, top = 22.dp, bottom = 22.dp)) {
Box(
Modifier
.background(color = brownGreyColor)
.size(24.dp)
)
Column(Modifier.padding(start = 24.dp)) {
Subtitle5("Доставка • Завтра, 25 июля")
Caption("На складе 112 шт.", Modifier.padding(top = 2.dp))
if (pickupStoresCount > 0) {
Subtitle5("Самовывоз • Сегодня", Modifier.padding(top = 16.dp))
Caption("Доступно в $pickupStoresCount магазинах", Modifier.padding(top = 2.dp))
}
}
}
}
@Composable
fun CountView(productViewModel: ProductViewModel) {
val availableCount by productViewModel.availableCount.observeAsState()
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.height(78.dp)
.padding(start = 16.dp, end = 24.dp)
) {
Box(
Modifier
.background(color = brownGreyColor)
.size(24.dp)
)
Column(
modifier = Modifier
.weight(1f)
.padding(start = 24.dp, end = 24.dp)
) {
Text("Рассчитать количество", style = TextStyle(color = Color.Black))
Text(
"В наличии: $availableCount",
style = TextStyle(color = brownGreyColor, fontSize = 12.sp)
)
}
Box(
Modifier
.background(color = brownGreyColor)
.size(24.dp)
)
}
}
@Composable
fun HeaderView(height: Dp, title: String) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(height = height)
.background(color = whiteTwo)
.padding(start = 16.dp, bottom = 16.dp),
contentAlignment = Alignment.BottomStart
) {
Text(title, style = TextStyle(fontWeight = FontWeight.Medium, fontSize = 16.sp))
}
}
@Composable
fun PriceView(productViewModel: ProductViewModel) {
val itemsInCart by productViewModel.itemsInCart.observeAsState()
Row(
modifier = Modifier
.height(80.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
"13 686,00", modifier = Modifier.padding(start = 16.dp),
style = TextStyle(color = Color.Black, fontSize = 20.sp, fontWeight = FontWeight.Medium)
)
Text(
"₽/шт.", modifier = Modifier
.weight(1f)
.padding(start = 4.dp), style = TextStyle(
color = brownGreyColor, fontSize = 12.sp
)
)
if (itemsInCart == 0) {
Button(
onClick = {
productViewModel.addToCart()
},
modifier = Modifier
.background(
color = MaterialTheme.colors.background,
shape = RoundedCornerShape(4.dp)
)
.height(48.dp)
.width(160.dp)
.padding(end = 24.dp),
) {
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) {
Text(
"В корзину",
style = TextStyle(
color = Color.White,
fontWeight = FontWeight.Medium,
fontSize = 16.sp
)
)
}
}
} else {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.height(48.dp)
.width(160.dp)
.padding(end = 24.dp)
) {
Text("$itemsInCart")
}
}
}
}
@Composable
fun RatingRowView() {
Box(
modifier = Modifier
.background(color = White)
.height(52.dp)
.fillMaxWidth()
)
}
@Composable
fun ImageHeader() {
Box(
modifier = Modifier
.background(color = White)
.height(300.dp)
.fillMaxWidth()
)
}
@Composable
fun Toolbar() {
Row(
modifier = Modifier
.height(44.dp)
.fillMaxWidth()
.background(color = MaterialTheme.colors.background)
) {
Text("Back", modifier = Modifier.weight(1f))
Text("Menu")
}
}
package ru.leroymerlin.library_sdk.screens.product_details
import android.widget.ListView
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
data class CharacteristicModel(
val title: String,
val value: String
)
class ProductViewModel: ViewModel() {
private val _sku: MutableLiveData<String> = MutableLiveData("Артикул: 80133659")
val sku: LiveData<String> = _sku
private val _title: MutableLiveData<String> = MutableLiveData("Дрель аккумуляторная Dexter, 18В, Li-ion, 2 Ач")
val title: LiveData<String> = _title
private val _itemsInCart: MutableLiveData<Int> = MutableLiveData(0)
val itemsInCart: LiveData<Int> = _itemsInCart
private val _availableCount: MutableLiveData<Int> = MutableLiveData(9999)
val availableCount: LiveData<Int> = _availableCount
private val _pickupStoresCount: MutableLiveData<Int> = MutableLiveData(10)
val pickupStoresCount: LiveData<Int> = _pickupStoresCount
private val _characteristics: MutableLiveData<List<CharacteristicModel>> = MutableLiveData(
listOf(
CharacteristicModel("Толщина (мм)", "12.5"),
CharacteristicModel("Вес, кг:", "8.8"),
CharacteristicModel("Марка", "KNAUF"),
CharacteristicModel("Страна производитель:", "Россия")
)
)
val characteristics: LiveData<List<CharacteristicModel>> = _characteristics
fun addToCart() {
_itemsInCart.postValue(1)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment