mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Migrate reader slider and next/prev buttons to Compose
This commit is contained in:
		| @@ -0,0 +1,121 @@ | ||||
| package eu.kanade.presentation.reader | ||||
|  | ||||
| import androidx.compose.foundation.background | ||||
| import androidx.compose.foundation.layout.Row | ||||
| import androidx.compose.foundation.layout.Spacer | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.shape.RoundedCornerShape | ||||
| import androidx.compose.material.icons.Icons | ||||
| import androidx.compose.material.icons.outlined.SkipNext | ||||
| import androidx.compose.material.icons.outlined.SkipPrevious | ||||
| import androidx.compose.material3.FilledIconButton | ||||
| import androidx.compose.material3.Icon | ||||
| import androidx.compose.material3.IconButtonDefaults | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.Slider | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.runtime.CompositionLocalProvider | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.draw.clip | ||||
| import androidx.compose.ui.hapticfeedback.HapticFeedbackType | ||||
| import androidx.compose.ui.platform.LocalHapticFeedback | ||||
| import androidx.compose.ui.platform.LocalLayoutDirection | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.unit.LayoutDirection | ||||
| import androidx.compose.ui.unit.dp | ||||
| import eu.kanade.presentation.util.isTabletUi | ||||
| import eu.kanade.tachiyomi.R | ||||
|  | ||||
| @Composable | ||||
| fun ChapterNavigator( | ||||
|     isRtl: Boolean, | ||||
|     onNextChapter: () -> Unit, | ||||
|     enabledNext: Boolean, | ||||
|     onPreviousChapter: () -> Unit, | ||||
|     enabledPrevious: Boolean, | ||||
|     currentPage: Int, | ||||
|     totalPages: Int, | ||||
|     onSliderValueChange: (Int) -> Unit, | ||||
| ) { | ||||
|     val isTabletUi = isTabletUi() | ||||
|     val horizontalPadding = if (isTabletUi) 24.dp else 16.dp | ||||
|     val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr | ||||
|  | ||||
|     val backgroundColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.9f) | ||||
|     val haptic = LocalHapticFeedback.current | ||||
|  | ||||
|     // We explicitly handle direction based on the reader viewer rather than the system direction | ||||
|     CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { | ||||
|         Row( | ||||
|             modifier = Modifier | ||||
|                 .fillMaxWidth() | ||||
|                 .padding(horizontal = horizontalPadding), | ||||
|             verticalAlignment = Alignment.CenterVertically, | ||||
|         ) { | ||||
|             val isLeftEnabled = if (isRtl) enabledNext else enabledPrevious | ||||
|             if (isLeftEnabled) { | ||||
|                 FilledIconButton( | ||||
|                     onClick = if (isRtl) onNextChapter else onPreviousChapter, | ||||
|                     colors = IconButtonDefaults.filledIconButtonColors( | ||||
|                         containerColor = backgroundColor, | ||||
|                     ), | ||||
|                 ) { | ||||
|                     Icon( | ||||
|                         imageVector = Icons.Outlined.SkipPrevious, | ||||
|                         contentDescription = stringResource(if (isRtl) R.string.action_next_chapter else R.string.action_previous_chapter), | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (totalPages > 1) { | ||||
|                 CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) { | ||||
|                     Row( | ||||
|                         modifier = Modifier | ||||
|                             .weight(1f) | ||||
|                             .clip(RoundedCornerShape(24.dp)) | ||||
|                             .background(backgroundColor) | ||||
|                             .padding(horizontal = 16.dp), | ||||
|                         verticalAlignment = Alignment.CenterVertically, | ||||
|                     ) { | ||||
|                         Text(text = currentPage.toString()) | ||||
|  | ||||
|                         Slider( | ||||
|                             modifier = Modifier | ||||
|                                 .weight(1f) | ||||
|                                 .padding(horizontal = 8.dp), | ||||
|                             value = currentPage.toFloat(), | ||||
|                             valueRange = 1f..totalPages.toFloat(), | ||||
|                             steps = totalPages, | ||||
|                             onValueChange = { | ||||
|                                 onSliderValueChange(it.toInt() - 1) | ||||
|                                 haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) | ||||
|                             }, | ||||
|                         ) | ||||
|  | ||||
|                         Text(text = totalPages.toString()) | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 Spacer(Modifier.weight(1f)) | ||||
|             } | ||||
|  | ||||
|             val isRightEnabled = if (isRtl) enabledPrevious else enabledNext | ||||
|             if (isRightEnabled) { | ||||
|                 FilledIconButton( | ||||
|                     onClick = if (isRtl) onPreviousChapter else onNextChapter, | ||||
|                     colors = IconButtonDefaults.filledIconButtonColors( | ||||
|                         containerColor = backgroundColor, | ||||
|                     ), | ||||
|                 ) { | ||||
|                     Icon( | ||||
|                         imageVector = Icons.Outlined.SkipNext, | ||||
|                         contentDescription = stringResource(if (isRtl) R.string.action_previous_chapter else R.string.action_next_chapter), | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -6,18 +6,15 @@ import android.app.ProgressDialog | ||||
| import android.app.assist.AssistContent | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.content.res.ColorStateList | ||||
| import android.graphics.Bitmap | ||||
| import android.graphics.Color | ||||
| import android.graphics.ColorMatrix | ||||
| import android.graphics.ColorMatrixColorFilter | ||||
| import android.graphics.Paint | ||||
| import android.graphics.drawable.RippleDrawable | ||||
| import android.net.Uri | ||||
| import android.os.Build | ||||
| import android.os.Bundle | ||||
| import android.view.Gravity | ||||
| import android.view.HapticFeedbackConstants | ||||
| import android.view.KeyEvent | ||||
| import android.view.Menu | ||||
| import android.view.MenuItem | ||||
| @@ -37,17 +34,16 @@ import androidx.core.transition.doOnEnd | ||||
| import androidx.core.view.WindowCompat | ||||
| import androidx.core.view.WindowInsetsCompat | ||||
| import androidx.core.view.WindowInsetsControllerCompat | ||||
| import androidx.core.view.isInvisible | ||||
| import androidx.core.view.isVisible | ||||
| import androidx.core.view.updateLayoutParams | ||||
| import androidx.lifecycle.lifecycleScope | ||||
| import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView | ||||
| import com.google.android.material.shape.MaterialShapeDrawable | ||||
| import com.google.android.material.slider.Slider | ||||
| import com.google.android.material.transition.platform.MaterialContainerTransform | ||||
| import dev.chrisbanes.insetter.applyInsetter | ||||
| import eu.kanade.domain.base.BasePreferences | ||||
| import eu.kanade.domain.manga.model.orientationType | ||||
| import eu.kanade.presentation.reader.ChapterNavigator | ||||
| import eu.kanade.presentation.reader.PageIndicatorText | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationReceiver | ||||
| @@ -66,14 +62,12 @@ import eu.kanade.tachiyomi.ui.reader.setting.OrientationType | ||||
| import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences | ||||
| import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsSheet | ||||
| import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer | ||||
| import eu.kanade.tachiyomi.ui.webview.WebViewActivity | ||||
| import eu.kanade.tachiyomi.util.preference.toggle | ||||
| import eu.kanade.tachiyomi.util.system.applySystemAnimatorScale | ||||
| import eu.kanade.tachiyomi.util.system.createReaderThemeContext | ||||
| import eu.kanade.tachiyomi.util.system.getThemeColor | ||||
| import eu.kanade.tachiyomi.util.system.hasDisplayCutout | ||||
| import eu.kanade.tachiyomi.util.system.isNightMode | ||||
| import eu.kanade.tachiyomi.util.system.toShareIntent | ||||
| @@ -101,7 +95,6 @@ import tachiyomi.core.util.system.logcat | ||||
| import tachiyomi.domain.manga.model.Manga | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import kotlin.math.abs | ||||
| import kotlin.math.max | ||||
|  | ||||
| class ReaderActivity : BaseActivity() { | ||||
|  | ||||
| @@ -113,9 +106,6 @@ class ReaderActivity : BaseActivity() { | ||||
|                 addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private const val ENABLED_BUTTON_IMAGE_ALPHA = 255 | ||||
|         private const val DISABLED_BUTTON_IMAGE_ALPHA = 64 | ||||
|     } | ||||
|  | ||||
|     private val readerPreferences: ReaderPreferences by injectLazy() | ||||
| @@ -128,12 +118,6 @@ class ReaderActivity : BaseActivity() { | ||||
|  | ||||
|     val hasCutout by lazy { hasDisplayCutout() } | ||||
|  | ||||
|     /** | ||||
|      * Viewer used to display the pages (pager, webtoon, ...). | ||||
|      */ | ||||
|     var viewer: BaseViewer? = null | ||||
|         private set | ||||
|  | ||||
|     /** | ||||
|      * Whether the menu is currently visible. | ||||
|      */ | ||||
| @@ -255,8 +239,7 @@ class ReaderActivity : BaseActivity() { | ||||
|      */ | ||||
|     override fun onDestroy() { | ||||
|         super.onDestroy() | ||||
|         viewer?.destroy() | ||||
|         viewer = null | ||||
|         viewModel.state.value.viewer?.destroy() | ||||
|         config = null | ||||
|         menuToggleToast?.cancel() | ||||
|         readingModeToast?.cancel() | ||||
| @@ -365,7 +348,7 @@ class ReaderActivity : BaseActivity() { | ||||
|      * Dispatches a key event. If the viewer doesn't handle it, call the default implementation. | ||||
|      */ | ||||
|     override fun dispatchKeyEvent(event: KeyEvent): Boolean { | ||||
|         val handled = viewer?.handleKeyEvent(event) ?: false | ||||
|         val handled = viewModel.state.value.viewer?.handleKeyEvent(event) ?: false | ||||
|         return handled || super.dispatchKeyEvent(event) | ||||
|     } | ||||
|  | ||||
| @@ -374,7 +357,7 @@ class ReaderActivity : BaseActivity() { | ||||
|      * implementation. | ||||
|      */ | ||||
|     override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean { | ||||
|         val handled = viewer?.handleGenericMotionEvent(event) ?: false | ||||
|         val handled = viewModel.state.value.viewer?.handleGenericMotionEvent(event) ?: false | ||||
|         return handled || super.dispatchGenericMotionEvent(event) | ||||
|     } | ||||
|  | ||||
| @@ -416,46 +399,30 @@ class ReaderActivity : BaseActivity() { | ||||
|  | ||||
|             PageIndicatorText( | ||||
|                 currentPage = state.currentPage, | ||||
|                 totalPages = state.viewerChapters?.currChapter?.pages?.size ?: -1, | ||||
|                 totalPages = state.totalPages, | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         // Init listeners on bottom menu | ||||
|         binding.pageSlider.addOnSliderTouchListener( | ||||
|             object : Slider.OnSliderTouchListener { | ||||
|                 override fun onStartTrackingTouch(slider: Slider) { | ||||
|                     isScrollingThroughPages = true | ||||
|                 } | ||||
|         binding.readerNav.setComposeContent { | ||||
|             val state by viewModel.state.collectAsState() | ||||
|  | ||||
|                 override fun onStopTrackingTouch(slider: Slider) { | ||||
|                     isScrollingThroughPages = false | ||||
|                 } | ||||
|             }, | ||||
|         ) | ||||
|         binding.pageSlider.addOnChangeListener { slider, value, fromUser -> | ||||
|             if (viewer != null && fromUser) { | ||||
|                 isScrollingThroughPages = true | ||||
|                 moveToPageIndex(value.toInt()) | ||||
|                 slider.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY) | ||||
|             } | ||||
|         } | ||||
|         binding.leftChapter.setOnClickListener { | ||||
|             if (viewer != null) { | ||||
|                 if (viewer is R2LPagerViewer) { | ||||
|                     loadNextChapter() | ||||
|                 } else { | ||||
|                     loadPreviousChapter() | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         binding.rightChapter.setOnClickListener { | ||||
|             if (viewer != null) { | ||||
|                 if (viewer is R2LPagerViewer) { | ||||
|                     loadPreviousChapter() | ||||
|                 } else { | ||||
|                     loadNextChapter() | ||||
|                 } | ||||
|             } | ||||
|             if (state.viewer == null) return@setComposeContent | ||||
|             val isRtl = state.viewer is R2LPagerViewer | ||||
|  | ||||
|             ChapterNavigator( | ||||
|                 isRtl = isRtl, | ||||
|                 onNextChapter = ::loadNextChapter, | ||||
|                 enabledNext = state.viewerChapters?.nextChapter != null, | ||||
|                 onPreviousChapter = ::loadPreviousChapter, | ||||
|                 enabledPrevious = state.viewerChapters?.prevChapter != null, | ||||
|                 currentPage = state.currentPage, | ||||
|                 totalPages = state.totalPages, | ||||
|                 onSliderValueChange = { | ||||
|                     isScrollingThroughPages = true | ||||
|                     moveToPageIndex(it) | ||||
|                 }, | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         initBottomShortcuts() | ||||
| @@ -466,18 +433,6 @@ class ReaderActivity : BaseActivity() { | ||||
|         } | ||||
|         binding.toolbarBottom.background = toolbarBackground.copy(this@ReaderActivity) | ||||
|  | ||||
|         binding.readerSeekbar.background = toolbarBackground.copy(this@ReaderActivity)?.apply { | ||||
|             setCornerSize(999F) | ||||
|         } | ||||
|         listOf(binding.leftChapter, binding.rightChapter).forEach { | ||||
|             it.background = binding.readerSeekbar.background.copy(this) | ||||
|             it.foreground = RippleDrawable( | ||||
|                 ColorStateList.valueOf(getThemeColor(android.R.attr.colorControlHighlight)), | ||||
|                 null, | ||||
|                 it.background, | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         val toolbarColor = ColorUtils.setAlphaComponent( | ||||
|             toolbarBackground.resolvedTintColor, | ||||
|             toolbarBackground.alpha, | ||||
| @@ -671,7 +626,7 @@ class ReaderActivity : BaseActivity() { | ||||
|      * and the toolbar title. | ||||
|      */ | ||||
|     private fun setManga(manga: Manga) { | ||||
|         val prevViewer = viewer | ||||
|         val prevViewer = viewModel.state.value.viewer | ||||
|  | ||||
|         val viewerMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false)) | ||||
|         binding.actionReadingMode.setImageResource(viewerMode.iconRes) | ||||
| @@ -693,7 +648,7 @@ class ReaderActivity : BaseActivity() { | ||||
|             prevViewer.destroy() | ||||
|             binding.viewerContainer.removeAllViews() | ||||
|         } | ||||
|         viewer = newViewer | ||||
|         viewModel.onViewerLoaded(newViewer) | ||||
|         updateViewerInset(readerPreferences.fullscreen().get()) | ||||
|         binding.viewerContainer.addView(newViewer.getView()) | ||||
|  | ||||
| @@ -703,15 +658,6 @@ class ReaderActivity : BaseActivity() { | ||||
|  | ||||
|         supportActionBar?.title = manga.title | ||||
|  | ||||
|         binding.pageSlider.isRTL = newViewer is R2LPagerViewer | ||||
|         if (newViewer is R2LPagerViewer) { | ||||
|             binding.leftChapter.setTooltip(R.string.action_next_chapter) | ||||
|             binding.rightChapter.setTooltip(R.string.action_previous_chapter) | ||||
|         } else { | ||||
|             binding.leftChapter.setTooltip(R.string.action_previous_chapter) | ||||
|             binding.rightChapter.setTooltip(R.string.action_next_chapter) | ||||
|         } | ||||
|  | ||||
|         val loadingIndicatorContext = createReaderThemeContext() | ||||
|         loadingIndicator = ReaderProgressIndicator(loadingIndicatorContext).apply { | ||||
|             updateLayoutParams<FrameLayout.LayoutParams> { | ||||
| @@ -751,26 +697,9 @@ class ReaderActivity : BaseActivity() { | ||||
|      */ | ||||
|     private fun setChapters(viewerChapters: ViewerChapters) { | ||||
|         binding.readerContainer.removeView(loadingIndicator) | ||||
|         viewer?.setChapters(viewerChapters) | ||||
|         viewModel.state.value.viewer?.setChapters(viewerChapters) | ||||
|         binding.toolbar.subtitle = viewerChapters.currChapter.chapter.name | ||||
|  | ||||
|         val currentChapterPageCount = viewerChapters.currChapter.pages?.size ?: 1 | ||||
|         binding.readerSeekbar.isInvisible = currentChapterPageCount == 1 | ||||
|  | ||||
|         val leftChapterObject = if (viewer is R2LPagerViewer) viewerChapters.nextChapter else viewerChapters.prevChapter | ||||
|         val rightChapterObject = if (viewer is R2LPagerViewer) viewerChapters.prevChapter else viewerChapters.nextChapter | ||||
|  | ||||
|         if (leftChapterObject == null && rightChapterObject == null) { | ||||
|             binding.leftChapter.isVisible = false | ||||
|             binding.rightChapter.isVisible = false | ||||
|         } else { | ||||
|             binding.leftChapter.isEnabled = leftChapterObject != null | ||||
|             binding.leftChapter.imageAlpha = if (leftChapterObject != null) ENABLED_BUTTON_IMAGE_ALPHA else DISABLED_BUTTON_IMAGE_ALPHA | ||||
|  | ||||
|             binding.rightChapter.isEnabled = rightChapterObject != null | ||||
|             binding.rightChapter.imageAlpha = if (rightChapterObject != null) ENABLED_BUTTON_IMAGE_ALPHA else DISABLED_BUTTON_IMAGE_ALPHA | ||||
|         } | ||||
|  | ||||
|         // Invalidate menu to show proper chapter bookmark state | ||||
|         invalidateOptionsMenu() | ||||
|  | ||||
| @@ -812,7 +741,7 @@ class ReaderActivity : BaseActivity() { | ||||
|      * page is not found. | ||||
|      */ | ||||
|     private fun moveToPageIndex(index: Int) { | ||||
|         val viewer = viewer ?: return | ||||
|         val viewer = viewModel.state.value.viewer ?: return | ||||
|         val currentChapter = viewModel.getCurrentChapter() ?: return | ||||
|         val page = currentChapter.pages?.getOrNull(index) ?: return | ||||
|         viewer.moveToPage(page) | ||||
| @@ -847,21 +776,6 @@ class ReaderActivity : BaseActivity() { | ||||
|     @SuppressLint("SetTextI18n") | ||||
|     fun onPageSelected(page: ReaderPage) { | ||||
|         viewModel.onPageSelected(page) | ||||
|         val pages = page.chapter.pages ?: return | ||||
|  | ||||
|         // Set page numbers | ||||
|         if (viewer !is R2LPagerViewer) { | ||||
|             binding.leftPageText.text = "${page.number}" | ||||
|             binding.rightPageText.text = "${pages.size}" | ||||
|         } else { | ||||
|             binding.rightPageText.text = "${page.number}" | ||||
|             binding.leftPageText.text = "${pages.size}" | ||||
|         } | ||||
|  | ||||
|         // Set slider progress | ||||
|         binding.pageSlider.isEnabled = pages.size > 1 | ||||
|         binding.pageSlider.valueTo = max(pages.lastIndex.toFloat(), 1f) | ||||
|         binding.pageSlider.value = page.index.toFloat() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -989,7 +903,7 @@ class ReaderActivity : BaseActivity() { | ||||
|      * Updates viewer inset depending on fullscreen reader preferences. | ||||
|      */ | ||||
|     fun updateViewerInset(fullscreen: Boolean) { | ||||
|         viewer?.getView()?.applyInsetter { | ||||
|         viewModel.state.value.viewer?.getView()?.applyInsetter { | ||||
|             if (!fullscreen) { | ||||
|                 type(navigationBars = true, statusBars = true) { | ||||
|                     padding() | ||||
|   | ||||
| @@ -1,30 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.ui.reader | ||||
|  | ||||
| import android.content.Context | ||||
| import android.util.AttributeSet | ||||
| import com.google.android.material.slider.Slider | ||||
|  | ||||
| /** | ||||
|  * Slider to show current chapter progress. | ||||
|  */ | ||||
| class ReaderSlider @JvmOverloads constructor( | ||||
|     context: Context, | ||||
|     attrs: AttributeSet? = null, | ||||
| ) : Slider(context, attrs) { | ||||
|  | ||||
|     init { | ||||
|         stepSize = 1f | ||||
|         setLabelFormatter { value -> | ||||
|             (value.toInt() + 1).toString() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Whether the slider should draw from right to left. | ||||
|      */ | ||||
|     var isRTL: Boolean | ||||
|         set(value) { | ||||
|             layoutDirection = if (value) LAYOUT_DIRECTION_RTL else LAYOUT_DIRECTION_LTR | ||||
|         } | ||||
|         get() = layoutDirection == LAYOUT_DIRECTION_RTL | ||||
| } | ||||
| @@ -33,6 +33,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters | ||||
| import eu.kanade.tachiyomi.ui.reader.setting.OrientationType | ||||
| import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences | ||||
| import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.Viewer | ||||
| import eu.kanade.tachiyomi.util.chapter.removeDuplicates | ||||
| import eu.kanade.tachiyomi.util.editCover | ||||
| import eu.kanade.tachiyomi.util.lang.byteSize | ||||
| @@ -396,6 +397,14 @@ class ReaderViewModel( | ||||
|         eventChannel.trySend(Event.ReloadViewerChapters) | ||||
|     } | ||||
|  | ||||
|     fun onViewerLoaded(viewer: Viewer?) { | ||||
|         mutableState.update { | ||||
|             it.copy( | ||||
|                 viewer = viewer, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called every time a page changes on the reader. Used to mark the flag of chapters being | ||||
|      * read, update tracking services, enqueue downloaded chapter deletion, and updating the active chapter if this | ||||
| @@ -881,7 +890,15 @@ class ReaderViewModel( | ||||
|         val viewerChapters: ViewerChapters? = null, | ||||
|         val isLoadingAdjacentChapter: Boolean = false, | ||||
|         val currentPage: Int = -1, | ||||
|     ) | ||||
|  | ||||
|         /** | ||||
|          * Viewer used to display the pages (pager, webtoon, ...). | ||||
|          */ | ||||
|         val viewer: Viewer? = null, | ||||
|     ) { | ||||
|         val totalPages: Int | ||||
|             get() = viewerChapters?.currChapter?.pages?.size ?: -1 | ||||
|     } | ||||
|  | ||||
|     sealed class Event { | ||||
|         object ReloadViewerChapters : Event() | ||||
|   | ||||
| @@ -34,7 +34,7 @@ class ReaderReadingModeSettings @JvmOverloads constructor(context: Context, attr | ||||
|  | ||||
|         initGeneralPreferences() | ||||
|  | ||||
|         when ((context as ReaderActivity).viewer) { | ||||
|         when ((context as ReaderActivity).viewModel.state.value.viewer) { | ||||
|             is PagerViewer -> initPagerPreferences() | ||||
|             is WebtoonViewer -> initWebtoonPreferences() | ||||
|         } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import androidx.annotation.DrawableRes | ||||
| import androidx.annotation.StringRes | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.ui.reader.ReaderActivity | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.Viewer | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.pager.L2RPagerViewer | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer | ||||
| @@ -31,7 +31,7 @@ enum class ReadingModeType(val prefValue: Int, @StringRes val stringRes: Int, @D | ||||
|  | ||||
|         fun fromSpinner(position: Int?) = values().find { value -> value.prefValue == position } ?: DEFAULT | ||||
|  | ||||
|         fun toViewer(preference: Int?, activity: ReaderActivity): BaseViewer { | ||||
|         fun toViewer(preference: Int?, activity: ReaderActivity): Viewer { | ||||
|             return when (fromPreference(preference)) { | ||||
|                 LEFT_TO_RIGHT -> L2RPagerViewer(activity) | ||||
|                 RIGHT_TO_LEFT -> R2LPagerViewer(activity) | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters | ||||
| /** | ||||
|  * Interface for implementing a viewer. | ||||
|  */ | ||||
| interface BaseViewer { | ||||
| interface Viewer { | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the view this viewer uses. | ||||
| @@ -17,7 +17,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition | ||||
| import eu.kanade.tachiyomi.ui.reader.model.InsertPage | ||||
| import eu.kanade.tachiyomi.ui.reader.model.ReaderPage | ||||
| import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.Viewer | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation.NavigationRegion | ||||
| import kotlinx.coroutines.MainScope | ||||
| import kotlinx.coroutines.cancel | ||||
| @@ -26,10 +26,10 @@ import uy.kohesive.injekt.injectLazy | ||||
| import kotlin.math.min | ||||
|  | ||||
| /** | ||||
|  * Implementation of a [BaseViewer] to display pages with a [ViewPager]. | ||||
|  * Implementation of a [Viewer] to display pages with a [ViewPager]. | ||||
|  */ | ||||
| @Suppress("LeakingThis") | ||||
| abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { | ||||
| abstract class PagerViewer(val activity: ReaderActivity) : Viewer { | ||||
|  | ||||
|     val downloadManager: DownloadManager by injectLazy() | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage | ||||
| import eu.kanade.tachiyomi.ui.reader.model.StencilPage | ||||
| import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters | ||||
| import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.Viewer | ||||
| import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation.NavigationRegion | ||||
| import kotlinx.coroutines.MainScope | ||||
| import kotlinx.coroutines.cancel | ||||
| @@ -30,9 +30,9 @@ import kotlin.math.max | ||||
| import kotlin.math.min | ||||
|  | ||||
| /** | ||||
|  * Implementation of a [BaseViewer] to display pages with a [RecyclerView]. | ||||
|  * Implementation of a [Viewer] to display pages with a [RecyclerView]. | ||||
|  */ | ||||
| class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true) : BaseViewer { | ||||
| class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true) : Viewer { | ||||
|  | ||||
|     val downloadManager: DownloadManager by injectLazy() | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,6 @@ import android.graphics.drawable.Drawable | ||||
| import android.net.Uri | ||||
| import android.os.Build | ||||
| import android.os.PowerManager | ||||
| import android.util.TypedValue | ||||
| import androidx.annotation.AttrRes | ||||
| import androidx.annotation.ColorInt | ||||
| import androidx.appcompat.view.ContextThemeWrapper | ||||
| @@ -89,19 +88,6 @@ fun Context.hasPermission(permission: String) = PermissionChecker.checkSelfPermi | ||||
|     return color | ||||
| } | ||||
|  | ||||
| @ColorInt fun Context.getThemeColor(attr: Int): Int { | ||||
|     val tv = TypedValue() | ||||
|     return if (this.theme.resolveAttribute(attr, tv, true)) { | ||||
|         if (tv.resourceId != 0) { | ||||
|             getColor(tv.resourceId) | ||||
|         } else { | ||||
|             tv.data | ||||
|         } | ||||
|     } else { | ||||
|         0 | ||||
|     } | ||||
| } | ||||
|  | ||||
| val Context.powerManager: PowerManager | ||||
|     get() = getSystemService()!! | ||||
|  | ||||
|   | ||||
| @@ -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="@android:color/black" | ||||
|         android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z" /> | ||||
| </vector> | ||||
| @@ -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="@android:color/black" | ||||
|         android:pathData="M6,6h2v12L6,18zM9.5,12l8.5,6L18,6z" /> | ||||
| </vector> | ||||
| @@ -59,82 +59,12 @@ | ||||
|             android:layout_gravity="bottom" | ||||
|             android:orientation="vertical"> | ||||
|  | ||||
|             <LinearLayout | ||||
|             <androidx.compose.ui.platform.ComposeView | ||||
|                 android:id="@+id/reader_nav" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginStart="8dp" | ||||
|                 android:layout_marginEnd="8dp" | ||||
|                 android:layout_marginBottom="16dp" | ||||
|                 android:layoutDirection="ltr" | ||||
|                 android:orientation="horizontal"> | ||||
|  | ||||
|                 <ImageButton | ||||
|                     android:id="@+id/left_chapter" | ||||
|                     android:layout_width="48dp" | ||||
|                     android:layout_height="48dp" | ||||
|                     android:layout_marginEnd="8dp" | ||||
|                     android:contentDescription="@string/action_previous_chapter" | ||||
|                     android:padding="@dimen/screen_edge_margin" | ||||
|                     app:srcCompat="@drawable/ic_skip_previous_24dp" | ||||
|                     app:tint="?attr/colorOnSurface" /> | ||||
|  | ||||
|                 <LinearLayout | ||||
|                     android:id="@+id/reader_seekbar" | ||||
|                     android:layout_width="0dp" | ||||
|                     android:layout_height="match_parent" | ||||
|                     android:layout_weight="1" | ||||
|                     android:clickable="true" | ||||
|                     android:paddingStart="8dp" | ||||
|                     android:paddingEnd="8dp" | ||||
|                     tools:ignore="KeyboardInaccessibleWidget"> | ||||
|  | ||||
|                     <TextView | ||||
|                         android:id="@+id/left_page_text" | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="match_parent" | ||||
|                         android:gravity="center" | ||||
|                         android:minWidth="32dp" | ||||
|                         android:textColor="?attr/colorOnSurface" | ||||
|                         android:textSize="15sp" | ||||
|                         tools:text="1" /> | ||||
|  | ||||
|                     <!-- | ||||
|                         Wonky way of setting height due to issues with horizontally centering the thumb in Android 5. | ||||
|                         See https://stackoverflow.com/questions/15701767/android-thumb-is-not-centered-in-seekbar | ||||
|                     --> | ||||
|                     <eu.kanade.tachiyomi.ui.reader.ReaderSlider | ||||
|                         android:id="@+id/page_slider" | ||||
|                         android:layout_width="0dp" | ||||
|                         android:layout_height="wrap_content" | ||||
|                         android:layout_weight="1" | ||||
|                         android:maxHeight="?attr/actionBarSize" | ||||
|                         android:minHeight="?attr/actionBarSize" | ||||
|                         app:tickVisible="true"/> | ||||
|  | ||||
|                     <TextView | ||||
|                         android:id="@+id/right_page_text" | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="match_parent" | ||||
|                         android:gravity="center" | ||||
|                         android:minWidth="32dp" | ||||
|                         android:textColor="?attr/colorOnSurface" | ||||
|                         android:textSize="15sp" | ||||
|                         tools:text="15" /> | ||||
|  | ||||
|                 </LinearLayout> | ||||
|  | ||||
|                 <ImageButton | ||||
|                     android:id="@+id/right_chapter" | ||||
|                     android:layout_width="48dp" | ||||
|                     android:layout_height="48dp" | ||||
|                     android:layout_marginStart="8dp" | ||||
|                     android:contentDescription="@string/action_next_chapter" | ||||
|                     android:padding="@dimen/screen_edge_margin" | ||||
|                     app:srcCompat="@drawable/ic_skip_next_24dp" | ||||
|                     app:tint="?attr/colorOnSurface" /> | ||||
|  | ||||
|             </LinearLayout> | ||||
|                 android:layoutDirection="ltr" /> | ||||
|  | ||||
|             <androidx.constraintlayout.widget.ConstraintLayout | ||||
|                 android:id="@+id/toolbar_bottom" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user