Compare commits

...

9 Commits
v4.1 ... v4.1.1

Author SHA1 Message Date
Koitharu
656a707b4c Bump version 2023-01-01 08:49:15 +02:00
Koitharu
04afe7a934 Bind ssiv with lifecycle 2023-01-01 08:17:07 +02:00
Koitharu
689670b3ff Show inconito mode indicator on Read button 2023-01-01 08:17:03 +02:00
Zakhar Timoshenko
6273a9decb Merge pull request #281 from weblate/weblate-kotatsu-strings
Translations update from Hosted Weblate
2022-12-31 22:37:57 +03:00
Eric
72336d4f71 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (399 of 399 strings)

Co-authored-by: Eric <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2022-12-31 20:33:30 +01:00
J. Lavoie
731e998eb2 Translated using Weblate (French)
Currently translated at 100.0% (399 of 399 strings)

Translated using Weblate (Italian)

Currently translated at 79.9% (319 of 399 strings)

Translated using Weblate (German)

Currently translated at 97.2% (388 of 399 strings)

Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2022-12-31 20:33:30 +01:00
gallegonovato
9bf53114de Translated using Weblate (Spanish)
Currently translated at 100.0% (399 of 399 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2022-12-31 20:33:30 +01:00
Zakhar Timoshenko
0e1b8db688 Update parsers, Happy New Year! 2022-12-31 22:32:35 +03:00
Zakhar Timoshenko
3a62e2e6c0 Add monochrome icon on One UI 5.0 2022-12-31 15:08:47 +03:00
23 changed files with 121 additions and 50 deletions

View File

@@ -15,8 +15,8 @@ android {
applicationId 'org.koitharu.kotatsu' applicationId 'org.koitharu.kotatsu'
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 33 targetSdkVersion 33
versionCode 507 versionCode 508
versionName '4.1' versionName '4.1.1'
generatedDensities = [] generatedDensities = []
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -83,7 +83,7 @@ afterEvaluate {
} }
} }
dependencies { dependencies {
implementation('com.github.KotatsuApp:kotatsu-parsers:9ee1c21a67') { implementation('com.github.KotatsuApp:kotatsu-parsers:c4acb9725f') {
exclude group: 'org.json', module: 'json' exclude group: 'org.json', module: 'json'
} }
@@ -125,7 +125,7 @@ dependencies {
implementation 'io.coil-kt:coil-base:2.2.2' implementation 'io.coil-kt:coil-base:2.2.2'
implementation 'io.coil-kt:coil-svg:2.2.2' implementation 'io.coil-kt:coil-svg:2.2.2'
implementation 'com.github.KotatsuApp:subsampling-scale-image-view:95e6c188c6' implementation 'com.github.KotatsuApp:subsampling-scale-image-view:1b19231b2f'
implementation 'com.github.solkin:disk-lru-cache:1.4' implementation 'com.github.solkin:disk-lru-cache:1.4'
implementation 'ch.acra:acra-http:5.9.7' implementation 'ch.acra:acra-http:5.9.7'

View File

@@ -248,6 +248,9 @@
<meta-data <meta-data
android:name="android.webkit.WebView.MetricsOptOut" android:name="android.webkit.WebView.MetricsOptOut"
android:value="true" /> android:value="true" />
<meta-data
android:name="com.samsung.android.icon_container.has_icon_container"
android:value="@bool/com_samsung_android_icon_container_has_icon_container"/>
</application> </application>

View File

@@ -228,18 +228,18 @@ class DetailsActivity :
} }
} }
private fun onHistoryChanged(info: HistoryInfo?) { private fun onHistoryChanged(info: HistoryInfo) {
with(binding.buttonRead) { with(binding.buttonRead) {
if (info?.history != null) { if (info.history != null) {
setText(R.string._continue) setText(R.string._continue)
setIconResource(R.drawable.ic_play) setIconResource(if (info.isIncognitoMode) R.drawable.ic_incognito else R.drawable.ic_play)
} else { } else {
setText(R.string.read) setText(R.string.read)
setIconResource(R.drawable.ic_read) setIconResource(if (info.isIncognitoMode) R.drawable.ic_incognito else R.drawable.ic_play)
} }
} }
val text = when { val text = when {
info == null -> getString(R.string.loading_) !info.isValid -> getString(R.string.loading_)
info.currentChapter >= 0 -> getString(R.string.chapter_d_of_d, info.currentChapter + 1, info.totalChapters) info.currentChapter >= 0 -> getString(R.string.chapter_d_of_d, info.currentChapter + 1, info.totalChapters)
info.totalChapters == 0 -> getString(R.string.no_chapters) info.totalChapters == 0 -> getString(R.string.no_chapters)
else -> resources.getQuantityString(R.plurals.chapters, info.totalChapters, info.totalChapters) else -> resources.getQuantityString(R.plurals.chapters, info.totalChapters, info.totalChapters)

View File

@@ -18,7 +18,6 @@ import coil.request.ImageRequest
import coil.util.CoilUtils import coil.util.CoilUtils
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseFragment import org.koitharu.kotatsu.base.ui.BaseFragment
@@ -27,9 +26,9 @@ import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.base.ui.widgets.ChipsView import org.koitharu.kotatsu.base.ui.widgets.ChipsView
import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.databinding.FragmentDetailsBinding import org.koitharu.kotatsu.databinding.FragmentDetailsBinding
import org.koitharu.kotatsu.details.ui.model.ChapterListItem import org.koitharu.kotatsu.details.ui.model.ChapterListItem
import org.koitharu.kotatsu.details.ui.model.HistoryInfo
import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingItemDecoration import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingItemDecoration
import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter
import org.koitharu.kotatsu.history.domain.PROGRESS_NONE import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
@@ -45,8 +44,20 @@ import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingInfo
import org.koitharu.kotatsu.search.ui.MangaListActivity import org.koitharu.kotatsu.search.ui.MangaListActivity
import org.koitharu.kotatsu.search.ui.SearchActivity import org.koitharu.kotatsu.search.ui.SearchActivity
import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.FileSize
import org.koitharu.kotatsu.utils.ext.* import org.koitharu.kotatsu.utils.ext.computeSize
import org.koitharu.kotatsu.utils.ext.crossfade
import org.koitharu.kotatsu.utils.ext.drawableTop
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.ifNullOrEmpty
import org.koitharu.kotatsu.utils.ext.measureHeight
import org.koitharu.kotatsu.utils.ext.referer
import org.koitharu.kotatsu.utils.ext.resolveDp
import org.koitharu.kotatsu.utils.ext.scaleUpActivityOptionsOf
import org.koitharu.kotatsu.utils.ext.textAndVisible
import org.koitharu.kotatsu.utils.ext.toFileOrNull
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import org.koitharu.kotatsu.utils.image.CoverSizeResolver import org.koitharu.kotatsu.utils.image.CoverSizeResolver
import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class DetailsFragment : class DetailsFragment :
@@ -75,7 +86,7 @@ class DetailsFragment :
binding.chipsTags.onChipClickListener = this binding.chipsTags.onChipClickListener = this
viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated) viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated)
viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged) viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged)
viewModel.readingHistory.observe(viewLifecycleOwner, ::onHistoryChanged) viewModel.historyInfo.observe(viewLifecycleOwner, ::onHistoryChanged)
viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged) viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged)
viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged) viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged)
viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged) viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged)
@@ -123,12 +134,14 @@ class DetailsFragment :
drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_finished) drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_finished)
} }
} }
MangaState.ONGOING -> { MangaState.ONGOING -> {
infoLayout.textViewState.apply { infoLayout.textViewState.apply {
textAndVisible = resources.getString(R.string.state_ongoing) textAndVisible = resources.getString(R.string.state_ongoing)
drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_ongoing) drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_ongoing)
} }
} }
else -> infoLayout.textViewState.isVisible = false else -> infoLayout.textViewState.isVisible = false
} }
if (manga.source == MangaSource.LOCAL) { if (manga.source == MangaSource.LOCAL) {
@@ -178,8 +191,8 @@ class DetailsFragment :
} }
} }
private fun onHistoryChanged(history: MangaHistory?) { private fun onHistoryChanged(history: HistoryInfo) {
binding.progressView.setPercent(history?.percent ?: PROGRESS_NONE, animate = true) binding.progressView.setPercent(history.history?.percent ?: PROGRESS_NONE, animate = true)
} }
private fun onLoadingStateChanged(isLoading: Boolean) { private fun onLoadingStateChanged(isLoading: Boolean) {
@@ -229,6 +242,7 @@ class DetailsFragment :
), ),
) )
} }
R.id.textView_source -> { R.id.textView_source -> {
startActivity( startActivity(
MangaListActivity.newIntent( MangaListActivity.newIntent(
@@ -237,6 +251,7 @@ class DetailsFragment :
), ),
) )
} }
R.id.imageView_cover -> { R.id.imageView_cover -> {
startActivity( startActivity(
ImageActivity.newIntent(v.context, manga.largeCoverUrl.ifNullOrEmpty { manga.coverUrl }), ImageActivity.newIntent(v.context, manga.largeCoverUrl.ifNullOrEmpty { manga.coverUrl }),
@@ -249,7 +264,7 @@ class DetailsFragment :
override fun onLongClick(v: View): Boolean { override fun onLongClick(v: View): Boolean {
when (v.id) { when (v.id) {
R.id.button_read -> { R.id.button_read -> {
if (viewModel.readingHistory.value == null) { if (viewModel.historyInfo.value?.history == null) {
return false return false
} }
val menu = PopupMenu(v.context, v) val menu = PopupMenu(v.context, v)
@@ -271,12 +286,14 @@ class DetailsFragment :
) )
true true
} }
else -> false else -> false
} }
} }
menu.show() menu.show()
return true return true
} }
else -> return false else -> return false
} }
} }

View File

@@ -13,10 +13,18 @@ import androidx.lifecycle.viewModelScope
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import java.io.IOException
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.plus import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@@ -46,6 +54,7 @@ import org.koitharu.kotatsu.utils.asFlowLiveData
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
import java.io.IOException
class DetailsViewModel @AssistedInject constructor( class DetailsViewModel @AssistedInject constructor(
@Assisted intent: MangaIntent, @Assisted intent: MangaIntent,
@@ -91,17 +100,18 @@ class DetailsViewModel @AssistedInject constructor(
val manga = delegate.manga.filterNotNull().asLiveData(viewModelScope.coroutineContext) val manga = delegate.manga.filterNotNull().asLiveData(viewModelScope.coroutineContext)
val favouriteCategories = favourite.asLiveData(viewModelScope.coroutineContext) val favouriteCategories = favourite.asLiveData(viewModelScope.coroutineContext)
val newChaptersCount = newChapters.asLiveData(viewModelScope.coroutineContext) val newChaptersCount = newChapters.asLiveData(viewModelScope.coroutineContext)
@Deprecated("")
val readingHistory = history.asLiveData(viewModelScope.coroutineContext)
val isChaptersReversed = chaptersReversed.asLiveData(viewModelScope.coroutineContext) val isChaptersReversed = chaptersReversed.asLiveData(viewModelScope.coroutineContext)
val historyInfo = combine( val historyInfo: LiveData<HistoryInfo> = combine(
delegate.manga, delegate.manga,
history, history,
) { m, h -> settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled },
HistoryInfo(m, h) ) { m, h, im ->
}.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, null) HistoryInfo(m, h, im)
}.asFlowLiveData(
context = viewModelScope.coroutineContext + Dispatchers.Default,
defaultValue = HistoryInfo(null, null, false),
)
val bookmarks = delegate.manga.flatMapLatest { val bookmarks = delegate.manga.flatMapLatest {
if (it != null) bookmarksRepository.observeBookmarks(it) else flowOf(emptyList()) if (it != null) bookmarksRepository.observeBookmarks(it) else flowOf(emptyList())

View File

@@ -7,8 +7,12 @@ class HistoryInfo(
val totalChapters: Int, val totalChapters: Int,
val currentChapter: Int, val currentChapter: Int,
val history: MangaHistory?, val history: MangaHistory?,
val isIncognitoMode: Boolean,
) { ) {
val isValid: Boolean
get() = totalChapters >= 0
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (javaClass != other?.javaClass) return false if (javaClass != other?.javaClass) return false
@@ -18,6 +22,7 @@ class HistoryInfo(
if (totalChapters != other.totalChapters) return false if (totalChapters != other.totalChapters) return false
if (currentChapter != other.currentChapter) return false if (currentChapter != other.currentChapter) return false
if (history != other.history) return false if (history != other.history) return false
if (isIncognitoMode != other.isIncognitoMode) return false
return true return true
} }
@@ -26,20 +31,21 @@ class HistoryInfo(
var result = totalChapters var result = totalChapters
result = 31 * result + currentChapter result = 31 * result + currentChapter
result = 31 * result + (history?.hashCode() ?: 0) result = 31 * result + (history?.hashCode() ?: 0)
result = 31 * result + isIncognitoMode.hashCode()
return result return result
} }
} }
@Suppress("FunctionName") fun HistoryInfo(manga: Manga?, history: MangaHistory?, isIncognitoMode: Boolean): HistoryInfo {
fun HistoryInfo(manga: Manga?, history: MangaHistory?): HistoryInfo? { val chapters = manga?.chapters
val chapters = manga?.chapters ?: return null
return HistoryInfo( return HistoryInfo(
totalChapters = chapters.size, totalChapters = chapters?.size ?: -1,
currentChapter = if (history != null) { currentChapter = if (history != null && !chapters.isNullOrEmpty()) {
chapters.indexOfFirst { it.id == history.chapterId } chapters.indexOfFirst { it.id == history.chapterId }
} else { } else {
-1 -1
}, },
history = history, history = history,
isIncognitoMode = isIncognitoMode,
) )
} }

View File

@@ -12,6 +12,7 @@ import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
import org.koitharu.kotatsu.core.github.AppUpdateRepository import org.koitharu.kotatsu.core.github.AppUpdateRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.observeAsFlow
import org.koitharu.kotatsu.core.prefs.observeAsLiveData import org.koitharu.kotatsu.core.prefs.observeAsLiveData
import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.history.domain.HistoryRepository
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
@@ -34,9 +35,12 @@ class MainViewModel @Inject constructor(
val onOpenReader = SingleLiveEvent<Manga>() val onOpenReader = SingleLiveEvent<Manga>()
val isResumeEnabled = historyRepository val isResumeEnabled = combine(
.observeHasItems() historyRepository.observeHasItems(),
.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled },
) { hasItems, incognito ->
hasItems && !incognito
}.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false)
val isFeedAvailable = settings.observeAsLiveData( val isFeedAvailable = settings.observeAsLiveData(
context = viewModelScope.coroutineContext + Dispatchers.Default, context = viewModelScope.coroutineContext + Dispatchers.Default,

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.reversed
import android.graphics.PointF import android.graphics.PointF
import android.view.Gravity import android.view.Gravity
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.lifecycle.LifecycleOwner
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.model.ZoomMode import org.koitharu.kotatsu.core.model.ZoomMode
@@ -13,12 +14,13 @@ import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.standard.PageHolder import org.koitharu.kotatsu.reader.ui.pager.standard.PageHolder
class ReversedPageHolder( class ReversedPageHolder(
owner: LifecycleOwner,
binding: ItemPageBinding, binding: ItemPageBinding,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
networkState: NetworkState, networkState: NetworkState,
exceptionResolver: ExceptionResolver, exceptionResolver: ExceptionResolver,
) : PageHolder(binding, loader, settings, networkState, exceptionResolver) { ) : PageHolder(owner, binding, loader, settings, networkState, exceptionResolver) {
init { init {
(binding.textViewNumber.layoutParams as FrameLayout.LayoutParams) (binding.textViewNumber.layoutParams as FrameLayout.LayoutParams)

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui.pager.reversed
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.databinding.ItemPageBinding import org.koitharu.kotatsu.databinding.ItemPageBinding
@@ -10,6 +11,7 @@ import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class ReversedPagesAdapter( class ReversedPagesAdapter(
private val lifecycleOwner: LifecycleOwner,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
networkState: NetworkState, networkState: NetworkState,
@@ -23,6 +25,7 @@ class ReversedPagesAdapter(
networkState: NetworkState, networkState: NetworkState,
exceptionResolver: ExceptionResolver, exceptionResolver: ExceptionResolver,
) = ReversedPageHolder( ) = ReversedPageHolder(
owner = lifecycleOwner,
binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false), binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
loader = loader, loader = loader,
settings = settings, settings = settings,

View File

@@ -39,10 +39,11 @@ class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
pagerAdapter = ReversedPagesAdapter( pagerAdapter = ReversedPagesAdapter(
viewModel.pageLoader, lifecycleOwner = viewLifecycleOwner,
viewModel.readerSettings, loader = viewModel.pageLoader,
networkState, settings = viewModel.readerSettings,
exceptionResolver, networkState = networkState,
exceptionResolver = exceptionResolver,
) )
with(binding.pager) { with(binding.pager) {
adapter = pagerAdapter adapter = pagerAdapter

View File

@@ -5,6 +5,7 @@ import android.graphics.PointF
import android.net.Uri import android.net.Uri
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleOwner
import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@@ -19,6 +20,7 @@ import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.* import org.koitharu.kotatsu.utils.ext.*
open class PageHolder( open class PageHolder(
owner: LifecycleOwner,
binding: ItemPageBinding, binding: ItemPageBinding,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
@@ -28,6 +30,7 @@ open class PageHolder(
View.OnClickListener { View.OnClickListener {
init { init {
binding.ssiv.bindToLifecycle(owner)
binding.ssiv.isEagerLoadingEnabled = !isLowRamDevice(context) binding.ssiv.isEagerLoadingEnabled = !isLowRamDevice(context)
binding.ssiv.addOnImageEventListener(delegate) binding.ssiv.addOnImageEventListener(delegate)
@Suppress("LeakingThis") @Suppress("LeakingThis")

View File

@@ -38,10 +38,11 @@ class PagerReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
pagesAdapter = PagesAdapter( pagesAdapter = PagesAdapter(
viewModel.pageLoader, lifecycleOwner = viewLifecycleOwner,
viewModel.readerSettings, loader = viewModel.pageLoader,
networkState, settings = viewModel.readerSettings,
exceptionResolver, networkState = networkState,
exceptionResolver = exceptionResolver,
) )
with(binding.pager) { with(binding.pager) {
adapter = pagesAdapter adapter = pagesAdapter

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui.pager.standard
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.databinding.ItemPageBinding import org.koitharu.kotatsu.databinding.ItemPageBinding
@@ -10,6 +11,7 @@ import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class PagesAdapter( class PagesAdapter(
private val lifecycleOwner: LifecycleOwner,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
networkState: NetworkState, networkState: NetworkState,
@@ -23,6 +25,7 @@ class PagesAdapter(
networkState: NetworkState, networkState: NetworkState,
exceptionResolver: ExceptionResolver, exceptionResolver: ExceptionResolver,
) = PageHolder( ) = PageHolder(
owner = lifecycleOwner,
binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false), binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
loader = loader, loader = loader,
settings = settings, settings = settings,

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding
@@ -10,6 +11,7 @@ import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class WebtoonAdapter( class WebtoonAdapter(
private val lifecycleOwner: LifecycleOwner,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
networkState: NetworkState, networkState: NetworkState,
@@ -23,6 +25,7 @@ class WebtoonAdapter(
networkState: NetworkState, networkState: NetworkState,
exceptionResolver: ExceptionResolver, exceptionResolver: ExceptionResolver,
) = WebtoonHolder( ) = WebtoonHolder(
owner = lifecycleOwner,
binding = ItemPageWebtoonBinding.inflate( binding = ItemPageWebtoonBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon
import android.net.Uri import android.net.Uri
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleOwner
import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.davemorrissey.labs.subscaleview.decoder.SkiaPooledImageRegionDecoder import com.davemorrissey.labs.subscaleview.decoder.SkiaPooledImageRegionDecoder
@@ -22,6 +23,7 @@ import org.koitharu.kotatsu.utils.ext.setProgressCompat
import org.koitharu.kotatsu.utils.ext.showCompat import org.koitharu.kotatsu.utils.ext.showCompat
class WebtoonHolder( class WebtoonHolder(
owner: LifecycleOwner,
binding: ItemPageWebtoonBinding, binding: ItemPageWebtoonBinding,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
@@ -34,6 +36,7 @@ class WebtoonHolder(
private val goneOnInvisibleListener = GoneOnInvisibleListener(bindingInfo.progressBar) private val goneOnInvisibleListener = GoneOnInvisibleListener(bindingInfo.progressBar)
init { init {
binding.ssiv.bindToLifecycle(owner)
binding.ssiv.regionDecoderFactory = SkiaPooledImageRegionDecoder.Factory() binding.ssiv.regionDecoderFactory = SkiaPooledImageRegionDecoder.Factory()
binding.ssiv.addOnImageEventListener(delegate) binding.ssiv.addOnImageEventListener(delegate)
bindingInfo.buttonRetry.setOnClickListener(this) bindingInfo.buttonRetry.setOnClickListener(this)

View File

@@ -35,10 +35,11 @@ class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
webtoonAdapter = WebtoonAdapter( webtoonAdapter = WebtoonAdapter(
viewModel.pageLoader, lifecycleOwner = viewLifecycleOwner,
viewModel.readerSettings, loader = viewModel.pageLoader,
networkState, settings = viewModel.readerSettings,
exceptionResolver, networkState = networkState,
exceptionResolver = exceptionResolver,
) )
with(binding.recyclerView) { with(binding.recyclerView) {
setHasFixedSize(true) setHasFixedSize(true)

View File

@@ -390,4 +390,5 @@
<string name="reader_control_ltr">Ergonomische Leserkontrolle</string> <string name="reader_control_ltr">Ergonomische Leserkontrolle</string>
<string name="reader_control_ltr_summary">Tippe auf den rechten Rand oder drücke die rechte Taste, um immer zur nächsten Seite zu wechseln</string> <string name="reader_control_ltr_summary">Tippe auf den rechten Rand oder drücke die rechte Taste, um immer zur nächsten Seite zu wechseln</string>
<string name="reader_slider">Seitenwechsel-Schieberegler anzeigen</string> <string name="reader_slider">Seitenwechsel-Schieberegler anzeigen</string>
<string name="source_disabled">Quelle deaktiviert</string>
</resources> </resources>

View File

@@ -396,4 +396,5 @@
<string name="network_unavailable">La red no está disponible</string> <string name="network_unavailable">La red no está disponible</string>
<string name="compact">Compacta</string> <string name="compact">Compacta</string>
<string name="network_unavailable_hint">Enciende la Wi-Fi o la red móvil para leer los mangas en línea</string> <string name="network_unavailable_hint">Enciende la Wi-Fi o la red móvil para leer los mangas en línea</string>
<string name="source_disabled">Fuente desactivada</string>
</resources> </resources>

View File

@@ -395,4 +395,5 @@
<string name="compact">Compact</string> <string name="compact">Compact</string>
<string name="server_error">Erreur côté serveur (%1$d). Veuillez réessayer plus tard</string> <string name="server_error">Erreur côté serveur (%1$d). Veuillez réessayer plus tard</string>
<string name="clear_new_chapters_counters">Effacer aussi les informations sur les nouveaux chapitres</string> <string name="clear_new_chapters_counters">Effacer aussi les informations sur les nouveaux chapitres</string>
<string name="source_disabled">Source désactivée</string>
</resources> </resources>

View File

@@ -320,4 +320,6 @@
<string name="invalid_domain_message">Dominio non valido</string> <string name="invalid_domain_message">Dominio non valido</string>
<string name="select_range">Seleziona l\'intervallo</string> <string name="select_range">Seleziona l\'intervallo</string>
<string name="not_found_404">Contenuto non trovato o rimosso</string> <string name="not_found_404">Contenuto non trovato o rimosso</string>
<string name="compact">Compatto</string>
<string name="source_disabled">Fonte disabilitata</string>
</resources> </resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="com_samsung_android_icon_container_has_icon_container">false</bool>
</resources>

View File

@@ -31,7 +31,7 @@
<string name="clear_cookies">清除cookies</string> <string name="clear_cookies">清除cookies</string>
<string name="chapters_checking_progress">检查新的章节: %1$d/%2$d</string> <string name="chapters_checking_progress">检查新的章节: %1$d/%2$d</string>
<string name="error_empty_name">你必须输入一个名称</string> <string name="error_empty_name">你必须输入一个名称</string>
<string name="new_sources_text">新的漫画</string> <string name="new_sources_text">新的漫画源可用</string>
<string name="suggestions_summary">根据你的喜好推荐漫画</string> <string name="suggestions_summary">根据你的喜好推荐漫画</string>
<string name="suggestions_info">所有的数据都在这个设备上进行本地分析. 您的个人数据不会被转移到任何服务机构</string> <string name="suggestions_info">所有的数据都在这个设备上进行本地分析. 您的个人数据不会被转移到任何服务机构</string>
<string name="never">从不</string> <string name="never">从不</string>
@@ -48,7 +48,7 @@
<string name="detailed_list">详细列表</string> <string name="detailed_list">详细列表</string>
<string name="grid">网格</string> <string name="grid">网格</string>
<string name="list_mode">列表模式</string> <string name="list_mode">列表模式</string>
<string name="remote_sources">远程</string> <string name="remote_sources">远程源</string>
<string name="loading_">加载中…</string> <string name="loading_">加载中…</string>
<string name="computing_">计算中…</string> <string name="computing_">计算中…</string>
<string name="chapter_d_of_d">%1$d/%2$d章节</string> <string name="chapter_d_of_d">%1$d/%2$d章节</string>
@@ -230,7 +230,7 @@
<string name="about_feedback_4pda">关于4PDA主题</string> <string name="about_feedback_4pda">关于4PDA主题</string>
<string name="auth_complete">授权</string> <string name="auth_complete">授权</string>
<string name="auth_not_supported_by">不支持在%s上登录</string> <string name="auth_not_supported_by">不支持在%s上登录</string>
<string name="text_clear_cookies_prompt">你将被从所有来源中注销</string> <string name="text_clear_cookies_prompt">你将退出登录所有来源</string>
<string name="genres">类型</string> <string name="genres">类型</string>
<string name="state_ongoing">连载中</string> <string name="state_ongoing">连载中</string>
<string name="state_finished">已完结</string> <string name="state_finished">已完结</string>
@@ -395,4 +395,5 @@
<string name="clear_new_chapters_counters">同样清除新章节信息</string> <string name="clear_new_chapters_counters">同样清除新章节信息</string>
<string name="server_error">服务器端错误 (%1$d)。请稍后再试</string> <string name="server_error">服务器端错误 (%1$d)。请稍后再试</string>
<string name="compact">紧凑</string> <string name="compact">紧凑</string>
<string name="source_disabled">已禁用图源</string>
</resources> </resources>

View File

@@ -3,4 +3,5 @@
<bool name="is_tablet">false</bool> <bool name="is_tablet">false</bool>
<bool name="light_status_bar">true</bool> <bool name="light_status_bar">true</bool>
<bool name="light_navigation_bar">false</bool> <bool name="light_navigation_bar">false</bool>
</resources> <bool name="com_samsung_android_icon_container_has_icon_container">true</bool>
</resources>