mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-15 05:27:28 +01:00
Use Compose for Library list and grid (#7520)
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package eu.kanade.presentation.library.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun BadgeGroup(
|
||||
modifier: Modifier = Modifier,
|
||||
shape: Shape = RoundedCornerShape(4.dp),
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
Row(modifier = modifier.clip(shape)) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Badge(
|
||||
text: String,
|
||||
color: Color = MaterialTheme.colorScheme.secondary,
|
||||
textColor: Color = MaterialTheme.colorScheme.onSecondary,
|
||||
shape: Shape = RectangleShape,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(color)
|
||||
.clip(shape),
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp),
|
||||
color = textColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package eu.kanade.presentation.library.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridScope
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.util.plus
|
||||
|
||||
@Composable
|
||||
fun LazyLibraryGrid(
|
||||
modifier: Modifier = Modifier,
|
||||
columns: Int,
|
||||
content: LazyGridScope.() -> Unit,
|
||||
) {
|
||||
LazyVerticalGrid(
|
||||
modifier = modifier,
|
||||
columns = if (columns == 0) GridCells.Adaptive(128.dp) else GridCells.Fixed(columns),
|
||||
contentPadding = PaddingValues(8.dp) + WindowInsets.navigationBars.asPaddingValues(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package eu.kanade.presentation.library.components
|
||||
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import eu.kanade.domain.manga.model.MangaCover
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
||||
|
||||
@Composable
|
||||
fun LibraryComfortableGrid(
|
||||
items: List<LibraryItem>,
|
||||
columns: Int,
|
||||
selection: List<LibraryManga>,
|
||||
onClick: (LibraryManga) -> Unit,
|
||||
onLongClick: (LibraryManga) -> Unit,
|
||||
) {
|
||||
LazyLibraryGrid(
|
||||
columns = columns,
|
||||
) {
|
||||
items(
|
||||
items = items,
|
||||
key = {
|
||||
it.manga.id!!
|
||||
},
|
||||
) { libraryItem ->
|
||||
LibraryComfortableGridItem(
|
||||
libraryItem,
|
||||
libraryItem.manga in selection,
|
||||
onClick,
|
||||
onLongClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LibraryComfortableGridItem(
|
||||
item: LibraryItem,
|
||||
isSelected: Boolean,
|
||||
onClick: (LibraryManga) -> Unit,
|
||||
onLongClick: (LibraryManga) -> Unit,
|
||||
) {
|
||||
val manga = item.manga
|
||||
LibraryGridItemSelectable(isSelected = isSelected) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
onClick(manga)
|
||||
},
|
||||
onLongClick = {
|
||||
onLongClick(manga)
|
||||
},
|
||||
),
|
||||
) {
|
||||
LibraryGridCover(
|
||||
mangaCover = MangaCover(
|
||||
manga.id!!,
|
||||
manga.source,
|
||||
manga.favorite,
|
||||
manga.thumbnail_url,
|
||||
manga.cover_last_modified,
|
||||
),
|
||||
downloadCount = item.downloadCount,
|
||||
unreadCount = item.unreadCount,
|
||||
isLocal = item.isLocal,
|
||||
language = item.sourceLanguage,
|
||||
)
|
||||
Text(
|
||||
text = manga.title,
|
||||
maxLines = 2,
|
||||
style = LocalTextStyle.current.copy(fontWeight = FontWeight.SemiBold),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package eu.kanade.presentation.library.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
||||
|
||||
@Composable
|
||||
fun LibraryCompactGrid(
|
||||
items: List<LibraryItem>,
|
||||
columns: Int,
|
||||
selection: List<LibraryManga>,
|
||||
onClick: (LibraryManga) -> Unit,
|
||||
onLongClick: (LibraryManga) -> Unit,
|
||||
) {
|
||||
LazyLibraryGrid(
|
||||
columns = columns,
|
||||
) {
|
||||
items(
|
||||
items = items,
|
||||
key = {
|
||||
it.manga.id!!
|
||||
},
|
||||
) { libraryItem ->
|
||||
LibraryCompactGridItem(
|
||||
item = libraryItem,
|
||||
isSelected = libraryItem.manga in selection,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LibraryCompactGridItem(
|
||||
item: LibraryItem,
|
||||
isSelected: Boolean,
|
||||
onClick: (LibraryManga) -> Unit,
|
||||
onLongClick: (LibraryManga) -> Unit,
|
||||
) {
|
||||
val manga = item.manga
|
||||
LibraryGridCover(
|
||||
modifier = Modifier
|
||||
.selectedOutline(isSelected)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
onClick(manga)
|
||||
},
|
||||
onLongClick = {
|
||||
onLongClick(manga)
|
||||
},
|
||||
),
|
||||
mangaCover = eu.kanade.domain.manga.model.MangaCover(
|
||||
manga.id!!,
|
||||
manga.source,
|
||||
manga.favorite,
|
||||
manga.thumbnail_url,
|
||||
manga.cover_last_modified,
|
||||
),
|
||||
downloadCount = item.downloadCount,
|
||||
unreadCount = item.unreadCount,
|
||||
isLocal = item.isLocal,
|
||||
language = item.sourceLanguage,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(bottomStart = 4.dp, bottomEnd = 4.dp))
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
0f to Color.Transparent,
|
||||
1f to Color(0xAA000000),
|
||||
),
|
||||
)
|
||||
.fillMaxHeight(0.33f)
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.BottomCenter),
|
||||
)
|
||||
Text(
|
||||
text = manga.title,
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.align(Alignment.BottomStart),
|
||||
maxLines = 2,
|
||||
style = LocalTextStyle.current.copy(color = Color.White, fontWeight = FontWeight.SemiBold),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package eu.kanade.presentation.library.components
|
||||
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
||||
|
||||
@Composable
|
||||
fun LibraryCoverOnlyGrid(
|
||||
items: List<LibraryItem>,
|
||||
columns: Int,
|
||||
selection: List<LibraryManga>,
|
||||
onClick: (LibraryManga) -> Unit,
|
||||
onLongClick: (LibraryManga) -> Unit,
|
||||
) {
|
||||
LazyLibraryGrid(
|
||||
columns = columns,
|
||||
) {
|
||||
items(
|
||||
items = items,
|
||||
key = {
|
||||
it.manga.id!!
|
||||
},
|
||||
) { libraryItem ->
|
||||
LibraryCoverOnlyGridItem(
|
||||
item = libraryItem,
|
||||
isSelected = libraryItem.manga in selection,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LibraryCoverOnlyGridItem(
|
||||
item: LibraryItem,
|
||||
isSelected: Boolean,
|
||||
onClick: (LibraryManga) -> Unit,
|
||||
onLongClick: (LibraryManga) -> Unit,
|
||||
) {
|
||||
val manga = item.manga
|
||||
LibraryGridCover(
|
||||
modifier = Modifier
|
||||
.selectedOutline(isSelected)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
onClick(manga)
|
||||
},
|
||||
onLongClick = {
|
||||
onLongClick(manga)
|
||||
},
|
||||
),
|
||||
mangaCover = eu.kanade.domain.manga.model.MangaCover(
|
||||
manga.id!!,
|
||||
manga.source,
|
||||
manga.favorite,
|
||||
manga.thumbnail_url,
|
||||
manga.cover_last_modified,
|
||||
),
|
||||
downloadCount = item.downloadCount,
|
||||
unreadCount = item.unreadCount,
|
||||
isLocal = item.isLocal,
|
||||
language = item.sourceLanguage,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package eu.kanade.presentation.library.components
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.components.MangaCover
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
@Composable
|
||||
fun LibraryGridCover(
|
||||
modifier: Modifier = Modifier,
|
||||
mangaCover: eu.kanade.domain.manga.model.MangaCover,
|
||||
downloadCount: Int,
|
||||
unreadCount: Int,
|
||||
isLocal: Boolean,
|
||||
language: String,
|
||||
content: @Composable BoxScope.() -> Unit = {},
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(MangaCover.Book.ratio),
|
||||
) {
|
||||
MangaCover.Book(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
data = mangaCover,
|
||||
)
|
||||
content()
|
||||
BadgeGroup(
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.align(Alignment.TopStart),
|
||||
) {
|
||||
if (downloadCount > 0) {
|
||||
Badge(
|
||||
text = "$downloadCount",
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
textColor = MaterialTheme.colorScheme.onTertiary,
|
||||
)
|
||||
}
|
||||
if (unreadCount > 0) {
|
||||
Badge(text = "$unreadCount")
|
||||
}
|
||||
}
|
||||
BadgeGroup(
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.align(Alignment.TopEnd),
|
||||
) {
|
||||
if (isLocal) {
|
||||
Badge(
|
||||
text = stringResource(id = R.string.local_source_badge),
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
textColor = MaterialTheme.colorScheme.onTertiary,
|
||||
)
|
||||
}
|
||||
if (isLocal.not() && language.isNotEmpty()) {
|
||||
Badge(
|
||||
text = language,
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
textColor = MaterialTheme.colorScheme.onTertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package eu.kanade.presentation.library.components
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.CornerRadius
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
fun Modifier.selectedOutline(isSelected: Boolean) = composed {
|
||||
val secondary = MaterialTheme.colorScheme.secondary
|
||||
if (isSelected) {
|
||||
drawBehind {
|
||||
val additional = 24.dp.value
|
||||
val offset = additional / 2
|
||||
val height = size.height + additional
|
||||
val width = size.width + additional
|
||||
drawRoundRect(
|
||||
color = secondary,
|
||||
topLeft = Offset(-offset, -offset),
|
||||
size = Size(width, height),
|
||||
cornerRadius = CornerRadius(offset),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LibraryGridItemSelectable(
|
||||
isSelected: Boolean,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
Box(Modifier.selectedOutline(isSelected)) {
|
||||
CompositionLocalProvider(LocalContentColor provides if (isSelected) MaterialTheme.colorScheme.onSecondary else MaterialTheme.colorScheme.onBackground) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package eu.kanade.presentation.library.components
|
||||
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
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.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.domain.manga.model.MangaCover
|
||||
import eu.kanade.presentation.util.horizontalPadding
|
||||
import eu.kanade.presentation.util.selectedBackground
|
||||
import eu.kanade.presentation.util.verticalPadding
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
||||
|
||||
@Composable
|
||||
fun LibraryList(
|
||||
items: List<LibraryItem>,
|
||||
columns: Int,
|
||||
selection: List<LibraryManga>,
|
||||
onClick: (LibraryManga) -> Unit,
|
||||
onLongClick: (LibraryManga) -> Unit,
|
||||
) {
|
||||
LazyColumn(
|
||||
contentPadding = WindowInsets.navigationBars.asPaddingValues(),
|
||||
) {
|
||||
items(
|
||||
items = items,
|
||||
key = {
|
||||
it.manga.id!!
|
||||
},
|
||||
) { libraryItem ->
|
||||
LibraryListItem(
|
||||
item = libraryItem,
|
||||
isSelected = libraryItem.manga in selection,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LibraryListItem(
|
||||
item: LibraryItem,
|
||||
isSelected: Boolean,
|
||||
onClick: (LibraryManga) -> Unit,
|
||||
onLongClick: (LibraryManga) -> Unit,
|
||||
) {
|
||||
val manga = item.manga
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.selectedBackground(isSelected)
|
||||
.height(56.dp)
|
||||
.combinedClickable(
|
||||
onClick = { onClick(manga) },
|
||||
onLongClick = { onLongClick(manga) },
|
||||
)
|
||||
.padding(horizontal = horizontalPadding),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
eu.kanade.presentation.components.MangaCover.Square(
|
||||
modifier = Modifier
|
||||
.padding(vertical = verticalPadding)
|
||||
.fillMaxHeight(),
|
||||
data = MangaCover(
|
||||
manga.id!!,
|
||||
manga.source,
|
||||
manga.favorite,
|
||||
manga.thumbnail_url,
|
||||
manga.cover_last_modified,
|
||||
),
|
||||
)
|
||||
Text(
|
||||
text = manga.title,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = horizontalPadding)
|
||||
.weight(1f),
|
||||
maxLines = 2,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
BadgeGroup {
|
||||
if (item.downloadCount > 0) {
|
||||
Badge(
|
||||
text = "${item.downloadCount}",
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
textColor = MaterialTheme.colorScheme.onTertiary,
|
||||
)
|
||||
}
|
||||
if (item.unreadCount > 0) {
|
||||
Badge(text = "${item.unreadCount}")
|
||||
}
|
||||
if (item.isLocal) {
|
||||
Badge(
|
||||
text = stringResource(id = R.string.local_source_badge),
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
textColor = MaterialTheme.colorScheme.onTertiary,
|
||||
)
|
||||
}
|
||||
if (item.isLocal.not() && item.sourceLanguage.isNotEmpty()) {
|
||||
Badge(
|
||||
text = item.sourceLanguage,
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
textColor = MaterialTheme.colorScheme.onTertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
package eu.kanade.presentation.util
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.LocalMinimumTouchTargetEnforcement
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
@@ -17,6 +20,15 @@ import androidx.compose.ui.unit.Constraints
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun Modifier.selectedBackground(isSelected: Boolean): Modifier = composed {
|
||||
if (isSelected) {
|
||||
val alpha = if (isSystemInDarkTheme()) 0.08f else 0.22f
|
||||
background(MaterialTheme.colorScheme.secondary.copy(alpha = alpha))
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
fun Modifier.secondaryItemAlpha(): Modifier = this.alpha(.78f)
|
||||
|
||||
fun Modifier.clickableNoIndication(
|
||||
|
||||
Reference in New Issue
Block a user