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 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.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -36,97 +37,129 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.extensions.faviconToPainter 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.SelectionMode
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
@Suppress("UnusedParameter", "LongMethod", "ComposableLambdaParameterNaming") @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun BookItem( fun BookItem(
bookOnDisk: BookOnDisk, bookOnDisk: BookOnDisk,
onClick: (BookOnDisk) -> Unit, onClick: ((BookOnDisk) -> Unit)? = null,
onLongClick: (BookOnDisk) -> Unit, onLongClick: ((BookOnDisk) -> Unit)? = null,
onMultiSelect: (BookOnDisk) -> Unit, onMultiSelect: ((BookOnDisk) -> Unit)? = null,
selectionMode: SelectionMode, selectionMode: SelectionMode = SelectionMode.NORMAL,
isCheckboxVisible: Boolean = false, onCheckedChange: (Boolean) -> Unit = {}
isChecked: Boolean = false,
onCheckedChange: (Boolean) -> Unit = {},
tags: @Composable () -> Unit = {}
) { ) {
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(dimensionResource(id = R.dimen.card_margin)) .padding(FIVE_DP)
.clickable { onClick(bookOnDisk) }, .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, shape = MaterialTheme.shapes.medium,
elevation = CardDefaults.elevatedCardElevation() elevation = CardDefaults.elevatedCardElevation()
) { ) {
Row( BookContent(bookOnDisk, selectionMode, onCheckedChange)
modifier = Modifier }
.padding(dimensionResource(id = R.dimen.activity_horizontal_margin)) }
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically @Composable
) { private fun BookContent(
if (isCheckboxVisible) { bookOnDisk: BookOnDisk,
Checkbox( selectionMode: SelectionMode,
checked = isChecked, onCheckedChange: (Boolean) -> Unit
onCheckedChange = onCheckedChange, ) {
modifier = Modifier.padding(end = 10.dp) Row(
) modifier = Modifier.padding(SIXTEEN_DP).fillMaxWidth(),
} verticalAlignment = Alignment.CenterVertically
) {
Icon( if (selectionMode == SelectionMode.MULTI) {
painter = bookOnDisk.book.faviconToPainter(), BookCheckbox(bookOnDisk, onCheckedChange)
contentDescription = stringResource(R.string.fav_icon), }
modifier = Modifier BookIcon(bookOnDisk.book.faviconToPainter())
.size(40.dp) BookDetails(Modifier.weight(1f), bookOnDisk)
.padding(end = 10.dp) }
) }
Column( @Composable
modifier = Modifier.weight(1f) private fun BookCheckbox(bookOnDisk: BookOnDisk, onCheckedChange: (Boolean) -> Unit) {
) { Checkbox(
Text( checked = bookOnDisk.isSelected,
text = bookOnDisk.book.title, onCheckedChange = onCheckedChange,
style = MaterialTheme.typography.titleMedium modifier = Modifier.padding(end = TEN_DP)
) )
Text( }
text = bookOnDisk.book.description.orEmpty(),
style = MaterialTheme.typography.bodyMedium, @Composable
maxLines = 2, fun BookIcon(painter: Painter) {
overflow = TextOverflow.Ellipsis, Icon(
color = MaterialTheme.colorScheme.onSurfaceVariant painter = painter,
) contentDescription = stringResource(R.string.fav_icon),
Row( modifier = Modifier
verticalAlignment = Alignment.CenterVertically, .size(BOOK_ICON_SIZE)
modifier = Modifier.padding(top = 4.dp) .padding(end = TEN_DP)
) { )
Text( }
text = bookOnDisk.book.date,
style = MaterialTheme.typography.bodySmall, @Composable
color = MaterialTheme.colorScheme.onSurfaceVariant private fun BookDetails(modifier: Modifier, bookOnDisk: BookOnDisk) {
) Column(modifier = modifier) {
Spacer(modifier = Modifier.width(8.dp)) Text(
Text( text = bookOnDisk.book.title,
text = bookOnDisk.book.size, style = MaterialTheme.typography.titleMedium
style = MaterialTheme.typography.bodySmall, )
color = MaterialTheme.colorScheme.onSurfaceVariant Text(
) text = bookOnDisk.book.description.orEmpty(),
Spacer(modifier = Modifier.width(8.dp)) style = MaterialTheme.typography.bodyMedium,
Text( maxLines = 2,
text = bookOnDisk.book.articleCount.orEmpty(), overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant
color = MaterialTheme.colorScheme.onSurfaceVariant )
) Row(
} verticalAlignment = Alignment.CenterVertically,
Spacer(modifier = Modifier.height(4.dp)) modifier = Modifier.padding(top = FOUR_DP)
tags() ) {
} 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.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier 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 import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.LanguageItem
@Composable @Composable
fun LanguageHeader(languageItem: LanguageItem) { fun ZimFilesLanguageHeader(languageItem: LanguageItem) {
Text( Text(
text = languageItem.text, text = languageItem.text,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .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.EncodeHintType
import com.google.zxing.qrcode.QRCodeWriter import com.google.zxing.qrcode.QRCodeWriter
import javax.inject.Inject import javax.inject.Inject
import androidx.core.graphics.createBitmap
import androidx.core.graphics.set
/** /**
* Utility class to generate QR codes. * Utility class to generate QR codes.
@ -47,10 +49,10 @@ class GenerateQR @Inject constructor() {
it[EncodeHintType.MARGIN] = 1 it[EncodeHintType.MARGIN] = 1
} }
val bits = QRCodeWriter().encode(code, BarcodeFormat.QR_CODE, size, size, hints) 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 (x in 0 until size) {
for (y 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 MINIMUM_HEIGHT_OF_QR_CODE = 76.dp
val MAXIMUM_HEIGHT_OF_QR_CODE = 128.dp val MAXIMUM_HEIGHT_OF_QR_CODE = 128.dp
val MINIMUM_HEIGHT_OF_BOOKS_LIST = 256.dp val MINIMUM_HEIGHT_OF_BOOKS_LIST = 256.dp
// BookItem dimes
val BOOK_ICON_SIZE = 40.dp
} }