Scale mode option for reader
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
package org.koitharu.kotatsu.core.model
|
||||
|
||||
enum class ZoomMode {
|
||||
|
||||
FIT_CENTER, FIT_HEIGHT, FIT_WIDTH, KEEP_START
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package org.koitharu.kotatsu.ui.reader
|
||||
|
||||
enum class ReaderAction {
|
||||
REPLACE, PREPEND, APPEND
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user