diff --git a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt index 1acd220fc..7ccfae0bd 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt @@ -1,5 +1,6 @@ package eu.kanade.presentation.components +import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.RowScope @@ -60,6 +61,7 @@ const val SEARCH_DEBOUNCE_MILLIS = 250L @Composable fun AppBar( modifier: Modifier = Modifier, + backgroundColor: Color? = null, // Text title: String?, subtitle: String? = null, @@ -81,6 +83,7 @@ fun AppBar( AppBar( modifier = modifier, + backgroundColor = backgroundColor, titleContent = { if (isActionMode) { AppBarTitle(actionModeCounter.toString()) @@ -106,6 +109,7 @@ fun AppBar( @Composable fun AppBar( modifier: Modifier = Modifier, + backgroundColor: Color? = null, // Title titleContent: @Composable () -> Unit, // Up button @@ -142,7 +146,7 @@ fun AppBar( title = titleContent, actions = actions, colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( + containerColor = backgroundColor ?: MaterialTheme.colorScheme.surfaceColorAtElevation( elevation = if (isActionMode) 3.dp else 0.dp, ), ), @@ -170,6 +174,9 @@ fun AppBarTitle( style = MaterialTheme.typography.bodyMedium, maxLines = 1, overflow = TextOverflow.Ellipsis, + modifier = Modifier.basicMarquee( + delayMillis = 2_000, + ), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt index 5a93e74f1..0ef6da13e 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt @@ -1,7 +1,6 @@ package eu.kanade.presentation.reader.appbars import androidx.compose.foundation.background -import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -13,11 +12,10 @@ import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.Share import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -31,6 +29,7 @@ fun BottomReaderBar( // SY --> enabledButtons: Set, // SY <-- + backgroundColor: Color, readingMode: ReadingModeType, onClickReadingMode: () -> Unit, orientationMode: OrientationType, @@ -39,21 +38,15 @@ fun BottomReaderBar( onClickCropBorder: () -> Unit, onClickSettings: () -> Unit, // SY --> - isHttpSource: Boolean, dualPageSplitEnabled: Boolean, doublePages: Boolean, onClickChapterList: () -> Unit, - onClickWebView: () -> Unit, - onClickShare: () -> Unit, + onClickWebView: (() -> Unit)?, + onClickShare: (() -> Unit)?, onClickPageLayout: () -> Unit, onClickShiftPage: () -> Unit, // SY <-- ) { - // 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( modifier = Modifier .fillMaxWidth() @@ -72,7 +65,7 @@ fun BottomReaderBar( } } - if (ReaderBottomButton.WebView.isIn(enabledButtons) && isHttpSource) { + if (ReaderBottomButton.WebView.isIn(enabledButtons) && onClickWebView != null) { IconButton(onClick = onClickWebView) { Icon( imageVector = Icons.Outlined.Public, @@ -81,7 +74,7 @@ fun BottomReaderBar( } } - if (ReaderBottomButton.Share.isIn(enabledButtons) && isHttpSource) { + if (ReaderBottomButton.Share.isIn(enabledButtons) && onClickShare != null) { IconButton(onClick = onClickShare) { Icon( imageVector = Icons.Outlined.Share, diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ExhUtils.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ExhUtils.kt new file mode 100644 index 000000000..be831adb0 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ExhUtils.kt @@ -0,0 +1,243 @@ +package eu.kanade.presentation.reader.appbars + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.KeyboardArrowDown +import androidx.compose.material.icons.outlined.KeyboardArrowUp +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import eu.kanade.presentation.theme.TachiyomiTheme +import eu.kanade.tachiyomi.R +import tachiyomi.presentation.core.util.ThemePreviews + +@Composable +fun ExhUtils( + modifier: Modifier = Modifier, + isVisible: Boolean, + onSetExhUtilsVisibility: (Boolean) -> Unit, + backgroundColor: Color, + isAutoScroll: Boolean, + isAutoScrollEnabled: Boolean, + onToggleAutoscroll: (Boolean) -> Unit, + autoScrollFrequency: String, + onSetAutoScrollFrequency: (String) -> Unit, + onClickAutoScrollHelp: () -> Unit, + onClickRetryAll: () -> Unit, + onClickRetryAllHelp: () -> Unit, + onClickBoostPage: () -> Unit, + onClickBoostPageHelp: () -> Unit, +) { + Column( + modifier + .fillMaxWidth() + .background(backgroundColor) + ) { + AnimatedVisibility(visible = isVisible) { + Column { + Row( + Modifier.fillMaxWidth().height(IntrinsicSize.Min), + verticalAlignment = Alignment.CenterVertically, + ) { + Row( + Modifier + .fillMaxWidth(0.5f) + .fillMaxHeight() + .clickable(enabled = isAutoScrollEnabled) { onToggleAutoscroll(!isAutoScroll) }, + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = stringResource(R.string.eh_autoscroll), + color = MaterialTheme.colorScheme.onSurface, + fontSize = 13.sp, + fontFamily = FontFamily.SansSerif, + style = MaterialTheme.typography.labelLarge, + modifier = Modifier.padding(start = 24.dp) + ) + Switch( + checked = isAutoScroll, + onCheckedChange = null, + enabled = isAutoScrollEnabled + ) + } + Row( + Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Column(Modifier.weight(3f)) { + var autoScrollFrequencyState by remember { + mutableStateOf(autoScrollFrequency) + } + TextField( + value = autoScrollFrequencyState, + onValueChange = { + autoScrollFrequencyState = it + onSetAutoScrollFrequency(it) + }, + isError = !isAutoScrollEnabled, + singleLine = true, + colors = TextFieldDefaults.colors( + focusedContainerColor = Color.Transparent, + unfocusedContainerColor = Color.Transparent, + focusedTextColor = MaterialTheme.colorScheme.onSurface, + unfocusedTextColor = MaterialTheme.colorScheme.onSurface + ), + modifier = Modifier.fillMaxWidth(), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Decimal + ), + ) + AnimatedVisibility(!isAutoScrollEnabled) { + Text( + text = stringResource(R.string.eh_autoscroll_freq_invalid), + color = MaterialTheme.colorScheme.error, + style = MaterialTheme.typography.labelSmall + ) + } + } + TextButton( + onClick = onClickAutoScrollHelp, + modifier = Modifier.weight(1f), + ) { + Text( + text = "?", + color = MaterialTheme.colorScheme.onSurface, + fontSize = 15.sp, + fontWeight = FontWeight.Bold, + ) + } + } + } + Row( + Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + ) { + Row( + Modifier.fillMaxWidth(0.5f), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + TextButton( + onClick = onClickRetryAll, + modifier = Modifier.weight(3f), + ) { + Text( + text = stringResource(R.string.eh_retry_all), + color = MaterialTheme.colorScheme.onSurface, + fontSize = 13.sp, + fontFamily = FontFamily.SansSerif + ) + } + TextButton( + onClick = onClickRetryAllHelp, + modifier = Modifier.weight(1f), + ) { + Text( + text = "?", + color = MaterialTheme.colorScheme.onSurface, + fontSize = 15.sp, + fontWeight = FontWeight.Bold, + ) + } + } + Row( + Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + TextButton( + onClick = onClickBoostPage, + modifier = Modifier.weight(3f), + ) { + Text( + text = stringResource(R.string.eh_boost_page), + color = MaterialTheme.colorScheme.onSurface, + fontSize = 13.sp, + fontFamily = FontFamily.SansSerif + ) + } + TextButton( + onClick = onClickBoostPageHelp, + modifier = Modifier.weight(1f), + ) { + Text( + text = "?", + color = MaterialTheme.colorScheme.onSurface, + fontSize = 15.sp, + fontWeight = FontWeight.Bold, + ) + } + } + } + } + } + + IconButton( + onClick = { onSetExhUtilsVisibility(!isVisible) }, + modifier = Modifier.fillMaxWidth() + ) { + Icon( + imageVector = if (isVisible) { + Icons.Outlined.KeyboardArrowUp + } else { + Icons.Outlined.KeyboardArrowDown + }, + contentDescription = null, + ) + } + } +} + +@Composable +@ThemePreviews +private fun ExhUtilsPreview() { + TachiyomiTheme { + ExhUtils( + isVisible = true, + onSetExhUtilsVisibility = {}, + backgroundColor = Color.Black, + isAutoScroll = true, + isAutoScrollEnabled = true, + onToggleAutoscroll = {}, + autoScrollFrequency = "3.0", + onSetAutoScrollFrequency = {}, + onClickAutoScrollHelp = {}, + onClickBoostPage = {}, + onClickBoostPageHelp = {}, + onClickRetryAll = {}, + onClickRetryAllHelp = {} + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt index c465a92cd..422e8104c 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -6,14 +6,23 @@ import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutHorizontally 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.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Alignment @@ -22,6 +31,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp +import eu.kanade.presentation.components.AppBar import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.viewer.Viewer @@ -56,8 +66,18 @@ fun BoxIgnoreLayoutDirection(modifier: Modifier, content: @Composable BoxScope.( @Composable fun ReaderAppBars( 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, enabledNext: Boolean, onPreviousChapter: () -> Unit, @@ -74,20 +94,40 @@ fun ReaderAppBars( onClickCropBorder: () -> Unit, onClickSettings: () -> Unit, // SY --> + isExhToolsVisible: Boolean, + onSetExhUtilsVisibility: (Boolean) -> Unit, + isAutoScroll: Boolean, + isAutoScrollEnabled: Boolean, + onToggleAutoscroll: (Boolean) -> Unit, + autoScrollFrequency: String, + onSetAutoScrollFrequency: (String) -> Unit, + onClickAutoScrollHelp: () -> Unit, + onClickRetryAll: () -> Unit, + onClickRetryAllHelp: () -> Unit, + onClickBoostPage: () -> Unit, + onClickBoostPageHelp: () -> Unit, navBarType: NavBarType, currentPageText: String, enabledButtons: Set, - isHttpSource: Boolean, dualPageSplitEnabled: Boolean, doublePages: Boolean, onClickChapterList: () -> Unit, - onClickWebView: () -> Unit, - onClickShare: () -> Unit, onClickPageLayout: () -> Unit, onClickShiftPage: () -> Unit, ) { 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) { + // SY --> + Modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)) + // SY <-- + } else { + Modifier + } // SY --> @@ -104,7 +144,8 @@ fun ReaderAppBars( targetOffsetX = { -it }, animationSpec = animationSpec, ), - modifier = Modifier.padding(bottom = 48.dp, top = 120.dp) + modifier = Modifier + .padding(bottom = 48.dp, top = 120.dp) .align(Alignment.TopStart) ) { ChapterNavigator( @@ -131,7 +172,8 @@ fun ReaderAppBars( targetOffsetX = { it }, animationSpec = animationSpec, ), - modifier = Modifier.padding(bottom = 48.dp, top = 120.dp) + modifier = Modifier + .padding(bottom = 48.dp, top = 120.dp) .align(Alignment.TopEnd) ) { ChapterNavigator( @@ -152,6 +194,72 @@ fun ReaderAppBars( modifier = Modifier.fillMaxHeight(), verticalArrangement = Arrangement.SpaceBetween, ) { + AnimatedVisibility( + visible = visible, + enter = slideInVertically( + initialOffsetY = { -it }, + animationSpec = animationSpec, + ), + exit = slideOutVertically( + targetOffsetY = { -it }, + animationSpec = animationSpec, + ), + ) { + // SY --> + Column(appBarModifier) { + // SY <-- + AppBar( + modifier = /*SY --> */ Modifier /*SY <-- */ + .clickable(onClick = onClickTopAppBar), + backgroundColor = backgroundColor, + title = mangaTitle, + subtitle = chapterTitle, + navigateUp = navigateUp, + /* SY --> 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, + ) + }, + ), + ) + }, SY <-- */ + ) + // SY --> + ExhUtils( + isVisible = isExhToolsVisible, + onSetExhUtilsVisibility = onSetExhUtilsVisibility, + backgroundColor = backgroundColor, + isAutoScroll = isAutoScroll, + isAutoScrollEnabled = isAutoScrollEnabled, + onToggleAutoscroll = onToggleAutoscroll, + autoScrollFrequency = autoScrollFrequency, + onSetAutoScrollFrequency = onSetAutoScrollFrequency, + onClickAutoScrollHelp = onClickAutoScrollHelp, + onClickRetryAll = onClickRetryAll, + onClickRetryAllHelp = onClickRetryAllHelp, + onClickBoostPage = onClickBoostPage, + onClickBoostPageHelp = onClickBoostPageHelp + ) + // SY <-- + } + } + + Spacer(modifier = Modifier.weight(1f)) AnimatedVisibility( @@ -187,6 +295,7 @@ fun ReaderAppBars( // SY --> enabledButtons = enabledButtons, // SY <-- + backgroundColor = backgroundColor, readingMode = readingMode, onClickReadingMode = onClickReadingMode, orientationMode = orientationMode, @@ -195,12 +304,11 @@ fun ReaderAppBars( onClickCropBorder = onClickCropBorder, onClickSettings = onClickSettings, // SY --> - isHttpSource = isHttpSource, dualPageSplitEnabled = dualPageSplitEnabled, doublePages = doublePages, onClickChapterList = onClickChapterList, - onClickWebView = onClickWebView, - onClickShare = onClickShare, + onClickWebView = onOpenInWebView, + onClickShare = onShare, onClickPageLayout = onClickPageLayout, onClickShiftPage = onClickShiftPage ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 5d7e6b4a4..4875c2c09 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -5,7 +5,6 @@ import android.annotation.TargetApi import android.app.assist.AssistContent import android.content.Context import android.content.Intent -import android.content.res.ColorStateList import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.Color @@ -15,19 +14,11 @@ import android.graphics.Paint import android.net.Uri import android.os.Build import android.os.Bundle -import android.text.Editable -import android.text.TextUtils -import android.text.TextWatcher import android.view.KeyEvent -import android.view.Menu import android.view.MotionEvent import android.view.View import android.view.View.LAYER_TYPE_HARDWARE import android.view.WindowManager -import android.view.animation.Animation -import android.view.animation.AnimationUtils -import android.widget.CompoundButton -import android.widget.TextView import android.widget.Toast import androidx.activity.viewModels import androidx.compose.foundation.layout.Arrangement @@ -35,6 +26,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.material3.AlertDialog import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -55,9 +47,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.google.android.material.internal.ToolbarUtils -import com.google.android.material.shape.MaterialShapeDrawable +import com.google.android.material.elevation.SurfaceColors import com.google.android.material.transition.platform.MaterialContainerTransform import dev.chrisbanes.insetter.applyInsetter import eu.kanade.domain.base.BasePreferences @@ -75,6 +65,7 @@ import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.databinding.ReaderActivityBinding import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.ui.base.activity.BaseActivity import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.reader.ReaderViewModel.SetAsCoverResult.AddToLibraryFirst @@ -94,22 +85,16 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer 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.isNightMode import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.view.setComposeContent -import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener import exh.source.isEhBasedSource import exh.util.defaultReaderType import exh.util.mangaType -import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filterNotNull @@ -118,7 +103,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch import logcat.LogPriority @@ -271,19 +255,6 @@ class ReaderActivity : BaseActivity() { .launchIn(lifecycleScope) } - // SY --> - private fun setEhUtilsVisibility(visible: Boolean) { - viewModel.showEhUtils(visible) - if (visible) { - binding.ehUtils.isVisible = true - binding.expandEhButton.setImageResource(R.drawable.ic_keyboard_arrow_up_white_32dp) - } else { - binding.ehUtils.isVisible = false - binding.expandEhButton.setImageResource(R.drawable.ic_keyboard_arrow_down_white_32dp) - } - } - // SY <-- - /** * Called when the activity is destroyed. Cleans up the viewer, configuration and any view. */ @@ -326,47 +297,6 @@ class ReaderActivity : BaseActivity() { 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 * delegated to the presenter. @@ -405,69 +335,16 @@ class ReaderActivity : BaseActivity() { return handled || super.dispatchGenericMotionEvent(event) } - // SY --> - fun TextView.textChanges(): Flow = callbackFlow { - val listener = object : TextWatcher { - override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit - - override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { - trySend(s) - } - - override fun afterTextChanged(s: Editable) = Unit - } - - addTextChangedListener(listener) - awaitClose { removeTextChangedListener(listener) } - } - .conflate() - .onStart { emit(text) } - - fun CompoundButton.checkedChanges(): Flow = callbackFlow { - val listener = CompoundButton.OnCheckedChangeListener { _, isChecked -> - trySend(isChecked) - } - setOnCheckedChangeListener(listener) - - awaitClose { setOnCheckedChangeListener(null) } - } - .conflate() - .onStart { emit(isChecked) } - // SY <-- - /** * Initializes the reader menu. It sets up click listeners and the initial visibility. */ private fun initializeMenu() { - setSupportActionBar(binding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - binding.toolbar.setNavigationOnClickListener { - onBackPressedDispatcher.onBackPressed() - } - - binding.header.applyInsetter { - type(navigationBars = true, statusBars = true) { - margin(top = true, horizontal = true) - } - } binding.dialogRoot.applyInsetter { type(navigationBars = 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 { val state by viewModel.state.collectAsState() val showPageNumber by viewModel.readerPreferences.showPageNumber().collectAsState() @@ -493,6 +370,9 @@ class ReaderActivity : BaseActivity() { ) } + val isHttpSource = viewModel.getSource() is HttpSource + val isFullscreen by readerPreferences.fullscreen().collectAsState() + val cropBorderPaged by readerPreferences.cropBorders().collectAsState() val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() // SY --> @@ -526,11 +406,20 @@ class ReaderActivity : BaseActivity() { } // SY <-- - ReaderAppBars( 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, enabledNext = state.viewerChapters?.nextChapter != null, onPreviousChapter = ::loadPreviousChapter, @@ -557,34 +446,29 @@ class ReaderActivity : BaseActivity() { cropEnabled = cropEnabled, onClickCropBorder = { val enabled = viewModel.toggleCropBorders() - menuToggleToast?.cancel() - menuToggleToast = toast( - if (enabled) { - R.string.on - } else { - R.string.off - }, - ) + menuToggleToast = toast(if (enabled) R.string.on else R.string.off) }, onClickSettings = viewModel::openSettingsDialog, // SY --> + isExhToolsVisible = state.ehUtilsVisible, + onSetExhUtilsVisibility = viewModel::showEhUtils, + isAutoScroll = state.autoScroll, + isAutoScrollEnabled = state.isAutoScrollEnabled, + onToggleAutoscroll = viewModel::toggleAutoScroll, + autoScrollFrequency = state.ehAutoscrollFreq, + onSetAutoScrollFrequency = viewModel::setAutoScrollFrequency, + onClickAutoScrollHelp = viewModel::openAutoScrollHelpDialog, + onClickRetryAll = ::exhRetryAll, + onClickRetryAllHelp = viewModel::openRetryAllHelp, + onClickBoostPage = ::exhBoostPage, + onClickBoostPageHelp = viewModel::openBoostPageHelp, currentPageText = state.currentPageText, navBarType = navBarType, enabledButtons = readerBottomButtons, - isHttpSource = remember { - viewModel.getSource() != null - }, dualPageSplitEnabled = dualPageSplitPaged, doublePages = state.doublePages, onClickChapterList = viewModel::openChapterListDialog, - onClickWebView = ::openChapterInWebView, - onClickShare = { - assistUrl?.let { - val intent = it.toUri().toShareIntent(this@ReaderActivity, type = "text/plain") - startActivity(Intent.createChooser(intent, getString(R.string.action_share))) - } - }, onClickPageLayout = { if (readerPreferences.pageLayout().get() == PagerConfig.PageLayout.AUTOMATIC) { (viewModel.state.value.viewer as? PagerViewer)?.config?.let { config -> @@ -682,188 +566,154 @@ class ReaderActivity : BaseActivity() { state.dateRelativeTime ) } + // SY --> + ReaderViewModel.Dialog.AutoScrollHelp -> AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(R.string.action_ok)) + } + }, + title = { Text(text = stringResource(R.string.eh_autoscroll_help)) }, + text = { Text(text = stringResource(R.string.eh_autoscroll_help_message)) }, + ) + ReaderViewModel.Dialog.BoostPageHelp -> AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(R.string.action_ok)) + } + }, + title = { Text(text = stringResource(R.string.eh_boost_page_help)) }, + text = { Text(text = stringResource(R.string.eh_boost_page_help_message)) }, + ) + ReaderViewModel.Dialog.RetryAllHelp -> AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(R.string.action_ok)) + } + }, + title = { Text(text = stringResource(R.string.eh_retry_all_help)) }, + text = { Text(text = stringResource(R.string.eh_retry_all_help_message)) }, + ) + // SY <-- null -> {} + } } - // SY --> - initDropdownMenu() - // SY <-- - - 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( - toolbarBackground.resolvedTintColor, - toolbarBackground.alpha, + SurfaceColors.SURFACE_2.getColor(this), + if (isNightMode()) 230 else 242, // 90% dark 95% light ) window.statusBarColor = toolbarColor if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { window.navigationBarColor = toolbarColor } - // SY --> - binding.toolbar.background.alpha = 0 - (binding.header.background as MaterialShapeDrawable).fillColor = ColorStateList.valueOf(toolbarColor) - // SY <-- // Set initial visibility setMenuVisibility(viewModel.state.value.menuVisible) - // --> EH - setEhUtilsVisibility(viewModel.state.value.ehUtilsVisible) - // <-- EH + enableExhAutoScroll() } - // EXH --> - fun initDropdownMenu() { - binding.expandEhButton.setOnClickListener { - val newValue = !viewModel.state.value.ehUtilsVisible - viewModel.showEhUtils(newValue) - setEhUtilsVisibility(newValue) - } - - binding.ehAutoscrollFreq.setText( - readerPreferences.autoscrollInterval().get().let { - if (it == -1f) { - "" - } else { - it.toString() - } - }, - ) - - binding.ehAutoscroll.checkedChanges() - .combine(binding.ehAutoscrollFreq.textChanges()) { checked, text -> - checked to text - } - .mapLatest { (checked, text) -> - val parsed = text.toString().toDoubleOrNull() - - if (parsed == null || parsed <= 0 || parsed > 9999) { - binding.ehAutoscrollFreq.error = getString(R.string.eh_autoscroll_freq_invalid) - readerPreferences.autoscrollInterval().set(-1f) - binding.ehAutoscroll.isEnabled = false - } else { - binding.ehAutoscrollFreq.error = null - readerPreferences.autoscrollInterval().set(parsed.toFloat()) - binding.ehAutoscroll.isEnabled = true - if (checked) { - repeatOnLifecycle(Lifecycle.State.STARTED) { - val interval = parsed.seconds - while (true) { - if (!binding.readerMenu.isVisible) { - viewModel.state.value.viewer.let { v -> - when (v) { - is PagerViewer -> v.moveToNext() - is WebtoonViewer -> { - if (readerPreferences.smoothAutoScroll().get()) { - v.linearScroll(interval) - } else { - v.scrollDown() - } + private fun enableExhAutoScroll() { + readerPreferences.autoscrollInterval().changes() + .combine(viewModel.state.map { it.autoScroll }.distinctUntilChanged()) { interval, enabled -> + interval.toDouble() to enabled + }.mapLatest { (intervalFloat, enabled) -> + if (enabled) { + repeatOnLifecycle(Lifecycle.State.STARTED) { + val interval = intervalFloat.seconds + while (true) { + if (!viewModel.state.value.menuVisible) { + viewModel.state.value.viewer.let { v -> + when (v) { + is PagerViewer -> v.moveToNext() + is WebtoonViewer -> { + if (readerPreferences.smoothAutoScroll().get()) { + v.linearScroll(interval) + } else { + v.scrollDown() } } } - delay(interval) - } else { - delay(100) } + delay(interval) + } else { + delay(100) } } } } } .launchIn(lifecycleScope) + } - binding.ehAutoscrollHelp.setOnClickListener { - MaterialAlertDialogBuilder(this) - .setTitle(R.string.eh_autoscroll_help) - .setMessage(R.string.eh_autoscroll_help_message) - .setPositiveButton(R.string.action_ok, null) - .show() - } + private fun exhRetryAll() { + var retried = 0 - binding.ehRetryAll.setOnClickListener { - var retried = 0 + viewModel.state.value.viewerChapters + ?.currChapter + ?.pages + ?.forEachIndexed { _, page -> + var shouldQueuePage = false + if (page.status == Page.State.ERROR) { + shouldQueuePage = true + } /*else if (page.status == Page.LOAD_PAGE || + page.status == Page.DOWNLOAD_IMAGE) { + // Do nothing + }*/ - viewModel.state.value.viewerChapters - ?.currChapter - ?.pages - ?.forEachIndexed { _, page -> - var shouldQueuePage = false - if (page.status == Page.State.ERROR) { - shouldQueuePage = true - } /*else if (page.status == Page.LOAD_PAGE || - page.status == Page.DOWNLOAD_IMAGE) { - // Do nothing - }*/ - - if (shouldQueuePage) { - page.status = Page.State.QUEUE - } else { - return@forEachIndexed - } - - // If we are using EHentai/ExHentai, get a new image URL - viewModel.manga?.let { m -> - val src = sourceManager.get(m.source) - if (src?.isEhBasedSource() == true) { - page.imageUrl = null - } - } - - val loader = page.chapter.pageLoader - if (page.index == exhCurrentpage()?.index && loader is HttpPageLoader) { - loader.boostPage(page) - } else { - loader?.retryPage(page) - } - - retried++ - } - - toast(resources.getQuantityString(R.plurals.eh_retry_toast, retried, retried)) - } - - binding.ehRetryAllHelp.setOnClickListener { - MaterialAlertDialogBuilder(this) - .setTitle(R.string.eh_retry_all_help) - .setMessage(R.string.eh_retry_all_help_message) - .setPositiveButton(R.string.action_ok, null) - .show() - } - - binding.ehBoostPage.setOnClickListener { - viewModel.state.value.viewer ?: return@setOnClickListener - val curPage = exhCurrentpage() ?: run { - toast(R.string.eh_boost_page_invalid) - return@setOnClickListener - } - - if (curPage.status == Page.State.ERROR) { - toast(R.string.eh_boost_page_errored) - } else if (curPage.status == Page.State.LOAD_PAGE || curPage.status == Page.State.DOWNLOAD_IMAGE) { - toast(R.string.eh_boost_page_downloading) - } else if (curPage.status == Page.State.READY) { - toast(R.string.eh_boost_page_downloaded) - } else { - val loader = (viewModel.state.value.viewerChapters?.currChapter?.pageLoader as? HttpPageLoader) - if (loader != null) { - loader.boostPage(curPage) - toast(R.string.eh_boost_boosted) + if (shouldQueuePage) { + page.status = Page.State.QUEUE } else { - toast(R.string.eh_boost_invalid_loader) + return@forEachIndexed } + + // If we are using EHentai/ExHentai, get a new image URL + viewModel.manga?.let { m -> + val src = sourceManager.get(m.source) + if (src?.isEhBasedSource() == true) { + page.imageUrl = null + } + } + + val loader = page.chapter.pageLoader + if (page.index == exhCurrentpage()?.index && loader is HttpPageLoader) { + loader.boostPage(page) + } else { + loader?.retryPage(page) + } + + retried++ } + + toast(resources.getQuantityString(R.plurals.eh_retry_toast, retried, retried)) + } + + private fun exhBoostPage() { + viewModel.state.value.viewer ?: return + val curPage = exhCurrentpage() ?: run { + toast(R.string.eh_boost_page_invalid) + return } - binding.ehBoostPageHelp.setOnClickListener { - MaterialAlertDialogBuilder(this) - .setTitle(R.string.eh_boost_page_help) - .setMessage(R.string.eh_boost_page_help_message) - .setPositiveButton(R.string.action_ok, null) - .show() + if (curPage.status == Page.State.ERROR) { + toast(R.string.eh_boost_page_errored) + } else if (curPage.status == Page.State.LOAD_PAGE || curPage.status == Page.State.DOWNLOAD_IMAGE) { + toast(R.string.eh_boost_page_downloading) + } else if (curPage.status == Page.State.READY) { + toast(R.string.eh_boost_page_downloaded) + } else { + val loader = (viewModel.state.value.viewerChapters?.currChapter?.pageLoader as? HttpPageLoader) + if (loader != null) { + loader.boostPage(curPage) + toast(R.string.eh_boost_boosted) + } else { + toast(R.string.eh_boost_invalid_loader) + } } } @@ -882,7 +732,7 @@ class ReaderActivity : BaseActivity() { viewer.config.doublePages = doublePages viewModel.setDoublePages(viewer.config.doublePages) } - val currentChapter = viewModel.getCurrentChapter() + val currentChapter = viewModel.state.value.currentChapter if (doublePages) { // If we're moving from singe to double, we want the current page to be the first page val currentPage = viewModel.state.value.currentPage @@ -921,40 +771,12 @@ class ReaderActivity : BaseActivity() { viewModel.showMenus(visible) if (visible) { windowInsetsController.show(WindowInsetsCompat.Type.systemBars()) - binding.readerMenu.isVisible = true - - 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) - } - }, - ) - // EXH --> - binding.header.startAnimation(toolbarAnimation) - // EXH <-- + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) } else { if (readerPreferences.fullscreen().get()) { windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) 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 - } - }, - ) - // EXH --> - binding.header.startAnimation(toolbarAnimation) - // EXH <-- - } } @@ -1001,14 +823,24 @@ class ReaderActivity : BaseActivity() { showReadingModeToast(viewModel.getMangaReadingMode()) } - supportActionBar?.title = manga.title - loadingIndicator = ReaderProgressIndicator(this) binding.readerContainer.addView(loadingIndicator) 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() { val manga = viewModel.manga ?: return val source = viewModel.getSource() ?: return @@ -1018,6 +850,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) { try { readingModeToast?.cancel() @@ -1057,15 +896,6 @@ class ReaderActivity : BaseActivity() { 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 { viewModel.getChapterUrl()?.let { url -> assistUrl = url @@ -1103,7 +933,7 @@ class ReaderActivity : BaseActivity() { */ private fun moveToPageIndex(index: Int) { 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 viewer.moveToPage(page) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index fe0468bac..b4350cfd2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -64,6 +64,7 @@ import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.update @@ -271,6 +272,24 @@ class ReaderViewModel @JvmOverloads constructor( chapterId = currentChapter.chapter.id!! } .launchIn(viewModelScope) + + // SY --> + state.mapLatest { it.ehAutoscrollFreq } + .distinctUntilChanged() + .drop(1) + .onEach { text -> + val parsed = text.toDoubleOrNull() + + if (parsed == null || parsed <= 0 || parsed > 9999) { + readerPreferences.autoscrollInterval().set(-1f) + mutableState.update { it.copy(isAutoScrollEnabled = false) } + } else { + readerPreferences.autoscrollInterval().set(parsed.toFloat()) + mutableState.update { it.copy(isAutoScrollEnabled = true) } + } + } + .launchIn(viewModelScope) + // SY <-- } override fun onCleared() { @@ -319,8 +338,24 @@ class ReaderViewModel @JvmOverloads constructor( val mergedReferences = if (source is MergedSource) runBlocking { getMergedReferencesById.await(manga.id) } else emptyList() val mergedManga = if (source is MergedSource) runBlocking { getMergedMangaById.await(manga.id) }.associateBy { it.id } else emptyMap() val relativeTime = uiPreferences.relativeTime().get() + val autoScrollFreq = readerPreferences.autoscrollInterval().get() // SY <-- - mutableState.update { it.copy(manga = manga /* SY --> */, meta = metadata, mergedManga = mergedManga, dateRelativeTime = relativeTime/* SY <-- */) } + mutableState.update { + it.copy( + manga = manga, + /* SY --> */ + meta = metadata, + mergedManga = mergedManga, + dateRelativeTime = relativeTime, + ehAutoscrollFreq = if (autoScrollFreq == -1f) { + "" + } else { + autoScrollFreq.toString() + }, + isAutoScrollEnabled = autoScrollFreq != -1f + /* SY <-- */ + ) + } if (chapterId == -1L) chapterId = initialChapterId val context = Injekt.get() @@ -384,7 +419,10 @@ class ReaderViewModel @JvmOverloads constructor( it.viewerChapters?.unref() chapterToDownload = cancelQueuedDownloads(newChapters.currChapter) - it.copy(viewerChapters = newChapters) + it.copy( + viewerChapters = newChapters, + bookmarked = newChapters.currChapter.chapter.bookmark, + ) } } return newChapters @@ -686,8 +724,8 @@ class ReaderViewModel @JvmOverloads constructor( /** * Returns the currently active chapter. */ - fun getCurrentChapter(): ReaderChapter? { - return state.value.viewerChapters?.currChapter + private fun getCurrentChapter(): ReaderChapter? { + return state.value.currentChapter } fun getSource() = manga?.source?.let { sourceManager.getOrStub(it) } as? HttpSource @@ -707,9 +745,11 @@ class ReaderViewModel @JvmOverloads constructor( /** * Bookmarks the currently active chapter. */ - fun bookmarkCurrentChapter(bookmarked: Boolean) { + fun toggleChapterBookmark() { val chapter = getCurrentChapter()?.chapter ?: return - chapter.bookmark = bookmarked // Otherwise the bookmark icon doesn't update + val bookmarked = !chapter.bookmark + chapter.bookmark = bookmarked + viewModelScope.launchNonCancellable { updateChapter.await( ChapterUpdate( @@ -718,6 +758,12 @@ class ReaderViewModel @JvmOverloads constructor( ), ) } + + mutableState.update { + it.copy( + bookmarked = bookmarked, + ) + } } // SY --> @@ -868,6 +914,26 @@ class ReaderViewModel @JvmOverloads constructor( fun setDoublePages(doublePages: Boolean) { mutableState.update { it.copy(doublePages = doublePages) } } + + fun openAutoScrollHelpDialog() { + mutableState.update { it.copy(dialog = Dialog.AutoScrollHelp) } + } + + fun openBoostPageHelp() { + mutableState.update { it.copy(dialog = Dialog.BoostPageHelp) } + } + + fun openRetryAllHelp() { + mutableState.update { it.copy(dialog = Dialog.RetryAllHelp) } + } + + fun toggleAutoScroll(enabled: Boolean) { + mutableState.update { it.copy(autoScroll = enabled) } + } + + fun setAutoScrollFrequency(frequency: String) { + mutableState.update { it.copy(ehAutoscrollFreq = frequency) } + } // SY <-- fun showLoadingDialog() { @@ -1168,6 +1234,7 @@ class ReaderViewModel @JvmOverloads constructor( data class State( val manga: Manga? = null, val viewerChapters: ViewerChapters? = null, + val bookmarked: Boolean = false, val isLoadingAdjacentChapter: Boolean = false, val currentPage: Int = -1, @@ -1188,10 +1255,16 @@ class ReaderViewModel @JvmOverloads constructor( val indexChapterToShift: Long? = null, val doublePages: Boolean = false, val dateRelativeTime: Boolean = true, + val autoScroll: Boolean = false, + val isAutoScrollEnabled: Boolean = false, + val ehAutoscrollFreq: String = "", // SY <-- ) { + val currentChapter: ReaderChapter? + get() = viewerChapters?.currChapter + val totalPages: Int - get() = viewerChapters?.currChapter?.pages?.size ?: -1 + get() = currentChapter?.pages?.size ?: -1 } sealed interface Dialog { @@ -1205,6 +1278,12 @@ class ReaderViewModel @JvmOverloads constructor( // SY <-- data class PageActions(val page: ReaderPage/* SY --> */, val extraPage: ReaderPage? = null /* SY <-- */) : Dialog + + // SY --> + data object AutoScrollHelp : Dialog + data object RetryAllHelp : Dialog + data object BoostPageHelp : Dialog + // SY <-- } sealed interface Event { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/listener/SimpleAnimationListener.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/listener/SimpleAnimationListener.kt deleted file mode 100755 index d06ef6443..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/listener/SimpleAnimationListener.kt +++ /dev/null @@ -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) {} -} diff --git a/app/src/main/res/anim/enter_from_top.xml b/app/src/main/res/anim/enter_from_top.xml deleted file mode 100755 index ec0431ba0..000000000 --- a/app/src/main/res/anim/enter_from_top.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/anim/exit_to_top.xml b/app/src/main/res/anim/exit_to_top.xml deleted file mode 100755 index 3a6f3e9db..000000000 --- a/app/src/main/res/anim/exit_to_top.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bookmark_24dp.xml b/app/src/main/res/drawable/ic_bookmark_24dp.xml deleted file mode 100644 index 0c63a2e54..000000000 --- a/app/src/main/res/drawable/ic_bookmark_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_bookmark_border_24dp.xml b/app/src/main/res/drawable/ic_bookmark_border_24dp.xml deleted file mode 100644 index c3d2916eb..000000000 --- a/app/src/main/res/drawable/ic_bookmark_border_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml index c6d2cef9b..2401432ff 100755 --- a/app/src/main/res/layout/reader_activity.xml +++ b/app/src/main/res/layout/reader_activity.xml @@ -1,7 +1,4 @@ @@ -44,145 +41,6 @@ android:layout_height="match_parent" android:visibility="gone" /> - - - - - - - - - - - - - - -