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,61 +37,95 @@ 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()
) { ) {
BookContent(bookOnDisk, selectionMode, onCheckedChange)
}
}
@Composable
private fun BookContent(
bookOnDisk: BookOnDisk,
selectionMode: SelectionMode,
onCheckedChange: (Boolean) -> Unit
) {
Row( Row(
modifier = Modifier modifier = Modifier.padding(SIXTEEN_DP).fillMaxWidth(),
.padding(dimensionResource(id = R.dimen.activity_horizontal_margin))
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
if (isCheckboxVisible) { if (selectionMode == SelectionMode.MULTI) {
Checkbox( BookCheckbox(bookOnDisk, onCheckedChange)
checked = isChecked,
onCheckedChange = onCheckedChange,
modifier = Modifier.padding(end = 10.dp)
)
} }
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( Icon(
painter = bookOnDisk.book.faviconToPainter(), painter = painter,
contentDescription = stringResource(R.string.fav_icon), contentDescription = stringResource(R.string.fav_icon),
modifier = Modifier modifier = Modifier
.size(40.dp) .size(BOOK_ICON_SIZE)
.padding(end = 10.dp) .padding(end = TEN_DP)
) )
}
Column( @Composable
modifier = Modifier.weight(1f) private fun BookDetails(modifier: Modifier, bookOnDisk: BookOnDisk) {
) { Column(modifier = modifier) {
Text( Text(
text = bookOnDisk.book.title, text = bookOnDisk.book.title,
style = MaterialTheme.typography.titleMedium style = MaterialTheme.typography.titleMedium
@ -104,29 +139,27 @@ fun BookItem(
) )
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(top = 4.dp) modifier = Modifier.padding(top = FOUR_DP)
) { ) {
Text( Text(
text = bookOnDisk.book.date, text = bookOnDisk.book.date,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(EIGHT_DP))
Text( Text(
text = bookOnDisk.book.size, text = bookOnDisk.book.size,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(EIGHT_DP))
Text( Text(
text = bookOnDisk.book.articleCount.orEmpty(), text = bookOnDisk.book.articleCount.orEmpty(),
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
} }
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(FOUR_DP))
tags() 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
} }