Migrate top reader app bar to Compose

This commit is contained in:
arkon 2023-10-14 12:30:17 -04:00
parent 5619a4c0d9
commit d18022c259
12 changed files with 149 additions and 231 deletions

View File

@ -1,5 +1,6 @@
package eu.kanade.presentation.components package eu.kanade.presentation.components
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
@ -60,6 +61,7 @@ const val SEARCH_DEBOUNCE_MILLIS = 250L
@Composable @Composable
fun AppBar( fun AppBar(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
backgroundColor: Color? = null,
// Text // Text
title: String?, title: String?,
subtitle: String? = null, subtitle: String? = null,
@ -81,6 +83,7 @@ fun AppBar(
AppBar( AppBar(
modifier = modifier, modifier = modifier,
backgroundColor = backgroundColor,
titleContent = { titleContent = {
if (isActionMode) { if (isActionMode) {
AppBarTitle(actionModeCounter.toString()) AppBarTitle(actionModeCounter.toString())
@ -106,6 +109,7 @@ fun AppBar(
@Composable @Composable
fun AppBar( fun AppBar(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
backgroundColor: Color? = null,
// Title // Title
titleContent: @Composable () -> Unit, titleContent: @Composable () -> Unit,
// Up button // Up button
@ -142,7 +146,7 @@ fun AppBar(
title = titleContent, title = titleContent,
actions = actions, actions = actions,
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( containerColor = backgroundColor ?: MaterialTheme.colorScheme.surfaceColorAtElevation(
elevation = if (isActionMode) 3.dp else 0.dp, elevation = if (isActionMode) 3.dp else 0.dp,
), ),
), ),
@ -170,6 +174,9 @@ fun AppBarTitle(
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
modifier = Modifier.basicMarquee(
delayMillis = 2_000,
),
) )
} }
} }

View File

@ -1,7 +1,6 @@
package eu.kanade.presentation.reader.appbars package eu.kanade.presentation.reader.appbars
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -10,11 +9,10 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.surfaceColorAtElevation
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.graphics.Color
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -24,6 +22,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
@Composable @Composable
fun BottomReaderBar( fun BottomReaderBar(
backgroundColor: Color,
readingMode: ReadingModeType, readingMode: ReadingModeType,
onClickReadingMode: () -> Unit, onClickReadingMode: () -> Unit,
orientationMode: OrientationType, orientationMode: OrientationType,
@ -32,11 +31,6 @@ fun BottomReaderBar(
onClickCropBorder: () -> Unit, onClickCropBorder: () -> Unit,
onClickSettings: () -> Unit, onClickSettings: () -> Unit,
) { ) {
// Match with toolbar background color set in ReaderActivity
val backgroundColor = MaterialTheme.colorScheme
.surfaceColorAtElevation(3.dp)
.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()

View File

@ -4,14 +4,28 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Bookmark
import androidx.compose.material.icons.outlined.BookmarkBorder
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
import eu.kanade.tachiyomi.ui.reader.viewer.Viewer import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
@ -22,8 +36,18 @@ private val animationSpec = tween<IntOffset>(200)
@Composable @Composable
fun ReaderAppBars( fun ReaderAppBars(
visible: Boolean, visible: Boolean,
viewer: Viewer?, fullscreen: Boolean,
mangaTitle: String?,
chapterTitle: String?,
navigateUp: () -> Unit,
onClickTopAppBar: () -> Unit,
bookmarked: Boolean,
onToggleBookmarked: () -> Unit,
onOpenInWebView: (() -> Unit)?,
onShare: (() -> Unit)?,
viewer: Viewer?,
onNextChapter: () -> Unit, onNextChapter: () -> Unit,
enabledNext: Boolean, enabledNext: Boolean,
onPreviousChapter: () -> Unit, onPreviousChapter: () -> Unit,
@ -41,11 +65,64 @@ fun ReaderAppBars(
onClickSettings: () -> Unit, onClickSettings: () -> Unit,
) { ) {
val isRtl = viewer is R2LPagerViewer val isRtl = viewer is R2LPagerViewer
val backgroundColor = MaterialTheme.colorScheme
.surfaceColorAtElevation(3.dp)
.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
val appBarModifier = if (fullscreen) {
Modifier.windowInsetsPadding(WindowInsets.systemBars)
} else {
Modifier
}
Column( Column(
modifier = Modifier.fillMaxHeight(), modifier = Modifier.fillMaxHeight(),
verticalArrangement = Arrangement.SpaceBetween, verticalArrangement = Arrangement.SpaceBetween,
) { ) {
AnimatedVisibility(
visible = visible,
enter = slideInVertically(
initialOffsetY = { -it },
animationSpec = animationSpec,
),
exit = slideOutVertically(
targetOffsetY = { -it },
animationSpec = animationSpec,
),
) {
AppBar(
modifier = appBarModifier
.clickable(onClick = onClickTopAppBar),
backgroundColor = backgroundColor,
title = mangaTitle,
subtitle = chapterTitle,
navigateUp = navigateUp,
actions = {
AppBarActions(
listOfNotNull(
AppBar.Action(
title = stringResource(if (bookmarked) R.string.action_remove_bookmark else R.string.action_bookmark),
icon = if (bookmarked) Icons.Outlined.Bookmark else Icons.Outlined.BookmarkBorder,
onClick = onToggleBookmarked,
),
onOpenInWebView?.let {
AppBar.OverflowAction(
title = stringResource(R.string.action_open_in_web_view),
onClick = it,
)
},
onShare?.let {
AppBar.OverflowAction(
title = stringResource(R.string.action_share),
onClick = it,
)
},
),
)
},
)
}
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
AnimatedVisibility( AnimatedVisibility(
@ -74,6 +151,7 @@ fun ReaderAppBars(
) )
BottomReaderBar( BottomReaderBar(
backgroundColor = backgroundColor,
readingMode = readingMode, readingMode = readingMode,
onClickReadingMode = onClickReadingMode, onClickReadingMode = onClickReadingMode,
orientationMode = orientationMode, orientationMode = orientationMode,

View File

@ -13,15 +13,10 @@ import android.graphics.Paint
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils
import android.view.KeyEvent import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View.LAYER_TYPE_HARDWARE import android.view.View.LAYER_TYPE_HARDWARE
import android.view.WindowManager import android.view.WindowManager
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.Toast import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -44,8 +39,7 @@ import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.google.android.material.internal.ToolbarUtils import com.google.android.material.elevation.SurfaceColors
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.transition.platform.MaterialContainerTransform import com.google.android.material.transition.platform.MaterialContainerTransform
import dev.chrisbanes.insetter.applyInsetter import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.base.BasePreferences
@ -74,13 +68,11 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.ui.webview.WebViewActivity
import eu.kanade.tachiyomi.util.system.applySystemAnimatorScale
import eu.kanade.tachiyomi.util.system.hasDisplayCutout import eu.kanade.tachiyomi.util.system.hasDisplayCutout
import eu.kanade.tachiyomi.util.system.isNightMode import eu.kanade.tachiyomi.util.system.isNightMode
import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toShareIntent
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.setComposeContent import eu.kanade.tachiyomi.util.view.setComposeContent
import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
@ -265,47 +257,6 @@ class ReaderActivity : BaseActivity() {
assistUrl?.let { outContent.webUri = it.toUri() } assistUrl?.let { outContent.webUri = it.toUri() }
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.reader, menu)
val isChapterBookmarked = viewModel.getCurrentChapter()?.chapter?.bookmark ?: false
menu.findItem(R.id.action_bookmark).isVisible = !isChapterBookmarked
menu.findItem(R.id.action_remove_bookmark).isVisible = isChapterBookmarked
val isHttpSource = viewModel.getSource() is HttpSource
menu.findItem(R.id.action_open_in_web_view).isVisible = isHttpSource
menu.findItem(R.id.action_share).isVisible = isHttpSource
return true
}
/**
* Called when an item of the options menu was clicked. Used to handle clicks on our menu
* entries.
*/
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_open_in_web_view -> {
openChapterInWebView()
}
R.id.action_bookmark -> {
viewModel.bookmarkCurrentChapter(true)
invalidateOptionsMenu()
}
R.id.action_remove_bookmark -> {
viewModel.bookmarkCurrentChapter(false)
invalidateOptionsMenu()
}
R.id.action_share -> {
assistUrl?.let {
val intent = it.toUri().toShareIntent(this, type = "text/plain")
startActivity(Intent.createChooser(intent, getString(R.string.action_share)))
}
}
}
return super.onOptionsItemSelected(item)
}
/** /**
* Called when the user clicks the back key or the button on the toolbar. The call is * Called when the user clicks the back key or the button on the toolbar. The call is
* delegated to the presenter. * delegated to the presenter.
@ -348,35 +299,12 @@ class ReaderActivity : BaseActivity() {
* Initializes the reader menu. It sets up click listeners and the initial visibility. * Initializes the reader menu. It sets up click listeners and the initial visibility.
*/ */
private fun initializeMenu() { private fun initializeMenu() {
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
binding.toolbar.setNavigationOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
binding.toolbar.applyInsetter {
type(navigationBars = true, statusBars = true) {
margin(top = true, horizontal = true)
}
}
binding.dialogRoot.applyInsetter { binding.dialogRoot.applyInsetter {
type(navigationBars = true) { type(navigationBars = true) {
margin(vertical = true, horizontal = true) margin(vertical = true, horizontal = true)
} }
} }
binding.toolbar.setOnClickListener {
viewModel.manga?.id?.let { id ->
startActivity(
Intent(this, MainActivity::class.java).apply {
action = Constants.SHORTCUT_MANGA
putExtra(Constants.MANGA_EXTRA, id)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
},
)
}
}
binding.pageNumber.setComposeContent { binding.pageNumber.setComposeContent {
val state by viewModel.state.collectAsState() val state by viewModel.state.collectAsState()
val showPageNumber by viewModel.readerPreferences.showPageNumber().collectAsState() val showPageNumber by viewModel.readerPreferences.showPageNumber().collectAsState()
@ -400,6 +328,9 @@ class ReaderActivity : BaseActivity() {
) )
} }
val isHttpSource = viewModel.getSource() is HttpSource
val isFullscreen by readerPreferences.fullscreen().collectAsState()
val cropBorderPaged by readerPreferences.cropBorders().collectAsState() val cropBorderPaged by readerPreferences.cropBorders().collectAsState()
val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState()
val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode()) val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode())
@ -407,8 +338,18 @@ class ReaderActivity : BaseActivity() {
ReaderAppBars( ReaderAppBars(
visible = state.menuVisible, visible = state.menuVisible,
viewer = state.viewer, fullscreen = isFullscreen,
mangaTitle = state.manga?.title,
chapterTitle = state.currentChapter?.chapter?.name,
navigateUp = onBackPressedDispatcher::onBackPressed,
onClickTopAppBar = ::openMangaScreen,
bookmarked = state.bookmarked,
onToggleBookmarked = viewModel::toggleChapterBookmark,
onOpenInWebView = ::openChapterInWebView.takeIf { isHttpSource },
onShare = ::shareChapter.takeIf { isHttpSource },
viewer = state.viewer,
onNextChapter = ::loadNextChapter, onNextChapter = ::loadNextChapter,
enabledNext = state.viewerChapters?.nextChapter != null, enabledNext = state.viewerChapters?.nextChapter != null,
onPreviousChapter = ::loadPreviousChapter, onPreviousChapter = ::loadPreviousChapter,
@ -435,15 +376,8 @@ class ReaderActivity : BaseActivity() {
cropEnabled = cropEnabled, cropEnabled = cropEnabled,
onClickCropBorder = { onClickCropBorder = {
val enabled = viewModel.toggleCropBorders() val enabled = viewModel.toggleCropBorders()
menuToggleToast?.cancel() menuToggleToast?.cancel()
menuToggleToast = toast( menuToggleToast = toast(if (enabled) R.string.on else R.string.off)
if (enabled) {
R.string.on
} else {
R.string.off
},
)
}, },
onClickSettings = viewModel::openSettingsDialog, onClickSettings = viewModel::openSettingsDialog,
) )
@ -507,13 +441,9 @@ class ReaderActivity : BaseActivity() {
} }
} }
val toolbarBackground = (binding.toolbar.background as MaterialShapeDrawable).apply {
elevation = resources.getDimension(R.dimen.m3_sys_elevation_level2)
alpha = if (isNightMode()) 230 else 242 // 90% dark 95% light
}
val toolbarColor = ColorUtils.setAlphaComponent( val toolbarColor = ColorUtils.setAlphaComponent(
toolbarBackground.resolvedTintColor, SurfaceColors.SURFACE_2.getColor(this),
toolbarBackground.alpha, if (isNightMode()) 230 else 242, // 90% dark 95% light
) )
window.statusBarColor = toolbarColor window.statusBarColor = toolbarColor
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
@ -531,35 +461,12 @@ class ReaderActivity : BaseActivity() {
viewModel.showMenus(visible) viewModel.showMenus(visible)
if (visible) { if (visible) {
windowInsetsController.show(WindowInsetsCompat.Type.systemBars()) windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
binding.readerMenu.isVisible = true window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top)
toolbarAnimation.applySystemAnimatorScale(this)
toolbarAnimation.setAnimationListener(
object : SimpleAnimationListener() {
override fun onAnimationStart(animation: Animation) {
// Fix status bar being translucent the first time it's opened.
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
}
},
)
binding.toolbar.startAnimation(toolbarAnimation)
} else { } else {
if (readerPreferences.fullscreen().get()) { if (readerPreferences.fullscreen().get()) {
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
} }
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_top)
toolbarAnimation.applySystemAnimatorScale(this)
toolbarAnimation.setAnimationListener(
object : SimpleAnimationListener() {
override fun onAnimationEnd(animation: Animation) {
binding.readerMenu.isVisible = false
}
},
)
binding.toolbar.startAnimation(toolbarAnimation)
} }
} }
@ -593,14 +500,24 @@ class ReaderActivity : BaseActivity() {
showReadingModeToast(viewModel.getMangaReadingMode()) showReadingModeToast(viewModel.getMangaReadingMode())
} }
supportActionBar?.title = manga.title
loadingIndicator = ReaderProgressIndicator(this) loadingIndicator = ReaderProgressIndicator(this)
binding.readerContainer.addView(loadingIndicator) binding.readerContainer.addView(loadingIndicator)
startPostponedEnterTransition() startPostponedEnterTransition()
} }
private fun openMangaScreen() {
viewModel.manga?.id?.let { id ->
startActivity(
Intent(this, MainActivity::class.java).apply {
action = Constants.SHORTCUT_MANGA
putExtra(Constants.MANGA_EXTRA, id)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
},
)
}
}
private fun openChapterInWebView() { private fun openChapterInWebView() {
val manga = viewModel.manga ?: return val manga = viewModel.manga ?: return
val source = viewModel.getSource() ?: return val source = viewModel.getSource() ?: return
@ -610,6 +527,13 @@ class ReaderActivity : BaseActivity() {
} }
} }
private fun shareChapter() {
assistUrl?.let {
val intent = it.toUri().toShareIntent(this, type = "text/plain")
startActivity(Intent.createChooser(intent, getString(R.string.action_share)))
}
}
private fun showReadingModeToast(mode: Int) { private fun showReadingModeToast(mode: Int) {
try { try {
readingModeToast?.cancel() readingModeToast?.cancel()
@ -629,15 +553,6 @@ class ReaderActivity : BaseActivity() {
binding.readerContainer.removeView(loadingIndicator) binding.readerContainer.removeView(loadingIndicator)
viewModel.state.value.viewer?.setChapters(viewerChapters) viewModel.state.value.viewer?.setChapters(viewerChapters)
binding.toolbar.subtitle = viewerChapters.currChapter.chapter.name
ToolbarUtils.getSubtitleTextView(binding.toolbar)?.let {
it.ellipsize = TextUtils.TruncateAt.MARQUEE
it.isSelected = true
}
// Invalidate menu to show proper chapter bookmark state
invalidateOptionsMenu()
lifecycleScope.launchIO { lifecycleScope.launchIO {
viewModel.getChapterUrl()?.let { url -> viewModel.getChapterUrl()?.let { url ->
assistUrl = url assistUrl = url
@ -675,7 +590,7 @@ class ReaderActivity : BaseActivity() {
*/ */
private fun moveToPageIndex(index: Int) { private fun moveToPageIndex(index: Int) {
val viewer = viewModel.state.value.viewer ?: return val viewer = viewModel.state.value.viewer ?: return
val currentChapter = viewModel.getCurrentChapter() ?: return val currentChapter = viewModel.state.value.currentChapter ?: return
val page = currentChapter.pages?.getOrNull(index) ?: return val page = currentChapter.pages?.getOrNull(index) ?: return
viewer.moveToPage(page) viewer.moveToPage(page)
} }

View File

@ -298,7 +298,10 @@ class ReaderViewModel @JvmOverloads constructor(
it.viewerChapters?.unref() it.viewerChapters?.unref()
chapterToDownload = cancelQueuedDownloads(newChapters.currChapter) chapterToDownload = cancelQueuedDownloads(newChapters.currChapter)
it.copy(viewerChapters = newChapters) it.copy(
viewerChapters = newChapters,
bookmarked = newChapters.currChapter.chapter.bookmark,
)
} }
} }
return newChapters return newChapters
@ -567,8 +570,8 @@ class ReaderViewModel @JvmOverloads constructor(
/** /**
* Returns the currently active chapter. * Returns the currently active chapter.
*/ */
fun getCurrentChapter(): ReaderChapter? { private fun getCurrentChapter(): ReaderChapter? {
return state.value.viewerChapters?.currChapter return state.value.currentChapter
} }
fun getSource() = manga?.source?.let { sourceManager.getOrStub(it) } as? HttpSource fun getSource() = manga?.source?.let { sourceManager.getOrStub(it) } as? HttpSource
@ -588,9 +591,11 @@ class ReaderViewModel @JvmOverloads constructor(
/** /**
* Bookmarks the currently active chapter. * Bookmarks the currently active chapter.
*/ */
fun bookmarkCurrentChapter(bookmarked: Boolean) { fun toggleChapterBookmark() {
val chapter = getCurrentChapter()?.chapter ?: return val chapter = getCurrentChapter()?.chapter ?: return
chapter.bookmark = bookmarked // Otherwise the bookmark icon doesn't update val bookmarked = !chapter.bookmark
chapter.bookmark = bookmarked
viewModelScope.launchNonCancellable { viewModelScope.launchNonCancellable {
updateChapter.await( updateChapter.await(
ChapterUpdate( ChapterUpdate(
@ -599,6 +604,12 @@ class ReaderViewModel @JvmOverloads constructor(
), ),
) )
} }
mutableState.update {
it.copy(
bookmarked = bookmarked,
)
}
} }
/** /**
@ -873,6 +884,7 @@ class ReaderViewModel @JvmOverloads constructor(
data class State( data class State(
val manga: Manga? = null, val manga: Manga? = null,
val viewerChapters: ViewerChapters? = null, val viewerChapters: ViewerChapters? = null,
val bookmarked: Boolean = false,
val isLoadingAdjacentChapter: Boolean = false, val isLoadingAdjacentChapter: Boolean = false,
val currentPage: Int = -1, val currentPage: Int = -1,
@ -883,8 +895,11 @@ class ReaderViewModel @JvmOverloads constructor(
val dialog: Dialog? = null, val dialog: Dialog? = null,
val menuVisible: Boolean = false, val menuVisible: Boolean = false,
) { ) {
val currentChapter: ReaderChapter?
get() = viewerChapters?.currChapter
val totalPages: Int val totalPages: Int
get() = viewerChapters?.currChapter?.pages?.size ?: -1 get() = currentChapter?.pages?.size ?: -1
} }
sealed interface Dialog { sealed interface Dialog {

View File

@ -1,11 +0,0 @@
package eu.kanade.tachiyomi.widget.listener
import android.view.animation.Animation
open class SimpleAnimationListener : Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {}
override fun onAnimationStart(animation: Animation) {}
}

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:duration="200"
android:fromYDelta="-100%"
android:toYDelta="0%" />
</set>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:duration="200"
android:fromYDelta="0%"
android:toYDelta="-100%" />
</set>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z" />
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M17,3L7,3c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,5h10v13z" />
</vector>

View File

@ -1,5 +1,4 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -42,22 +41,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="gone" /> android:visibility="gone" />
<FrameLayout
android:id="@+id/reader_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="?attr/actionBarTheme"
android:visibility="invisible"
tools:visibility="visible">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
</FrameLayout>
<androidx.compose.ui.platform.ComposeView <androidx.compose.ui.platform.ComposeView
android:id="@+id/dialog_root" android:id="@+id/dialog_root"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_bookmark"
android:icon="@drawable/ic_bookmark_border_24dp"
android:title="@string/action_bookmark"
app:iconTint="?attr/colorOnSurface"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_remove_bookmark"
android:icon="@drawable/ic_bookmark_24dp"
android:title="@string/action_remove_bookmark"
app:iconTint="?attr/colorOnSurface"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_open_in_web_view"
android:title="@string/action_open_in_web_view"
app:showAsAction="never" />
<item
android:id="@+id/action_share"
android:title="@string/action_share"
app:showAsAction="never" />
</menu>