Refined the BookItem for better readability and maintainability.

* Created `ZimFileLanguageHeader` for showing the languages of ZIM files.
This commit is contained in:
MohitMaliFtechiz 2025-03-13 15:39:05 +05:30
parent 7cdcc0d021
commit 674ff5b24c
4 changed files with 119 additions and 81 deletions

View File

@ -18,7 +18,8 @@
package org.kiwix.kiwixmobile.ui
import androidx.compose.foundation.clickable
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -36,97 +37,129 @@ 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.dimensionResource
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.extensions.faviconToPainter
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.BOOK_ICON_SIZE
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.EIGHT_DP
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FIVE_DP
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FOUR_DP
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TEN_DP
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.SelectionMode
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
@Suppress("UnusedParameter", "LongMethod", "ComposableLambdaParameterNaming")
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun BookItem(
bookOnDisk: BookOnDisk,
onClick: (BookOnDisk) -> Unit,
onLongClick: (BookOnDisk) -> Unit,
onMultiSelect: (BookOnDisk) -> Unit,
selectionMode: SelectionMode,
isCheckboxVisible: Boolean = false,
isChecked: Boolean = false,
onCheckedChange: (Boolean) -> Unit = {},
tags: @Composable () -> Unit = {}
onClick: ((BookOnDisk) -> Unit)? = null,
onLongClick: ((BookOnDisk) -> Unit)? = null,
onMultiSelect: ((BookOnDisk) -> Unit)? = null,
selectionMode: SelectionMode = SelectionMode.NORMAL,
onCheckedChange: (Boolean) -> Unit = {}
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(dimensionResource(id = R.dimen.card_margin))
.clickable { onClick(bookOnDisk) },
.padding(FIVE_DP)
.combinedClickable(
onClick = {
when (selectionMode) {
SelectionMode.MULTI -> onMultiSelect?.invoke(bookOnDisk)
SelectionMode.NORMAL -> onClick?.invoke(bookOnDisk)
}
},
onLongClick = {
if (selectionMode == SelectionMode.NORMAL) {
onLongClick?.invoke(bookOnDisk)
}
}
),
shape = MaterialTheme.shapes.medium,
elevation = CardDefaults.elevatedCardElevation()
) {
Row(
modifier = Modifier
.padding(dimensionResource(id = R.dimen.activity_horizontal_margin))
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
if (isCheckboxVisible) {
Checkbox(
checked = isChecked,
onCheckedChange = onCheckedChange,
modifier = Modifier.padding(end = 10.dp)
)
}
Icon(
painter = bookOnDisk.book.faviconToPainter(),
contentDescription = stringResource(R.string.fav_icon),
modifier = Modifier
.size(40.dp)
.padding(end = 10.dp)
)
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = bookOnDisk.book.title,
style = MaterialTheme.typography.titleMedium
)
Text(
text = bookOnDisk.book.description.orEmpty(),
style = MaterialTheme.typography.bodyMedium,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(top = 4.dp)
) {
Text(
text = bookOnDisk.book.date,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = bookOnDisk.book.size,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = bookOnDisk.book.articleCount.orEmpty(),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(modifier = Modifier.height(4.dp))
tags()
}
}
BookContent(bookOnDisk, selectionMode, onCheckedChange)
}
}
@Composable
private fun BookContent(
bookOnDisk: BookOnDisk,
selectionMode: SelectionMode,
onCheckedChange: (Boolean) -> Unit
) {
Row(
modifier = Modifier.padding(SIXTEEN_DP).fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
if (selectionMode == SelectionMode.MULTI) {
BookCheckbox(bookOnDisk, onCheckedChange)
}
BookIcon(bookOnDisk.book.faviconToPainter())
BookDetails(Modifier.weight(1f), bookOnDisk)
}
}
@Composable
private fun BookCheckbox(bookOnDisk: BookOnDisk, onCheckedChange: (Boolean) -> Unit) {
Checkbox(
checked = bookOnDisk.isSelected,
onCheckedChange = onCheckedChange,
modifier = Modifier.padding(end = TEN_DP)
)
}
@Composable
fun BookIcon(painter: Painter) {
Icon(
painter = painter,
contentDescription = stringResource(R.string.fav_icon),
modifier = Modifier
.size(BOOK_ICON_SIZE)
.padding(end = TEN_DP)
)
}
@Composable
private fun BookDetails(modifier: Modifier, bookOnDisk: BookOnDisk) {
Column(modifier = modifier) {
Text(
text = bookOnDisk.book.title,
style = MaterialTheme.typography.titleMedium
)
Text(
text = bookOnDisk.book.description.orEmpty(),
style = MaterialTheme.typography.bodyMedium,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(top = FOUR_DP)
) {
Text(
text = bookOnDisk.book.date,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.width(EIGHT_DP))
Text(
text = bookOnDisk.book.size,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.width(EIGHT_DP))
Text(
text = bookOnDisk.book.articleCount.orEmpty(),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(modifier = Modifier.height(FOUR_DP))
TagsView(bookOnDisk.tags)
}
}

View File

@ -24,16 +24,16 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.EIGHT_DP
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.LanguageItem
@Composable
fun LanguageHeader(languageItem: LanguageItem) {
fun ZimFilesLanguageHeader(languageItem: LanguageItem) {
Text(
text = languageItem.text,
style = MaterialTheme.typography.titleMedium,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
.padding(vertical = EIGHT_DP)
)
}

View File

@ -24,6 +24,8 @@ import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.qrcode.QRCodeWriter
import javax.inject.Inject
import androidx.core.graphics.createBitmap
import androidx.core.graphics.set
/**
* Utility class to generate QR codes.
@ -47,10 +49,10 @@ class GenerateQR @Inject constructor() {
it[EncodeHintType.MARGIN] = 1
}
val bits = QRCodeWriter().encode(code, BarcodeFormat.QR_CODE, size, size, hints)
return Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565).also {
return createBitmap(size, size, Bitmap.Config.RGB_565).also {
for (x in 0 until size) {
for (y in 0 until size) {
it.setPixel(x, y, if (bits[x, y]) foregroundColor else backgroundColor)
it[x, y] = if (bits[x, y]) foregroundColor else backgroundColor
}
}
}

View File

@ -90,4 +90,7 @@ object ComposeDimens {
val MINIMUM_HEIGHT_OF_QR_CODE = 76.dp
val MAXIMUM_HEIGHT_OF_QR_CODE = 128.dp
val MINIMUM_HEIGHT_OF_BOOKS_LIST = 256.dp
// BookItem dimes
val BOOK_ICON_SIZE = 40.dp
}