From 817ec20ad9cd972b97b9c297fa3b19418b47a838 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Wed, 12 Mar 2025 17:51:22 +0530 Subject: [PATCH] Created `ZimHostScreen` compose screen. * Created BookItem, and LanguageHeader compose screens which we are showing on the ZimHostScreen. --- .../java/org/kiwix/kiwixmobile/ui/BookItem.kt | 132 ++++++++++++++ .../kiwix/kiwixmobile/ui/LanguageHeader.kt | 39 +++++ .../kiwixmobile/webserver/ZimHostFragment.kt | 2 +- .../kiwixmobile/webserver/ZimHostScreen.kt | 164 ++++++++++++++++++ .../kiwixmobile/core/utils/ComposeDimens.kt | 8 + 5 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/kiwix/kiwixmobile/ui/BookItem.kt create mode 100644 app/src/main/java/org/kiwix/kiwixmobile/ui/LanguageHeader.kt create mode 100644 app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostScreen.kt diff --git a/app/src/main/java/org/kiwix/kiwixmobile/ui/BookItem.kt b/app/src/main/java/org/kiwix/kiwixmobile/ui/BookItem.kt new file mode 100644 index 000000000..4477afd30 --- /dev/null +++ b/app/src/main/java/org/kiwix/kiwixmobile/ui/BookItem.kt @@ -0,0 +1,132 @@ +/* + * Kiwix Android + * Copyright (c) 2025 Kiwix + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package org.kiwix.kiwixmobile.ui + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Checkbox +import androidx.compose.material3.Icon +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.dimensionResource +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.zim_manager.fileselect_view.SelectionMode +import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk + +@Suppress("UnusedParameter", "LongMethod", "ComposableLambdaParameterNaming") +@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 = {} +) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(dimensionResource(id = R.dimen.card_margin)) + .clickable { onClick(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() + } + } + } +} diff --git a/app/src/main/java/org/kiwix/kiwixmobile/ui/LanguageHeader.kt b/app/src/main/java/org/kiwix/kiwixmobile/ui/LanguageHeader.kt new file mode 100644 index 000000000..b08a07b08 --- /dev/null +++ b/app/src/main/java/org/kiwix/kiwixmobile/ui/LanguageHeader.kt @@ -0,0 +1,39 @@ +/* + * Kiwix Android + * Copyright (c) 2025 Kiwix + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package org.kiwix.kiwixmobile.ui + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +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.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.LanguageItem + +@Composable +fun LanguageHeader(languageItem: LanguageItem) { + Text( + text = languageItem.text, + style = MaterialTheme.typography.titleMedium, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp) + ) +} diff --git a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostFragment.kt index 9019cb618..4c70ed6f3 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostFragment.kt @@ -263,7 +263,7 @@ class ZimHostFragment : BaseFragment(), ZimHostCallbacks, ZimHostContract.View { private fun startStopServer() { when { ServerUtils.isServerStarted -> stopServer() - selectedBooksPath.size > 0 -> { + selectedBooksPath.isNotEmpty() -> { when { connectivityReporter.checkWifi() -> startWifiDialog() connectivityReporter.checkTethering() -> startKiwixHotspot() diff --git a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostScreen.kt b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostScreen.kt new file mode 100644 index 000000000..e942f9335 --- /dev/null +++ b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostScreen.kt @@ -0,0 +1,164 @@ +/* + * Kiwix Android + * Copyright (c) 2025 Kiwix + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package org.kiwix.kiwixmobile.webserver + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.minimumInteractiveComponentSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import org.kiwix.kiwixmobile.core.R +import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar +import org.kiwix.kiwixmobile.core.ui.components.KiwixButton +import org.kiwix.kiwixmobile.core.ui.models.IconItem +import org.kiwix.kiwixmobile.core.ui.models.toPainter +import org.kiwix.kiwixmobile.core.ui.theme.KiwixTheme +import org.kiwix.kiwixmobile.core.utils.ComposeDimens.MATERIAL_MINIMUM_HEIGHT_AND_WIDTH +import org.kiwix.kiwixmobile.core.utils.ComposeDimens.MAXIMUM_HEIGHT_OF_QR_CODE +import org.kiwix.kiwixmobile.core.utils.ComposeDimens.MINIMUM_HEIGHT_OF_BOOKS_LIST +import org.kiwix.kiwixmobile.core.utils.ComposeDimens.MINIMUM_HEIGHT_OF_QR_CODE +import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP +import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem + +@Suppress("ComposableLambdaParameterNaming") +@Composable +fun ZimHostScreen( + serverIpText: String, + shareIconItem: Pair, () -> Unit>, + qrImageItem: Pair, IconItem>, + booksList: List, + startServerButtonItem: Pair, + navigationIcon: @Composable () -> Unit +) { + KiwixTheme { + Scaffold(topBar = { + KiwixAppBar(R.string.menu_wifi_hotspot, navigationIcon) + }) { contentPadding -> + Column(modifier = Modifier.fillMaxSize().padding(contentPadding)) { + Row( + modifier = Modifier.fillMaxWidth().padding(horizontal = SIXTEEN_DP), + verticalAlignment = Alignment.CenterVertically + ) { + ServerIpText(serverIpText, Modifier.weight(1f)) + ShareIcon(shareIconItem) + } + Column(modifier = Modifier.weight(1f).verticalScroll(rememberScrollState())) { + QRImage(qrImageItem) + BookItemList(booksList) + } + KiwixButton( + startServerButtonItem.first, + {}, + modifier = Modifier.fillMaxWidth(), + buttonBackgroundColor = startServerButtonItem.second + ) + } + } + } +} + +@Composable +fun ServerIpText( + serverIpText: String, + modifier: Modifier +) { + Text( + text = serverIpText, + modifier = modifier.minimumInteractiveComponentSize(), + textAlign = TextAlign.Start, + ) +} + +@Composable +fun ShareIcon(shareIconItem: Pair, () -> Unit>) { + if (shareIconItem.first.value) { + Image( + painter = painterResource(id = R.drawable.ic_share_35dp), + contentDescription = stringResource(id = R.string.share_host_address), + modifier = Modifier + .clickable { shareIconItem.second.invoke() } + .padding(4.dp) + .heightIn(min = MATERIAL_MINIMUM_HEIGHT_AND_WIDTH) + .widthIn(min = MATERIAL_MINIMUM_HEIGHT_AND_WIDTH), + contentScale = ContentScale.Inside + ) + } +} + +@Composable +fun QRImage(qrImageItem: Pair, IconItem>) { + Image( + painter = qrImageItem.second.toPainter(), + contentDescription = stringResource(id = R.string.qr_code), + modifier = Modifier + .fillMaxWidth() + .heightIn(min = MINIMUM_HEIGHT_OF_QR_CODE, max = MAXIMUM_HEIGHT_OF_QR_CODE) + .padding(horizontal = SIXTEEN_DP), + contentScale = ContentScale.Fit + ) +} + +@Suppress("UnusedParameter") +@Composable +fun BookItemList(booksList: List) { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .heightIn(min = MINIMUM_HEIGHT_OF_BOOKS_LIST), + content = { + } + ) +} + +// @Preview +// @Preview(name = "DarkMode", uiMode = Configuration.UI_MODE_NIGHT_YES) +// @Composable +// fun PreviewScreen() { +// val shareIconVisibility = remember { mutableStateOf(true) } +// ZimHostScreen( +// stringResource(R.string.server_textview_default_message), +// shareIconVisibility to {}, +// shareIconVisibility to IconItem.Drawable(org.kiwix.kiwixmobile.R.drawable.launch_screen), +// listOf(), +// stringResource(R.string.start_server_label) to StartServerGreen, +// { +// NavigationIcon(onClick = {}) +// } +// ) +// } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/ComposeDimens.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/ComposeDimens.kt index fd04ae553..1175e5b3c 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/ComposeDimens.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/ComposeDimens.kt @@ -82,4 +82,12 @@ object ComposeDimens { // AddNoteDialog dimens val MINIMUM_HEIGHT_OF_NOTE_TEXT_FILED = 120.dp + + // Material minimum width and height + val MATERIAL_MINIMUM_HEIGHT_AND_WIDTH = 48.dp + + // ZimHostFragment dimens + val MINIMUM_HEIGHT_OF_QR_CODE = 76.dp + val MAXIMUM_HEIGHT_OF_QR_CODE = 128.dp + val MINIMUM_HEIGHT_OF_BOOKS_LIST = 256.dp }