Scale mode option for reader

This commit is contained in:
Koitharu
2020-11-07 13:09:02 +02:00
parent bdebd0578e
commit 28a9659410
34 changed files with 264 additions and 57 deletions

View File

@@ -0,0 +1,6 @@
package org.koitharu.kotatsu.core.model
enum class ZoomMode {
FIT_CENTER, FIT_HEIGHT, FIT_WIDTH, KEEP_START
}

View File

@@ -6,11 +6,13 @@ import org.koitharu.kotatsu.core.model.MangaTag
import org.koitharu.kotatsu.core.model.SortOrder
import org.koitharu.kotatsu.domain.MangaLoaderContext
abstract class RemoteMangaRepository(protected val loaderContext: MangaLoaderContext) : MangaRepository {
abstract class RemoteMangaRepository(
protected val loaderContext: MangaLoaderContext
) : MangaRepository {
protected abstract val source: MangaSource
protected val conf by lazy(LazyThreadSafetyMode.NONE) {
protected val conf by lazy {
loaderContext.getSettings(source)
}

View File

@@ -7,6 +7,7 @@ import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.*
import java.util.*
abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepository(
loaderContext
@@ -14,7 +15,7 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
protected abstract val defaultDomain: String
override val sortOrders = arraySetOf(
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST,
SortOrder.POPULARITY,
SortOrder.ALPHABETICAL

View File

@@ -7,12 +7,14 @@ import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.*
import java.util.*
import kotlin.collections.ArrayList
class DesuMeRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepository(loaderContext) {
override val source = MangaSource.DESUME
override val sortOrders = arraySetOf(
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY,
SortOrder.NEWEST,

View File

@@ -7,13 +7,14 @@ import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.*
import java.util.*
abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
RemoteMangaRepository(loaderContext) {
protected abstract val defaultDomain: String
override val sortOrders = arraySetOf(
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.RATING
//FIXME SortOrder.ALPHABETICAL

View File

@@ -4,13 +4,14 @@ import androidx.collection.ArraySet
import androidx.collection.arraySetOf
import org.json.JSONArray
import org.json.JSONObject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.*
import java.util.*
import kotlin.collections.ArrayList
open class MangaLibRepository(loaderContext: MangaLoaderContext) :
RemoteMangaRepository(loaderContext) {
@@ -19,7 +20,7 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
override val source = MangaSource.MANGALIB
override val sortOrders = arraySetOf(
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.RATING,
SortOrder.ALPHABETICAL,
SortOrder.POPULARITY,

View File

@@ -15,7 +15,7 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
override val source = MangaSource.MANGATOWN
override val sortOrders = arraySetOf(
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL,
SortOrder.RATING,
SortOrder.POPULARITY,

View File

@@ -7,6 +7,7 @@ import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.*
import java.util.*
class MangareadRepository(
loaderContext: MangaLoaderContext
@@ -14,7 +15,10 @@ class MangareadRepository(
override val source = MangaSource.MANGAREAD
override val sortOrders = arraySetOf(SortOrder.UPDATED, SortOrder.POPULARITY)
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY
)
override suspend fun getList(
offset: Int,

View File

@@ -7,13 +7,18 @@ import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.*
import java.util.*
import java.util.regex.Pattern
class NudeMoonRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepository(loaderContext) {
override val source = MangaSource.NUDEMOON
override val sortOrders = arraySetOf(SortOrder.NEWEST, SortOrder.POPULARITY, SortOrder.RATING)
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST,
SortOrder.POPULARITY,
SortOrder.RATING
)
init {
loaderContext.insertCookies(
@@ -35,9 +40,7 @@ class NudeMoonRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposit
tag != null -> "https://$domain/tags/${tag.key}&rowstart=$offset"
else -> "https://$domain/all_manga?${getSortKey(sortOrder)}&rowstart=$offset"
}
val doc = loaderContext.httpGet(url) {
addHeader("Cookie", "NMfYa=1; nm_mobile=0;")
}.parseHtml()
val doc = loaderContext.httpGet(url).parseHtml()
val root = doc.body().run {
selectFirst("td.shoutbox") ?: selectFirst("td.main-bg")
} ?: throw ParseException("Cannot find root")

View File

@@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatDelegate
import androidx.collection.arraySetOf
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.parser.LocalMangaRepository
import org.koitharu.kotatsu.utils.delegates.prefs.*
import java.io.File
@@ -18,13 +19,13 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
PreferenceManager.getDefaultSharedPreferences(context)
)
var listMode by EnumPreferenceDelegate(
var listMode by IntEnumPreferenceDelegate(
ListMode::class.java,
KEY_LIST_MODE,
ListMode.DETAILED_LIST
)
var defaultSection by EnumPreferenceDelegate(
var defaultSection by IntEnumPreferenceDelegate(
AppSection::class.java,
KEY_APP_SECTION,
AppSection.HISTORY
@@ -66,6 +67,12 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
val isPreferRtlReader by BoolPreferenceDelegate(KEY_READER_PREFER_RTL, false)
val zoomMode by EnumPreferenceDelegate(
ZoomMode::class.java,
KEY_ZOOM_MODE,
ZoomMode.FIT_CENTER
)
val trackSources by StringSetPreferenceDelegate(
KEY_TRACK_SOURCES,
arraySetOf(TRACK_FAVOURITES, TRACK_HISTORY)
@@ -143,5 +150,6 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
const val KEY_APP_PASSWORD = "app_password"
const val KEY_PROTECT_APP = "protect_app"
const val KEY_APP_VERSION = "app_version"
const val KEY_ZOOM_MODE = "zoom_mode"
}
}

View File

@@ -13,20 +13,16 @@ open class MangaLoaderContext : KoinComponent {
private val okHttp by inject<OkHttpClient>()
private val cookieJar by inject<CookieJar>()
suspend fun httpGet(url: String, block: (Request.Builder.() -> Unit)? = null): Response {
suspend fun httpGet(url: String): Response {
val request = Request.Builder()
.get()
.url(url)
if (block != null) {
request.block()
}
return okHttp.newCall(request.build()).await()
}
suspend fun httpPost(
url: String,
form: Map<String, String>,
block: (Request.Builder.() -> Unit)? = null
form: Map<String, String>
): Response {
val body = FormBody.Builder()
form.forEach { (k, v) ->
@@ -35,16 +31,12 @@ open class MangaLoaderContext : KoinComponent {
val request = Request.Builder()
.post(body.build())
.url(url)
if (block != null) {
request.block()
}
return okHttp.newCall(request.build()).await()
}
suspend fun httpPost(
url: String,
payload: String,
block: (Request.Builder.() -> Unit)? = null
payload: String
): Response {
val body = FormBody.Builder()
payload.split('&').forEach {
@@ -58,9 +50,6 @@ open class MangaLoaderContext : KoinComponent {
val request = Request.Builder()
.post(body.build())
.url(url)
if (block != null) {
request.block()
}
return okHttp.newCall(request.build()).await()
}

View File

@@ -1,5 +0,0 @@
package org.koitharu.kotatsu.ui.reader
enum class ReaderAction {
REPLACE, PREPEND, APPEND
}

View File

@@ -96,7 +96,7 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
ViewCompat.setOnApplyWindowInsetsListener(rootLayout, this)
settings.subscribe(this)
loadSettings()
loadSwitchSettings()
orientationHelper.observeAutoOrientation()
.onEach {
toolbar_bottom.menu.findItem(R.id.action_screen_rotate).isVisible = !it
@@ -370,7 +370,11 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
loadSettings()
when (key) {
AppSettings.KEY_READER_SWITCHERS -> loadSwitchSettings()
AppSettings.KEY_READER_ANIMATION,
AppSettings.KEY_ZOOM_MODE -> reader?.recreateAdapter()
}
}
private fun showWaitWhileLoading() {
@@ -410,7 +414,7 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
.build()
}
private fun loadSettings() {
private fun loadSwitchSettings() {
settings.readerPageSwitch.let {
isTapSwitchEnabled = it.contains(AppSettings.PAGE_SWITCH_TAPS)
isVolumeKeysSwitchEnabled = it.contains(AppSettings.PAGE_SWITCH_VOLUME_KEYS)

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.ui.reader.base
import android.content.Context
import android.os.Bundle
import android.view.View
import androidx.annotation.CallSuper
import androidx.collection.LongSparseArray
import androidx.core.view.postDelayed
import kotlinx.coroutines.CancellationException
@@ -131,6 +132,11 @@ abstract class AbstractReader(contentLayoutId: Int) : BaseFragment(contentLayout
super.onDestroy()
}
@CallSuper
open fun recreateAdapter() {
adapter = onCreateAdapter(pages)
}
fun getPages(): List<MangaPage>? {
val chapterId = (pages.getOrNull(getCurrentItem()) ?: return null).chapterId
// TODO optimize

View File

@@ -4,7 +4,10 @@ import android.net.Uri
import androidx.core.net.toUri
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import kotlinx.coroutines.*
import org.koin.core.component.inject
import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.ui.reader.PageLoader
import org.koitharu.kotatsu.utils.ext.launchAfter
import org.koitharu.kotatsu.utils.ext.launchInstead
@@ -14,8 +17,10 @@ import java.io.IOException
class PageHolderDelegate(
private val loader: PageLoader,
private val callback: Callback
) : SubsamplingScaleImageView.DefaultOnImageEventListener(), CoroutineScope by loader {
) : SubsamplingScaleImageView.DefaultOnImageEventListener(),
CoroutineScope by loader {
private val settings by loader.inject<AppSettings>()
private var state = State.EMPTY
private var job: Job? = null
private var file: File? = null
@@ -36,7 +41,7 @@ class PageHolderDelegate(
override fun onReady() {
state = State.SHOWING
callback.onImageShowing()
callback.onImageShowing(settings.zoomMode)
}
override fun onImageLoaded() {
@@ -79,7 +84,7 @@ class PageHolderDelegate(
state = State.LOADED
callback.onImageReady(file.toUri())
} catch (e: CancellationException) {
//do nothing
// do nothing
} catch (e: Exception) {
state = State.ERROR
callback.onError(e)
@@ -99,7 +104,7 @@ class PageHolderDelegate(
fun onImageReady(uri: Uri)
fun onImageShowing()
fun onImageShowing(zoom: ZoomMode)
fun onImageShown()
}

View File

@@ -0,0 +1,48 @@
package org.koitharu.kotatsu.ui.reader.reversed
import android.graphics.PointF
import android.view.ViewGroup
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import kotlinx.android.synthetic.main.item_page.*
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.ui.reader.PageLoader
import org.koitharu.kotatsu.ui.reader.standard.PageHolder
class ReversedPageHolder(parent: ViewGroup, loader: PageLoader) : PageHolder(parent, loader) {
override fun onImageShowing(zoom: ZoomMode) {
ssiv.maxScale = 2f * maxOf(
ssiv.width / ssiv.sWidth.toFloat(),
ssiv.height / ssiv.sHeight.toFloat()
)
when (zoom) {
ZoomMode.FIT_CENTER -> {
ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE)
ssiv.resetScaleAndCenter()
}
ZoomMode.FIT_HEIGHT -> {
ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM)
ssiv.minScale = ssiv.height / ssiv.sHeight.toFloat()
ssiv.setScaleAndCenter(
ssiv.minScale,
PointF(ssiv.sWidth.toFloat(), ssiv.sHeight / 2f)
)
}
ZoomMode.FIT_WIDTH -> {
ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM)
ssiv.minScale = ssiv.width / ssiv.sWidth.toFloat()
ssiv.setScaleAndCenter(
ssiv.minScale,
PointF(ssiv.sWidth / 2f, 0f)
)
}
ZoomMode.KEEP_START -> {
ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE)
ssiv.setScaleAndCenter(
ssiv.maxScale,
PointF(ssiv.sWidth.toFloat(), 0f)
)
}
}
}
}

View File

@@ -5,14 +5,13 @@ import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
import org.koitharu.kotatsu.ui.reader.PageLoader
import org.koitharu.kotatsu.ui.reader.base.BaseReaderAdapter
import org.koitharu.kotatsu.ui.reader.base.ReaderPage
import org.koitharu.kotatsu.ui.reader.standard.PageHolder
class ReversedPagesAdapter(
pages: List<ReaderPage>,
private val loader: PageLoader
) : BaseReaderAdapter(pages) {
override fun onCreateViewHolder(parent: ViewGroup) = PageHolder(parent, loader)
override fun onCreateViewHolder(parent: ViewGroup) = ReversedPageHolder(parent, loader)
override fun onBindViewHolder(holder: BaseViewHolder<ReaderPage, Unit>, position: Int) {
super.onBindViewHolder(holder, reversed(position))

View File

@@ -15,6 +15,7 @@ import org.koitharu.kotatsu.ui.reader.base.ReaderPage
import org.koitharu.kotatsu.ui.reader.standard.PageAnimTransformer
import org.koitharu.kotatsu.ui.reader.standard.PagerPaginationListener
import org.koitharu.kotatsu.utils.ext.doOnPageChanged
import org.koitharu.kotatsu.utils.ext.swapAdapter
import org.koitharu.kotatsu.utils.ext.withArgs
class ReversedReaderFragment : AbstractReader(R.layout.fragment_reader_standard),
@@ -56,6 +57,11 @@ class ReversedReaderFragment : AbstractReader(R.layout.fragment_reader_standard)
return ReversedPagesAdapter(dataSet, loader)
}
override fun recreateAdapter() {
super.recreateAdapter()
pager.swapAdapter(adapter)
}
override fun getCurrentItem() = reversed(pager.currentItem)
override fun setCurrentItem(position: Int, isSmooth: Boolean) {

View File

@@ -1,19 +1,22 @@
package org.koitharu.kotatsu.ui.reader.standard
import android.graphics.PointF
import android.net.Uri
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import kotlinx.android.synthetic.main.item_page.*
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
import org.koitharu.kotatsu.ui.reader.PageLoader
import org.koitharu.kotatsu.ui.reader.base.PageHolderDelegate
import org.koitharu.kotatsu.ui.reader.base.ReaderPage
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
class PageHolder(parent: ViewGroup, loader: PageLoader) :
open class PageHolder(parent: ViewGroup, loader: PageLoader) :
BaseViewHolder<ReaderPage, Unit>(parent, R.layout.item_page),
PageHolderDelegate.Callback, View.OnClickListener {
@@ -43,12 +46,40 @@ class PageHolder(parent: ViewGroup, loader: PageLoader) :
ssiv.setImage(ImageSource.uri(uri))
}
override fun onImageShowing() {
override fun onImageShowing(zoom: ZoomMode) {
ssiv.maxScale = 2f * maxOf(
ssiv.width / ssiv.sWidth.toFloat(),
ssiv.height / ssiv.sHeight.toFloat()
)
ssiv.resetScaleAndCenter()
when (zoom) {
ZoomMode.FIT_CENTER -> {
ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE)
ssiv.resetScaleAndCenter()
}
ZoomMode.FIT_HEIGHT -> {
ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM)
ssiv.minScale = ssiv.height / ssiv.sHeight.toFloat()
ssiv.setScaleAndCenter(
ssiv.minScale,
PointF(0f, ssiv.sHeight / 2f)
)
}
ZoomMode.FIT_WIDTH -> {
ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM)
ssiv.minScale = ssiv.width / ssiv.sWidth.toFloat()
ssiv.setScaleAndCenter(
ssiv.minScale,
PointF(ssiv.sWidth / 2f, 0f)
)
}
ZoomMode.KEEP_START -> {
ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE)
ssiv.setScaleAndCenter(
ssiv.maxScale,
PointF(0f, 0f)
)
}
}
}
override fun onImageShown() {

View File

@@ -13,6 +13,7 @@ import org.koitharu.kotatsu.ui.reader.base.AbstractReader
import org.koitharu.kotatsu.ui.reader.base.BaseReaderAdapter
import org.koitharu.kotatsu.ui.reader.base.ReaderPage
import org.koitharu.kotatsu.utils.ext.doOnPageChanged
import org.koitharu.kotatsu.utils.ext.swapAdapter
import org.koitharu.kotatsu.utils.ext.withArgs
class PagerReaderFragment : AbstractReader(R.layout.fragment_reader_standard),
@@ -52,6 +53,11 @@ class PagerReaderFragment : AbstractReader(R.layout.fragment_reader_standard),
return PagesAdapter(dataSet, loader)
}
override fun recreateAdapter() {
super.recreateAdapter()
pager.swapAdapter(adapter)
}
override fun getCurrentItem() = pager.currentItem
override fun setCurrentItem(position: Int, isSmooth: Boolean) {

View File

@@ -8,6 +8,7 @@ import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import kotlinx.android.synthetic.main.item_page_webtoon.*
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
import org.koitharu.kotatsu.ui.reader.PageLoader
import org.koitharu.kotatsu.ui.reader.base.PageHolderDelegate
@@ -46,7 +47,7 @@ class WebtoonHolder(parent: ViewGroup, private val loader: PageLoader) :
ssiv.setImage(ImageSource.uri(uri))
}
override fun onImageShowing() {
override fun onImageShowing(zoom: ZoomMode) {
ssiv.maxScale = 2f * ssiv.width / ssiv.sWidth.toFloat()
ssiv.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM)
ssiv.minScale = ssiv.width / ssiv.sWidth.toFloat()

View File

@@ -32,6 +32,11 @@ class WebtoonReaderFragment : AbstractReader(R.layout.fragment_reader_webtoon) {
return WebtoonAdapter(dataSet, loader)
}
override fun recreateAdapter() {
super.recreateAdapter()
recyclerView.swapAdapter(adapter, true)
}
override fun onDestroyView() {
paginationListener = null
super.onDestroyView()

View File

@@ -16,6 +16,7 @@ import kotlinx.coroutines.launch
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.base.BasePreferenceFragment
@@ -26,6 +27,7 @@ import org.koitharu.kotatsu.ui.settings.utils.MultiSummaryProvider
import org.koitharu.kotatsu.ui.tracker.TrackWorker
import org.koitharu.kotatsu.utils.ext.getStorageName
import org.koitharu.kotatsu.utils.ext.md5
import org.koitharu.kotatsu.utils.ext.names
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import java.io.File
@@ -60,6 +62,11 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings),
summary = settings.getStorageDir(context)?.getStorageName(context)
?: getString(R.string.not_available)
}
findPreference<ListPreference>(AppSettings.KEY_ZOOM_MODE)?.let {
it.entryValues = ZoomMode.values().names()
it.setDefaultValue(ZoomMode.FIT_CENTER.name)
it.summaryProvider = ListPreference.SimpleSummaryProvider.getInstance()
}
findPreference<SwitchPreference>(AppSettings.KEY_PROTECT_APP)?.isChecked =
!settings.appPassword.isNullOrEmpty()
findPreference<Preference>(AppSettings.KEY_APP_VERSION)?.run {

View File

@@ -2,11 +2,14 @@ package org.koitharu.kotatsu.ui.settings
import android.os.Bundle
import android.view.View
import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.ui.base.BasePreferenceFragment
import org.koitharu.kotatsu.ui.settings.utils.MultiSummaryProvider
import org.koitharu.kotatsu.utils.ext.names
class ReaderSettingsFragment : BasePreferenceFragment(R.string.reader_settings) {
@@ -19,5 +22,10 @@ class ReaderSettingsFragment : BasePreferenceFragment(R.string.reader_settings)
findPreference<MultiSelectListPreference>(AppSettings.KEY_READER_SWITCHERS)?.let {
it.summaryProvider = MultiSummaryProvider(R.string.gestures_only)
}
findPreference<ListPreference>(AppSettings.KEY_ZOOM_MODE)?.let {
it.entryValues = ZoomMode.values().names()
it.setDefaultValue(ZoomMode.FIT_CENTER.name)
it.summaryProvider = ListPreference.SimpleSummaryProvider.getInstance()
}
}
}

View File

@@ -9,20 +9,19 @@ class EnumPreferenceDelegate<E : Enum<*>>(
private val cls: Class<E>,
private val key: String,
private val defValue: E
) :
ReadWriteProperty<SharedPreferences, E> {
) : ReadWriteProperty<SharedPreferences, E> {
override fun getValue(thisRef: SharedPreferences, property: KProperty<*>): E {
val ord = thisRef.getInt(key, -1)
if (ord == -1) {
val name = thisRef.getString(key, null)
if (name === null) {
return defValue
}
return cls.enumConstants?.firstOrNull { it.ordinal == ord } ?: defValue
return cls.enumConstants?.find { it.name == name } ?: defValue
}
override fun setValue(thisRef: SharedPreferences, property: KProperty<*>, value: E) {
thisRef.edit {
putInt(key, value.ordinal)
putString(key, value.name)
}
}
}

View File

@@ -0,0 +1,28 @@
package org.koitharu.kotatsu.utils.delegates.prefs
import android.content.SharedPreferences
import androidx.core.content.edit
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
@Deprecated("")
class IntEnumPreferenceDelegate<E : Enum<*>>(
private val cls: Class<E>,
private val key: String,
private val defValue: E
) : ReadWriteProperty<SharedPreferences, E> {
override fun getValue(thisRef: SharedPreferences, property: KProperty<*>): E {
val ord = thisRef.getInt(key, -1)
if (ord == -1) {
return defValue
}
return cls.enumConstants?.getOrNull(ord) ?: defValue
}
override fun setValue(thisRef: SharedPreferences, property: KProperty<*>, value: E) {
thisRef.edit {
putInt(key, value.ordinal)
}
}
}

View File

@@ -66,4 +66,10 @@ inline fun <T> Collection<T>.associateByLong(selector: (T) -> Long): LongSparseA
result.put(selector(item), item)
}
return result
}
}
inline fun <T, reified R> Array<T>.mapToArray(transform: (T) -> R): Array<R> = Array(size) { i ->
transform(get(i))
}
fun <T : Enum<T>> Array<T>.names() = mapToArray { it.name }

View File

@@ -200,4 +200,12 @@ fun RecyclerView.findCenterViewPosition(): Int {
val centerY = height / 2f
val view = findChildViewUnder(centerX, centerY) ?: return RecyclerView.NO_POSITION
return getChildAdapterPosition(view)
}
fun ViewPager2.swapAdapter(newAdapter: RecyclerView.Adapter<*>?) {
val position = currentItem
adapter = newAdapter
if (adapter != null && position != RecyclerView.NO_POSITION) {
currentItem = position
}
}

View File

@@ -163,4 +163,9 @@
<string name="prefer_rtl_reader">Предпочитать режим Справа налево</string>
<string name="prefer_rtl_reader_summary">Вы можете настроить режим чтения для каждой манги отдельно</string>
<string name="create_category">Создать категорию</string>
<string name="scale_mode">Масштабирование</string>
<string name="zoom_mode_fit_center">Вписать в экран</string>
<string name="zoom_mode_fit_height">Подогнать по высоте</string>
<string name="zoom_mode_fit_width">Подогнать по ширине</string>
<string name="zoom_mode_keep_start">Исходный размер</string>
</resources>

View File

@@ -9,6 +9,12 @@
<item>@string/taps_on_edges</item>
<item>@string/volume_buttons</item>
</string-array>
<string-array name="zoom_modes">
<item>@string/zoom_mode_fit_center</item>
<item>@string/zoom_mode_fit_height</item>
<item>@string/zoom_mode_fit_width</item>
<item>@string/zoom_mode_keep_start</item>
</string-array>
<string-array name="track_sources">
<item>@string/favourites</item>
<item>@string/history</item>

View File

@@ -165,4 +165,9 @@
<string name="prefer_rtl_reader_summary">You can set up the reading mode for each manga separately</string>
<string name="create_category">New category</string>
<string name="report_github">Create issue on GitHub</string>
<string name="scale_mode">Scale mode</string>
<string name="zoom_mode_fit_center">Fit center</string>
<string name="zoom_mode_fit_height">Fit to height</string>
<string name="zoom_mode_fit_width">Fit to width</string>
<string name="zoom_mode_keep_start">Keep at start</string>
</resources>

View File

@@ -70,6 +70,12 @@
android:title="@string/pages_animation"
app:iconSpaceReserved="false" />
<ListPreference
android:entries="@array/zoom_modes"
android:key="zoom_mode"
android:title="@string/scale_mode"
app:iconSpaceReserved="false" />
<SwitchPreference
android:defaultValue="false"
android:key="reader_prefer_rtl"

View File

@@ -17,6 +17,12 @@
android:title="@string/pages_animation"
app:iconSpaceReserved="false" />
<ListPreference
android:entries="@array/zoom_modes"
android:key="zoom_mode"
android:title="@string/scale_mode"
app:iconSpaceReserved="false" />
<SwitchPreference
android:defaultValue="false"
android:key="reader_prefer_rtl"