ReaderTransitionView: Use context theme color for texts (#5738)
* Put themed reader context in adapter This avoids creating themed context everytime the page holder is created, this also allows the transition view to use the same themed context. * Check against app night mode to create themed reader context * ReaderTransitionView: Use context theme color for texts The whole reader will need to be recreated when changing reader background while webtoon mode is used, because recreating just the RecyclerView without messing up the scroll position is impossible (I hope I just missed something).
This commit is contained in:
parent
27133520fc
commit
914b686c8e
11 changed files with 64 additions and 59 deletions
|
@ -8,22 +8,19 @@ import androidx.core.text.bold
|
|||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.ReaderTransitionViewBinding
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import eu.kanade.tachiyomi.util.system.isNightMode
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
LinearLayout(context, attrs) {
|
||||
|
||||
private val binding: ReaderTransitionViewBinding
|
||||
private val binding: ReaderTransitionViewBinding =
|
||||
ReaderTransitionViewBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
|
||||
init {
|
||||
binding = ReaderTransitionViewBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
|
||||
fun bind(transition: ChapterTransition) {
|
||||
when (transition) {
|
||||
is ChapterTransition.Prev -> bindPrevChapterTransition(transition)
|
||||
|
@ -31,26 +28,6 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At
|
|||
}
|
||||
|
||||
missingChapterWarning(transition)
|
||||
|
||||
val color = when (Injekt.get<PreferencesHelper>().readerTheme().get()) {
|
||||
0 -> context.getColor(android.R.color.black)
|
||||
3 -> context.getColor(automaticTextColor())
|
||||
else -> context.getColor(android.R.color.white)
|
||||
}
|
||||
listOf(binding.upperText, binding.warningText, binding.lowerText).forEach {
|
||||
it.setTextColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks text color for [ReaderActivity] based on light/dark theme preference
|
||||
*/
|
||||
private fun automaticTextColor(): Int {
|
||||
return if (context.isNightMode()) {
|
||||
android.R.color.white
|
||||
} else {
|
||||
android.R.color.black
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActionBar
|
||||
import android.content.Context
|
||||
import android.graphics.PointF
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.view.GestureDetector
|
||||
|
@ -30,7 +31,6 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
|
|||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig.ZoomType
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.createReaderThemeContext
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||
import rx.Observable
|
||||
|
@ -46,9 +46,10 @@ import java.util.concurrent.TimeUnit
|
|||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
class PagerPageHolder(
|
||||
readerThemedContext: Context,
|
||||
val viewer: PagerViewer,
|
||||
val page: ReaderPage
|
||||
) : FrameLayout(viewer.activity), ViewPagerAdapter.PositionableView {
|
||||
) : FrameLayout(readerThemedContext), ViewPagerAdapter.PositionableView {
|
||||
|
||||
/**
|
||||
* Item that identifies this view. Needed by the adapter to not recreate views.
|
||||
|
@ -97,12 +98,6 @@ class PagerPageHolder(
|
|||
*/
|
||||
private var readImageHeaderSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* Context that has been wrapped to use the correct theme values based on the
|
||||
* current app theme and reader background color
|
||||
*/
|
||||
private val readerThemedContext = context.createReaderThemeContext(viewer.config.theme)
|
||||
|
||||
val stateChangedListener = object : SubsamplingScaleImageView.OnStateChangedListener {
|
||||
override fun onScaleChanged(newScale: Float, origin: Int) {
|
||||
viewer.activity.hideMenu()
|
||||
|
@ -423,7 +418,7 @@ class PagerPageHolder(
|
|||
private fun initRetryButton(): PagerButton {
|
||||
if (retryButton != null) return retryButton!!
|
||||
|
||||
retryButton = PagerButton(readerThemedContext, viewer).apply {
|
||||
retryButton = PagerButton(context, viewer).apply {
|
||||
layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
gravity = Gravity.CENTER
|
||||
}
|
||||
|
@ -450,7 +445,7 @@ class PagerPageHolder(
|
|||
}
|
||||
decodeErrorLayout = decodeLayout
|
||||
|
||||
TextView(readerThemedContext).apply {
|
||||
TextView(context).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
setMargins(margins, margins, margins, margins)
|
||||
}
|
||||
|
@ -460,7 +455,7 @@ class PagerPageHolder(
|
|||
decodeLayout.addView(this)
|
||||
}
|
||||
|
||||
PagerButton(readerThemedContext, viewer).apply {
|
||||
PagerButton(context, viewer).apply {
|
||||
layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
setMargins(margins, margins, margins, margins)
|
||||
}
|
||||
|
@ -474,7 +469,7 @@ class PagerPageHolder(
|
|||
|
||||
val imageUrl = page.imageUrl
|
||||
if (imageUrl.orEmpty().startsWith("http", true)) {
|
||||
PagerButton(readerThemedContext, viewer).apply {
|
||||
PagerButton(context, viewer).apply {
|
||||
layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
setMargins(margins, margins, margins, margins)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -23,9 +24,10 @@ import rx.android.schedulers.AndroidSchedulers
|
|||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
class PagerTransitionHolder(
|
||||
readerThemedContext: Context,
|
||||
val viewer: PagerViewer,
|
||||
val transition: ChapterTransition
|
||||
) : LinearLayout(viewer.activity), ViewPagerAdapter.PositionableView {
|
||||
) : LinearLayout(readerThemedContext), ViewPagerAdapter.PositionableView {
|
||||
|
||||
/**
|
||||
* Item that identifies this view. Needed by the adapter to not recreate views.
|
||||
|
|
|
@ -77,7 +77,6 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
|||
pager.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
pager.offscreenPageLimit = 1
|
||||
pager.id = R.id.reader_pager
|
||||
pager.adapter = adapter
|
||||
pager.addOnPageChangeListener(
|
||||
object : ViewPager.SimpleOnPageChangeListener() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
|
@ -326,6 +325,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
|||
*/
|
||||
private fun refreshAdapter() {
|
||||
val currentItem = pager.currentItem
|
||||
adapter.refresh()
|
||||
pager.adapter = adapter
|
||||
pager.setCurrentItem(currentItem, false)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
|||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.hasMissingChapters
|
||||
import eu.kanade.tachiyomi.util.system.createReaderThemeContext
|
||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||
import timber.log.Timber
|
||||
|
||||
|
@ -32,6 +33,12 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
|
|||
|
||||
var currentChapter: ReaderChapter? = null
|
||||
|
||||
/**
|
||||
* Context that has been wrapped to use the correct theme values based on the
|
||||
* current app theme and reader background color
|
||||
*/
|
||||
private var readerThemedContext = viewer.activity.createReaderThemeContext(viewer.config.theme)
|
||||
|
||||
/**
|
||||
* Updates this adapter with the given [chapters]. It handles setting a few pages of the
|
||||
* next/previous chapter to allow seamless transitions and inverting the pages if the viewer
|
||||
|
@ -130,8 +137,8 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
|
|||
*/
|
||||
override fun createView(container: ViewGroup, position: Int): View {
|
||||
return when (val item = items[position]) {
|
||||
is ReaderPage -> PagerPageHolder(viewer, item)
|
||||
is ChapterTransition -> PagerTransitionHolder(viewer, item)
|
||||
is ReaderPage -> PagerPageHolder(readerThemedContext, viewer, item)
|
||||
is ChapterTransition -> PagerTransitionHolder(readerThemedContext, viewer, item)
|
||||
else -> throw NotImplementedError("Holder for ${item.javaClass} not implemented")
|
||||
}
|
||||
}
|
||||
|
@ -188,4 +195,8 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
|
|||
items.removeAll(insertPages)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
readerThemedContext = viewer.activity.createReaderThemeContext(viewer.config.theme)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
|||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.hasMissingChapters
|
||||
import eu.kanade.tachiyomi.util.system.createReaderThemeContext
|
||||
|
||||
/**
|
||||
* RecyclerView Adapter used by this [viewer] to where [ViewerChapters] updates are posted.
|
||||
|
@ -24,6 +25,12 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter<RecyclerV
|
|||
|
||||
var currentChapter: ReaderChapter? = null
|
||||
|
||||
/**
|
||||
* Context that has been wrapped to use the correct theme values based on the
|
||||
* current app theme and reader background color
|
||||
*/
|
||||
private var readerThemedContext = viewer.activity.createReaderThemeContext(viewer.config.theme)
|
||||
|
||||
/**
|
||||
* Updates this adapter with the given [chapters]. It handles setting a few pages of the
|
||||
* next/previous chapter to allow seamless transitions.
|
||||
|
@ -77,6 +84,10 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter<RecyclerV
|
|||
result.dispatchUpdatesTo(this)
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
readerThemedContext = viewer.activity.createReaderThemeContext(viewer.config.theme)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of items of the adapter.
|
||||
*/
|
||||
|
@ -101,11 +112,11 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter<RecyclerV
|
|||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
PAGE_VIEW -> {
|
||||
val view = FrameLayout(parent.context)
|
||||
val view = FrameLayout(readerThemedContext)
|
||||
WebtoonPageHolder(view, viewer)
|
||||
}
|
||||
TRANSITION_VIEW -> {
|
||||
val view = LinearLayout(parent.context)
|
||||
val view = LinearLayout(readerThemedContext)
|
||||
WebtoonTransitionHolder(view, viewer)
|
||||
}
|
||||
else -> error("Unknown view type")
|
||||
|
|
|
@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.navigation.KindlishNavigation
|
|||
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.RightAndLeftNavigation
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -22,14 +23,15 @@ class WebtoonConfig(
|
|||
preferences: PreferencesHelper = Injekt.get()
|
||||
) : ViewerConfig(preferences, scope) {
|
||||
|
||||
var themeChangedListener: (() -> Unit)? = null
|
||||
|
||||
var imageCropBorders = false
|
||||
private set
|
||||
|
||||
var sidePadding = 0
|
||||
private set
|
||||
|
||||
var theme = preferences.readerTheme().get()
|
||||
private set
|
||||
val theme = preferences.readerTheme().get()
|
||||
|
||||
init {
|
||||
preferences.cropBordersWebtoon()
|
||||
|
@ -54,8 +56,11 @@ class WebtoonConfig(
|
|||
preferences.dualPageInvertWebtoon()
|
||||
.register({ dualPageInvert = it }, { imagePropertyChangedListener?.invoke() })
|
||||
|
||||
preferences.readerTheme()
|
||||
.register({ theme = it }, { imagePropertyChangedListener?.invoke() })
|
||||
preferences.readerTheme().asFlow()
|
||||
.drop(1)
|
||||
.distinctUntilChanged()
|
||||
.onEach { themeChangedListener?.invoke() }
|
||||
.launchIn(scope)
|
||||
}
|
||||
|
||||
override var navigator: ViewerNavigation = defaultNavigation()
|
||||
|
|
|
@ -27,7 +27,6 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
|||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.createReaderThemeContext
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
|
@ -346,8 +345,7 @@ class WebtoonPageHolder(
|
|||
progressContainer = FrameLayout(context)
|
||||
frame.addView(progressContainer, MATCH_PARENT, parentHeight)
|
||||
|
||||
val indicatorContext = context.createReaderThemeContext(viewer.config.theme)
|
||||
val progress = ReaderProgressIndicator(indicatorContext).apply {
|
||||
val progress = ReaderProgressIndicator(context).apply {
|
||||
updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
gravity = Gravity.CENTER_HORIZONTAL
|
||||
updateMargins(top = parentHeight / 4)
|
||||
|
|
|
@ -48,6 +48,11 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
|||
*/
|
||||
private val layoutManager = WebtoonLayoutManager(activity)
|
||||
|
||||
/**
|
||||
* Configuration used by this viewer, like allow taps, or crop image borders.
|
||||
*/
|
||||
val config = WebtoonConfig(scope)
|
||||
|
||||
/**
|
||||
* Adapter of the recycler view.
|
||||
*/
|
||||
|
@ -63,11 +68,6 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
|||
*/
|
||||
private var currentPage: Any? = null
|
||||
|
||||
/**
|
||||
* Configuration used by this viewer, like allow taps, or crop image borders.
|
||||
*/
|
||||
val config = WebtoonConfig(scope)
|
||||
|
||||
/**
|
||||
* Subscriptions to keep while this viewer is used.
|
||||
*/
|
||||
|
@ -138,6 +138,10 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
|||
refreshAdapter()
|
||||
}
|
||||
|
||||
config.themeChangedListener = {
|
||||
activity.recreate()
|
||||
}
|
||||
|
||||
config.navigationModeChangedListener = {
|
||||
val showOnStart = config.navigationOverlayOnStart || config.forceNavigationOverlay
|
||||
activity.binding.navigationOverlay.setNavigation(config.navigator, config.tappingEnabled, showOnStart)
|
||||
|
@ -338,6 +342,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
|||
*/
|
||||
private fun refreshAdapter() {
|
||||
val position = layoutManager.findLastEndVisibleItemPosition()
|
||||
adapter.refresh()
|
||||
adapter.notifyItemRangeChanged(
|
||||
max(0, position - 3),
|
||||
min(position + 3, adapter.itemCount - 1)
|
||||
|
|
|
@ -310,7 +310,7 @@ fun Context.isNightMode(): Boolean {
|
|||
fun Context.createReaderThemeContext(readerThemeSelected: Int): Context {
|
||||
val isDarkBackground = when (readerThemeSelected) {
|
||||
1, 2 -> true // Black, Gray
|
||||
3 -> isNightMode() // Automatic bg uses activity background by default
|
||||
3 -> applicationContext.isNightMode() // Automatic bg uses activity background by default
|
||||
else -> false // White
|
||||
}
|
||||
val expected = if (isDarkBackground) Configuration.UI_MODE_NIGHT_YES else Configuration.UI_MODE_NIGHT_NO
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textSize="17.5sp"
|
||||
android:textAppearance="?attr/textAppearanceSubtitle1"
|
||||
tools:text="Top" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -35,6 +35,7 @@
|
|||
android:id="@+id/warning_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceSubtitle1"
|
||||
tools:text="Warning" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -43,7 +44,7 @@
|
|||
android:id="@+id/lower_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="17.5sp"
|
||||
android:textAppearance="?attr/textAppearanceSubtitle1"
|
||||
tools:text="Bottom" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
Reference in a new issue