mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 02:36:24 -04:00
Created the TabsView
to display tabs on the Reader screen.
* Improved the UI of the `Reader screen` to display the tabs view properly. * Refactored functionalities in `CoreReaderFragment`, including bottom toolbar interactions, runtime UI updates, and handling of the "No Book Open" button, etc.
This commit is contained in:
parent
39baa985fb
commit
6ea560407d
@ -31,12 +31,12 @@ import com.adevinta.android.barista.interaction.BaristaSleepInteractions
|
||||
import org.kiwix.kiwixmobile.BaseRobot
|
||||
import org.kiwix.kiwixmobile.Findable.ViewId
|
||||
import org.kiwix.kiwixmobile.R
|
||||
import org.kiwix.kiwixmobile.core.main.reader.CONTENT_LOADING_PROGRESSBAR_TESTING_TAG
|
||||
import org.kiwix.kiwixmobile.core.utils.dialog.ALERT_DIALOG_CONFIRM_BUTTON_TESTING_TAG
|
||||
import org.kiwix.kiwixmobile.core.utils.files.Log
|
||||
import org.kiwix.kiwixmobile.localFileTransfer.LocalFileTransferRobot
|
||||
import org.kiwix.kiwixmobile.localFileTransfer.localFileTransfer
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.local.BOOK_LIST_TESTING_TAG
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.local.CONTENT_LOADING_PROGRESSBAR_TESTING_TAG
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.local.LOCAL_FILE_TRANSFER_MENU_BUTTON_TESTING_TAG
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.local.NO_FILE_TEXT_TESTING_TAG
|
||||
import org.kiwix.kiwixmobile.testutils.TestUtils
|
||||
|
@ -49,6 +49,7 @@ import org.kiwix.kiwixmobile.core.extensions.setBottomMarginToFragmentContainerV
|
||||
import org.kiwix.kiwixmobile.core.extensions.setImageDrawableCompat
|
||||
import org.kiwix.kiwixmobile.core.extensions.snack
|
||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||
import org.kiwix.kiwixmobile.core.extensions.update
|
||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
||||
import org.kiwix.kiwixmobile.core.main.reader.CoreReaderFragment
|
||||
import org.kiwix.kiwixmobile.core.main.CoreWebViewClient
|
||||
@ -79,10 +80,12 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val activity = activity as CoreMainActivity
|
||||
noOpenBookButton?.setOnClickListener {
|
||||
activity.navigate(
|
||||
KiwixReaderFragmentDirections.actionNavigationReaderToNavigationLibrary()
|
||||
)
|
||||
readerScreenState.update {
|
||||
copy(onOpenLibraryButtonClicked = {
|
||||
activity.navigate(
|
||||
KiwixReaderFragmentDirections.actionNavigationReaderToNavigationLibrary()
|
||||
)
|
||||
})
|
||||
}
|
||||
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
toolbar?.let { activity.setupDrawerToggle(it, true) }
|
||||
|
@ -67,6 +67,11 @@ import androidx.annotation.AnimRes
|
||||
import androidx.appcompat.app.ActionBar
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.Group
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
@ -111,6 +116,7 @@ import org.kiwix.kiwixmobile.core.BuildConfig
|
||||
import org.kiwix.kiwixmobile.core.CoreApp
|
||||
import org.kiwix.kiwixmobile.core.DarkModeConfig
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.R.string
|
||||
import org.kiwix.kiwixmobile.core.StorageObserver
|
||||
import org.kiwix.kiwixmobile.core.base.BaseFragment
|
||||
import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions
|
||||
@ -125,12 +131,12 @@ import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.observeNavigatio
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.requestNotificationPermission
|
||||
import org.kiwix.kiwixmobile.core.extensions.ViewGroupExtensions.findFirstTextView
|
||||
import org.kiwix.kiwixmobile.core.extensions.closeFullScreenMode
|
||||
import org.kiwix.kiwixmobile.core.extensions.getDialogHostComposeView
|
||||
import org.kiwix.kiwixmobile.core.extensions.getToolbarNavigationIcon
|
||||
import org.kiwix.kiwixmobile.core.extensions.setToolTipWithContentDescription
|
||||
import org.kiwix.kiwixmobile.core.extensions.showFullScreenMode
|
||||
import org.kiwix.kiwixmobile.core.extensions.snack
|
||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||
import org.kiwix.kiwixmobile.core.extensions.update
|
||||
import org.kiwix.kiwixmobile.core.main.AddNoteDialog
|
||||
import org.kiwix.kiwixmobile.core.main.CompatFindActionModeCallback
|
||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
||||
@ -150,7 +156,6 @@ import org.kiwix.kiwixmobile.core.main.MainRepositoryActions
|
||||
import org.kiwix.kiwixmobile.core.main.OnSwipeTouchListener
|
||||
import org.kiwix.kiwixmobile.core.main.ServiceWorkerUninitialiser
|
||||
import org.kiwix.kiwixmobile.core.main.TableDrawerAdapter
|
||||
import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin.FromExternalLaunch
|
||||
import org.kiwix.kiwixmobile.core.main.TableDrawerAdapter.DocumentSection
|
||||
import org.kiwix.kiwixmobile.core.main.TableDrawerAdapter.TableClickListener
|
||||
import org.kiwix.kiwixmobile.core.main.TabsAdapter
|
||||
@ -158,6 +163,7 @@ import org.kiwix.kiwixmobile.core.main.ToolbarScrollingKiwixWebView
|
||||
import org.kiwix.kiwixmobile.core.main.UNINITIALISER_ADDRESS
|
||||
import org.kiwix.kiwixmobile.core.main.WebViewCallback
|
||||
import org.kiwix.kiwixmobile.core.main.WebViewProvider
|
||||
import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin.FromExternalLaunch
|
||||
import org.kiwix.kiwixmobile.core.navigateToAppSettings
|
||||
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
|
||||
import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryClickListener
|
||||
@ -174,6 +180,8 @@ import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.SearchItemToOpen
|
||||
import org.kiwix.kiwixmobile.core.ui.components.NavigationIcon
|
||||
import org.kiwix.kiwixmobile.core.ui.models.IconItem
|
||||
import org.kiwix.kiwixmobile.core.utils.AnimationUtils.rotate
|
||||
import org.kiwix.kiwixmobile.core.utils.DimenUtils.getToolbarHeight
|
||||
import org.kiwix.kiwixmobile.core.utils.DimenUtils.getWindowWidth
|
||||
@ -193,6 +201,7 @@ import org.kiwix.kiwixmobile.core.utils.TAG_FILE_SEARCHED
|
||||
import org.kiwix.kiwixmobile.core.utils.TAG_FILE_SEARCHED_NEW_TAB
|
||||
import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX
|
||||
import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower
|
||||
import org.kiwix.kiwixmobile.core.utils.dialog.DialogHost
|
||||
import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower
|
||||
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
|
||||
import org.kiwix.kiwixmobile.core.utils.dialog.UnsupportedMimeTypeHandler
|
||||
@ -361,6 +370,38 @@ abstract class CoreReaderFragment :
|
||||
private var isReadSelection = false
|
||||
private var isReadAloudServiceRunning = false
|
||||
private var libkiwixBook: Book? = null
|
||||
|
||||
private var composeView: ComposeView? = null
|
||||
protected val readerScreenState = mutableStateOf(
|
||||
ReaderScreenState(
|
||||
snackBarHostState = SnackbarHostState(),
|
||||
isNoBookOpenInReader = false,
|
||||
onOpenLibraryButtonClicked = {},
|
||||
pageLoadingItem = false to ZERO,
|
||||
shouldShowDonationPopup = false,
|
||||
// TODO set in onViewCreated.
|
||||
fullScreenItem = false to null,
|
||||
showBackToTopButton = false,
|
||||
backToTopButtonClick = { backToTop() },
|
||||
showFullscreenButton = false,
|
||||
onExitFullscreenClick = { closeFullScreen() },
|
||||
showTtsControls = false,
|
||||
onPauseTtsClick = { pauseTts() },
|
||||
pauseTtsButtonText = "",
|
||||
onStopTtsClick = { stopTts() },
|
||||
kiwixWebViewList = webViewList,
|
||||
bookmarkButtonItem = Triple(
|
||||
{ toggleBookmark() },
|
||||
{ goToBookmarks() },
|
||||
IconItem.Drawable(R.drawable.ic_bookmark_border_24dp)
|
||||
),
|
||||
previousPageButtonItem = { goBack() } to { showBackwardHistory() },
|
||||
onHomeButtonClick = { openMainPage() },
|
||||
nextPageButtonItem = { goForward() } to { showForwardHistory() },
|
||||
onTocClick = { openToc() },
|
||||
onCloseAllTabs = { closeAllTabs() }
|
||||
)
|
||||
)
|
||||
private var readerLifeCycleScope: CoroutineScope? = null
|
||||
|
||||
val coreReaderLifeCycleScope: CoroutineScope?
|
||||
@ -449,11 +490,28 @@ abstract class CoreReaderFragment :
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Suppress("LongMethod")
|
||||
override fun onViewCreated(
|
||||
view: View,
|
||||
savedInstanceState: Bundle?
|
||||
) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
composeView?.apply {
|
||||
setContent {
|
||||
ReaderScreen(
|
||||
state = readerScreenState.value,
|
||||
actionMenuItems = emptyList(),
|
||||
navigationIcon = {
|
||||
NavigationIcon(
|
||||
iconItem = IconItem.Vector(Icons.Filled.Menu),
|
||||
contentDescription = string.open_drawer,
|
||||
onClick = { navigationIconClick() }
|
||||
)
|
||||
}
|
||||
)
|
||||
DialogHost(alertDialogShower as AlertDialogShower)
|
||||
}
|
||||
}
|
||||
addAlertDialogToDialogHost()
|
||||
setupMenu()
|
||||
donationDialogHandler?.setDonationDialogCallBack(this)
|
||||
@ -555,10 +613,21 @@ abstract class CoreReaderFragment :
|
||||
handleClicks()
|
||||
}
|
||||
|
||||
private fun navigationIconClick() {
|
||||
// Manually handle the navigation open/close.
|
||||
// Since currently we are using the view based navigation drawer in other screens.
|
||||
// Once we fully migrate to jetpack compose we will refactor this code to use the
|
||||
// compose navigation.
|
||||
// TODO Replace with compose based navigation when migration is done.
|
||||
val activity = activity as CoreMainActivity
|
||||
if (activity.navigationDrawerIsOpen()) {
|
||||
activity.closeNavigationDrawer()
|
||||
} else {
|
||||
activity.openNavigationDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addAlertDialogToDialogHost() {
|
||||
fragmentReaderBinding?.root?.addView(
|
||||
requireContext().getDialogHostComposeView(alertDialogShower as AlertDialogShower)
|
||||
)
|
||||
externalLinkOpener?.setAlertDialogShower(alertDialogShower as AlertDialogShower)
|
||||
unsupportedMimeTypeHandler?.setAlertDialogShower(alertDialogShower as AlertDialogShower)
|
||||
}
|
||||
@ -704,9 +773,8 @@ abstract class CoreReaderFragment :
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
fragmentReaderBinding = FragmentReaderBinding.inflate(inflater, container, false)
|
||||
return fragmentReaderBinding?.root
|
||||
): View? = ComposeView(requireContext()).also {
|
||||
composeView = it
|
||||
}
|
||||
|
||||
private fun handleIntentExtras(intent: Intent) {
|
||||
@ -1251,11 +1319,15 @@ abstract class CoreReaderFragment :
|
||||
tts?.currentTTSTask?.let {
|
||||
if (it.paused) {
|
||||
tts?.pauseOrResume()
|
||||
pauseTTSButton?.setText(R.string.tts_pause)
|
||||
readerScreenState.update {
|
||||
copy(pauseTtsButtonText = context?.getString(R.string.tts_pause).orEmpty())
|
||||
}
|
||||
setActionAndStartTTSService(ACTION_PAUSE_OR_RESUME_TTS, false)
|
||||
} else {
|
||||
tts?.pauseOrResume()
|
||||
pauseTTSButton?.setText(R.string.tts_resume)
|
||||
readerScreenState.update {
|
||||
copy(pauseTtsButtonText = context?.getString(R.string.tts_resume).orEmpty())
|
||||
}
|
||||
setActionAndStartTTSService(ACTION_PAUSE_OR_RESUME_TTS, true)
|
||||
}
|
||||
}
|
||||
@ -1321,6 +1393,8 @@ abstract class CoreReaderFragment :
|
||||
storagePermissionForNotesLauncher = null
|
||||
donationDialogHandler?.setDonationDialogCallBack(null)
|
||||
donationDialogHandler = null
|
||||
composeView?.disposeComposition()
|
||||
composeView = null
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@ -1927,14 +2001,23 @@ abstract class CoreReaderFragment :
|
||||
List<String?>::contains
|
||||
).collect { isBookmarked ->
|
||||
this@CoreReaderFragment.isBookmarked = isBookmarked
|
||||
bottomToolbarBookmark?.setImageResource(
|
||||
if (isBookmarked) R.drawable.ic_bookmark_24dp else R.drawable.ic_bookmark_border_24dp
|
||||
)
|
||||
readerScreenState.update {
|
||||
copy(
|
||||
bookmarkButtonItem = bookmarkButtonItem.copy(third = getBookMarkButtonIcon(isBookmarked))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
updateUrlFlow()
|
||||
}
|
||||
|
||||
private fun getBookMarkButtonIcon(isBookmarked: Boolean) =
|
||||
if (isBookmarked) {
|
||||
IconItem.Drawable(R.drawable.ic_bookmark_24dp)
|
||||
} else {
|
||||
IconItem.Drawable(R.drawable.ic_bookmark_border_24dp)
|
||||
}
|
||||
|
||||
private fun safelyCancelBookmarkJob() {
|
||||
bookmarkingJob?.cancel()
|
||||
bookmarkingJob = null
|
||||
|
@ -18,22 +18,34 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.core.main.reader
|
||||
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
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.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
@ -43,14 +55,24 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.main.DarkModeViewPainter
|
||||
import org.kiwix.kiwixmobile.core.main.KiwixWebView
|
||||
import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar
|
||||
import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar
|
||||
import org.kiwix.kiwixmobile.core.ui.components.KiwixButton
|
||||
@ -63,11 +85,16 @@ import org.kiwix.kiwixmobile.core.ui.models.toPainter
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.Black
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.KiwixDialogTheme
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.White
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.CLOSE_ALL_TAB_BUTTON_BOTTOM_PADDING
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.EIGHT_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FOUR_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.ONE_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.READER_BOTTOM_APP_BAR_BUTTON_ICON_SIZE
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.READER_BOTTOM_APP_BAR_LAYOUT_HEIGHT
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TTS_BUTTONS_CONTROL_ALPHA
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TWO_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.StyleUtils.fromHtml
|
||||
|
||||
const val CONTENT_LOADING_PROGRESSBAR_TESTING_TAG = "contentLoadingProgressBarTestingTag"
|
||||
|
||||
@ -90,25 +117,34 @@ fun ReaderScreen(
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
if (state.isNoBookOpenInReader) {
|
||||
NoBookOpenView(state.onOpenLibraryButtonClicked)
|
||||
} else {
|
||||
ShowProgressBarIfZIMFilePageIsLoading(state)
|
||||
if (state.isNoBookOpenInReader) {
|
||||
NoBookOpenView(state.onOpenLibraryButtonClicked)
|
||||
}
|
||||
ShowZIMFileContent(state.kiwixWebViewList)
|
||||
TtsControls(state)
|
||||
BottomAppBarOfReaderScreen(
|
||||
state.bookmarkButtonItem,
|
||||
state.previousPageButtonItem,
|
||||
state.onHomeButtonClick,
|
||||
state.nextPageButtonItem,
|
||||
state.onTocClick
|
||||
)
|
||||
ShowFullScreenView(state)
|
||||
}
|
||||
TtsControls(state)
|
||||
ShowFullScreenView(state)
|
||||
ShowDonationLayout(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ShowZIMFileContent(kiwixWebViewList: List<KiwixWebView>) {
|
||||
if (kiwixWebViewList.isNotEmpty()) {
|
||||
AndroidView({ kiwixWebViewList[0] }, modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ShowFullScreenView(state: ReaderScreenState) {
|
||||
if (state.fullScreenItem.first) {
|
||||
@ -117,10 +153,12 @@ private fun ShowFullScreenView(state: ReaderScreenState) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ShowProgressBarIfZIMFilePageIsLoading(state: ReaderScreenState) {
|
||||
private fun BoxScope.ShowProgressBarIfZIMFilePageIsLoading(state: ReaderScreenState) {
|
||||
if (state.pageLoadingItem.first) {
|
||||
ContentLoadingProgressBar(
|
||||
modifier = Modifier.testTag(CONTENT_LOADING_PROGRESSBAR_TESTING_TAG),
|
||||
modifier = Modifier
|
||||
.testTag(CONTENT_LOADING_PROGRESSBAR_TESTING_TAG)
|
||||
.align(Alignment.CenterEnd),
|
||||
progressBarStyle = ProgressBarStyle.HORIZONTAL,
|
||||
progress = state.pageLoadingItem.second
|
||||
)
|
||||
@ -155,7 +193,7 @@ private fun NoBookOpenView(
|
||||
@Composable
|
||||
private fun BoxScope.TtsControls(state: ReaderScreenState) {
|
||||
if (state.showTtsControls) {
|
||||
Row(modifier = Modifier.align(Alignment.TopCenter)) {
|
||||
Row(modifier = Modifier.align(Alignment.BottomCenter)) {
|
||||
Button(
|
||||
onClick = state.onPauseTtsClick,
|
||||
modifier = Modifier
|
||||
@ -163,7 +201,7 @@ private fun BoxScope.TtsControls(state: ReaderScreenState) {
|
||||
.alpha(TTS_BUTTONS_CONTROL_ALPHA)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.tts_pause),
|
||||
text = state.pauseTtsButtonText,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
@ -204,10 +242,10 @@ private fun BackToTopFab(state: ReaderScreenState) {
|
||||
|
||||
@Composable
|
||||
private fun BottomAppBarOfReaderScreen(
|
||||
onBookmarkClick: () -> Unit,
|
||||
onBackClick: () -> Unit,
|
||||
onHomeClick: () -> Unit,
|
||||
onForwardClick: () -> Unit,
|
||||
bookmarkButtonItem: Triple<() -> Unit, () -> Unit, Drawable>,
|
||||
previousPageButtonItem: Pair<() -> Unit, () -> Unit>,
|
||||
onHomeButtonClick: () -> Unit,
|
||||
nextPageButtonItem: Pair<() -> Unit, () -> Unit>,
|
||||
onTocClick: () -> Unit
|
||||
) {
|
||||
BottomAppBar(
|
||||
@ -223,33 +261,36 @@ private fun BottomAppBarOfReaderScreen(
|
||||
) {
|
||||
// Bookmark Icon
|
||||
BottomAppBarButtonIcon(
|
||||
onBookmarkClick,
|
||||
Drawable(R.drawable.ic_bookmark_border_24dp),
|
||||
stringResource(R.string.bookmarks)
|
||||
onClick = bookmarkButtonItem.first,
|
||||
onLongClick = bookmarkButtonItem.second,
|
||||
buttonIcon = bookmarkButtonItem.third,
|
||||
contentDescription = stringResource(R.string.bookmarks)
|
||||
)
|
||||
// Back Icon(for going to previous page)
|
||||
BottomAppBarButtonIcon(
|
||||
onBackClick,
|
||||
Drawable(R.drawable.ic_keyboard_arrow_left_24dp),
|
||||
stringResource(R.string.go_to_previous_page)
|
||||
onClick = previousPageButtonItem.first,
|
||||
onLongClick = previousPageButtonItem.second,
|
||||
buttonIcon = Drawable(R.drawable.ic_keyboard_arrow_left_24dp),
|
||||
contentDescription = stringResource(R.string.go_to_previous_page)
|
||||
)
|
||||
// Home Icon(to open the home page of ZIM file)
|
||||
BottomAppBarButtonIcon(
|
||||
onHomeClick,
|
||||
Drawable(R.drawable.action_home),
|
||||
stringResource(R.string.menu_home)
|
||||
onClick = onHomeButtonClick,
|
||||
buttonIcon = Drawable(R.drawable.action_home),
|
||||
contentDescription = stringResource(R.string.menu_home)
|
||||
)
|
||||
// Forward Icon(for going to next page)
|
||||
BottomAppBarButtonIcon(
|
||||
onForwardClick,
|
||||
Drawable(R.drawable.ic_keyboard_arrow_right_24dp),
|
||||
stringResource(R.string.go_to_next_page)
|
||||
onClick = nextPageButtonItem.first,
|
||||
onLongClick = nextPageButtonItem.second,
|
||||
buttonIcon = Drawable(R.drawable.ic_keyboard_arrow_right_24dp),
|
||||
contentDescription = stringResource(R.string.go_to_next_page)
|
||||
)
|
||||
// Toggle Icon(to open the table of content in right side bar)
|
||||
BottomAppBarButtonIcon(
|
||||
onTocClick,
|
||||
Drawable(R.drawable.ic_toc_24dp),
|
||||
stringResource(R.string.table_of_contents)
|
||||
onClick = onTocClick,
|
||||
buttonIcon = Drawable(R.drawable.ic_toc_24dp),
|
||||
contentDescription = stringResource(R.string.table_of_contents)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -258,10 +299,14 @@ private fun BottomAppBarOfReaderScreen(
|
||||
@Composable
|
||||
private fun BottomAppBarButtonIcon(
|
||||
onClick: () -> Unit,
|
||||
onLongClick: (() -> Unit)? = null,
|
||||
buttonIcon: IconItem,
|
||||
contentDescription: String
|
||||
) {
|
||||
IconButton(onClick = onClick) {
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.combinedClickable(onClick = onClick, onLongClick = onLongClick)
|
||||
) {
|
||||
Icon(
|
||||
buttonIcon.toPainter(),
|
||||
contentDescription,
|
||||
@ -282,3 +327,130 @@ private fun BoxScope.ShowDonationLayout(state: ReaderScreenState) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabSwitcherView(
|
||||
webViews: List<KiwixWebView>,
|
||||
selectedIndex: Int,
|
||||
onSelectTab: (Int) -> Unit,
|
||||
onCloseTab: (Int) -> Unit,
|
||||
onCloseAllTabs: () -> Unit,
|
||||
painter: DarkModeViewPainter
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
LazyRow(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.TopCenter)
|
||||
.padding(top = SIXTEEN_DP),
|
||||
contentPadding = PaddingValues(horizontal = SIXTEEN_DP, vertical = EIGHT_DP),
|
||||
horizontalArrangement = Arrangement.spacedBy(EIGHT_DP)
|
||||
) {
|
||||
itemsIndexed(webViews, key = { _, item -> item.hashCode() }) { index, webView ->
|
||||
val context = LocalContext.current
|
||||
val title = remember(webView) {
|
||||
webView.title?.fromHtml()?.toString()
|
||||
?: context.getString(R.string.menu_home)
|
||||
}
|
||||
|
||||
LaunchedEffect(webView) {
|
||||
if (title != context.getString(R.string.menu_home)) {
|
||||
painter.update(webView)
|
||||
}
|
||||
}
|
||||
|
||||
TabItemView(
|
||||
title = title,
|
||||
isSelected = index == selectedIndex,
|
||||
webView = webView,
|
||||
onSelectTab = { onSelectTab(index) },
|
||||
onCloseTab = { onCloseTab(index) }
|
||||
)
|
||||
}
|
||||
}
|
||||
CloseAllTabButton(onCloseAllTabs)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.CloseAllTabButton(onCloseAllTabs: () -> Unit) {
|
||||
FloatingActionButton(
|
||||
onClick = onCloseAllTabs,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = CLOSE_ALL_TAB_BUTTON_BOTTOM_PADDING)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_close_black_24dp),
|
||||
contentDescription = stringResource(R.string.close_all_tabs)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
fun TabItemView(
|
||||
title: String,
|
||||
isSelected: Boolean,
|
||||
webView: KiwixWebView,
|
||||
modifier: Modifier = Modifier,
|
||||
onSelectTab: () -> Unit,
|
||||
onCloseTab: () -> Unit
|
||||
) {
|
||||
val cardElevation = if (isSelected) EIGHT_DP else TWO_DP
|
||||
val borderColor = if (isSelected) MaterialTheme.colorScheme.primary else Color.Transparent
|
||||
|
||||
Box(modifier = modifier) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = EIGHT_DP, vertical = FOUR_DP)
|
||||
.widthIn(min = 200.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = FOUR_DP),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(end = EIGHT_DP),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
IconButton(onClick = onCloseTab) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_clear_white_24dp),
|
||||
contentDescription = stringResource(R.string.close_tab)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Card with WebView (non-interactive with overlay)
|
||||
Card(
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
|
||||
border = BorderStroke(ONE_DP, borderColor),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1.6f) // approximate height logic
|
||||
.clickable { onSelectTab() }
|
||||
) {
|
||||
AndroidView(
|
||||
factory = { context ->
|
||||
// Detach if needed to avoid WebView already has a parent issue
|
||||
(webView.parent as? ViewGroup)?.removeView(webView)
|
||||
FrameLayout(context).apply {
|
||||
addView(webView)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ package org.kiwix.kiwixmobile.core.main.reader
|
||||
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import org.kiwix.kiwixmobile.core.main.KiwixWebView
|
||||
import org.kiwix.kiwixmobile.core.ui.models.IconItem.Drawable
|
||||
|
||||
/**
|
||||
* Represents the UI state for the Reader Screen.
|
||||
@ -59,7 +61,7 @@ data class ReaderScreenState(
|
||||
* - [Boolean]: Whether to show/hide full screen mode.
|
||||
* - [ComposeView]: full screen view.
|
||||
*/
|
||||
val fullScreenItem: Pair<Boolean, ComposeView>,
|
||||
val fullScreenItem: Pair<Boolean, ComposeView?>,
|
||||
/**
|
||||
* Manages the showing of "BackToTop" fab button.
|
||||
*/
|
||||
@ -72,5 +74,47 @@ data class ReaderScreenState(
|
||||
val onExitFullscreenClick: () -> Unit = {},
|
||||
val showTtsControls: Boolean = false,
|
||||
val onPauseTtsClick: () -> Unit = {},
|
||||
/**
|
||||
* Manages the showing of TTS button text(Pause/Resume).
|
||||
*/
|
||||
val pauseTtsButtonText: String,
|
||||
val onStopTtsClick: () -> Unit = {},
|
||||
/**
|
||||
* To show in the tabs view.
|
||||
*/
|
||||
val kiwixWebViewList: List<KiwixWebView>,
|
||||
/**
|
||||
* Handles the (UI, and clicks) for bookmark button in reader bottom toolbar.
|
||||
*
|
||||
* A [Triple] containing:
|
||||
* - [Unit]: Handles the normal click of button.
|
||||
* - [Unit]: Handles the long click of button.
|
||||
* - [Drawable]: Handles the Icon of button.
|
||||
*/
|
||||
val bookmarkButtonItem: Triple<() -> Unit, () -> Unit, Drawable>,
|
||||
/**
|
||||
* Handles the clicks of previous page button in reader bottom toolbar.
|
||||
*
|
||||
* A [Pair] containing:
|
||||
* - [Unit]: Handles the normal click of button(For going to previous page).
|
||||
* - [Unit]: Handles the long click of button(For showing the previous pages history).
|
||||
*/
|
||||
val previousPageButtonItem: Pair<() -> Unit, () -> Unit>,
|
||||
/**
|
||||
* Handles the click to open home page of ZIM file button click in reader bottom toolbar.
|
||||
*/
|
||||
val onHomeButtonClick: () -> Unit,
|
||||
/**
|
||||
* Handles the clicks of next page button in reader bottom toolbar.
|
||||
*
|
||||
* A [Pair] containing:
|
||||
* - [Unit]: Handles the normal click of button(For going to next page).
|
||||
* - [Unit]: Handles the long click of button(For showing the next pages history).
|
||||
*/
|
||||
val nextPageButtonItem: Pair<() -> Unit, () -> Unit>,
|
||||
/**
|
||||
* Handles the click to open right sidebar button click in reader bottom toolbar.
|
||||
*/
|
||||
val onTocClick: () -> Unit,
|
||||
val onCloseAllTabs: () -> Unit
|
||||
)
|
||||
|
@ -184,4 +184,5 @@ object ComposeDimens {
|
||||
val READER_BOTTOM_APP_BAR_LAYOUT_HEIGHT = 48.dp
|
||||
val READER_BOTTOM_APP_BAR_BUTTON_ICON_SIZE = 30.dp
|
||||
const val TTS_BUTTONS_CONTROL_ALPHA = 0.6f
|
||||
val CLOSE_ALL_TAB_BUTTON_BOTTOM_PADDING = 24.dp
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user