From b955d3177044a6f80c464423397ece1844383f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Blagoje=20Nikoli=C4=87?= Date: Mon, 14 Nov 2022 23:48:33 +0100 Subject: [PATCH 01/88] Translated using Weblate (Serbian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 4.2% (17 of 398 strings) Translated using Weblate (Serbian) Currently translated at 100.0% (8 of 8 strings) Added translation using Weblate (Serbian) Translated using Weblate (Serbian) Currently translated at 12.5% (1 of 8 strings) Added translation using Weblate (Serbian) Co-authored-by: Blagoje Nikolić Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/sr/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/ Translation: Kotatsu/Strings Translation: Kotatsu/plurals --- app/src/main/res/values-sr/plurals.xml | 43 ++++++++++++++++++++++++++ app/src/main/res/values-sr/strings.xml | 15 +++++++++ 2 files changed, 58 insertions(+) create mode 100644 app/src/main/res/values-sr/plurals.xml create mode 100644 app/src/main/res/values-sr/strings.xml diff --git a/app/src/main/res/values-sr/plurals.xml b/app/src/main/res/values-sr/plurals.xml new file mode 100644 index 000000000..bedee0fcd --- /dev/null +++ b/app/src/main/res/values-sr/plurals.xml @@ -0,0 +1,43 @@ + + + + Тотално %1$d странa + Тотално %1$d странице + Тотално %1$d странице + + + %1$d ставке + %1$d ставки + %1$d ставка + + + %1$d поглавља од %2$d + %1$d поглавља од %2$d + %1$d поглавља од %2$d + + + пре %1$d минута + пре %1$d минута + пре %1$d минута + + + пре %1$d сата + пре %1$d сата + пре %1$d сата + + + пре %1$d дана + пре %1$d дана + пре %1$d дана + + + %1$d нова поглавља + %1$d нових поглавља + %1$d нових поглавља + + + %1$d поглављe + %1$d поглавља + %1$d поглавља + + \ No newline at end of file diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml new file mode 100644 index 000000000..85ea48c5d --- /dev/null +++ b/app/src/main/res/values-sr/strings.xml @@ -0,0 +1,15 @@ + + + Локално складиште + Затвори мени + Грешка се појавила + Отвори мени + Фаворити + Историја + Неуспешно повезивање са интернетом + Детаљи + Поглавља + Листа + Детаљна листа + Табла + \ No newline at end of file From d224cd99bbf59cf58e9c411a816cef01fd5e2aae Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 21 Nov 2022 09:09:58 +0200 Subject: [PATCH 02/88] Update parsers --- app/build.gradle | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 71d5901ea..e20e6641c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 33 - versionCode 503 - versionName '4.0.3' + versionCode 504 + versionName '4.0.4' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -83,7 +83,7 @@ afterEvaluate { } } dependencies { - implementation('com.github.KotatsuApp:kotatsu-parsers:bf8a1f3db2') { + implementation('com.github.KotatsuApp:kotatsu-parsers:1e49d4095b') { exclude group: 'org.json', module: 'json' } @@ -137,10 +137,10 @@ dependencies { testImplementation 'org.json:json:20220924' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4' - androidTestImplementation 'androidx.test:runner:1.4.0' - androidTestImplementation 'androidx.test:rules:1.4.0' - androidTestImplementation 'androidx.test:core-ktx:1.4.0' - androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3' + androidTestImplementation 'androidx.test:runner:1.5.1' + androidTestImplementation 'androidx.test:rules:1.5.0' + androidTestImplementation 'androidx.test:core-ktx:1.5.0' + androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.4' androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4' From f320f22863aaf28b86134ab9a136cff8093434e7 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 28 Nov 2022 19:40:01 +0200 Subject: [PATCH 03/88] Improve network state observer --- .../koitharu/kotatsu/core/os/NetworkState.kt | 54 +++++++++++++ .../kotatsu/core/os/NetworkStateObserver.kt | 78 ------------------- .../kotatsu/reader/ui/pager/BasePageHolder.kt | 6 +- .../reader/ui/pager/BaseReaderAdapter.kt | 6 +- .../reader/ui/pager/PageHolderDelegate.kt | 4 +- .../ui/pager/reversed/ReversedPageHolder.kt | 4 +- .../ui/pager/reversed/ReversedPagesAdapter.kt | 6 +- .../pager/reversed/ReversedReaderFragment.kt | 6 +- .../reader/ui/pager/standard/PageHolder.kt | 4 +- .../ui/pager/standard/PagerReaderFragment.kt | 6 +- .../reader/ui/pager/standard/PagesAdapter.kt | 8 +- .../reader/ui/pager/webtoon/WebtoonAdapter.kt | 6 +- .../reader/ui/pager/webtoon/WebtoonHolder.kt | 4 +- .../ui/pager/webtoon/WebtoonReaderFragment.kt | 6 +- .../kotatsu/shelf/ui/ShelfViewModel.kt | 6 +- .../kotatsu/utils/MediatorStateFlow.kt | 42 ++++++++++ 16 files changed, 132 insertions(+), 114 deletions(-) create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/os/NetworkState.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/core/os/NetworkStateObserver.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/MediatorStateFlow.kt diff --git a/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkState.kt b/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkState.kt new file mode 100644 index 000000000..49d1704d6 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkState.kt @@ -0,0 +1,54 @@ +package org.koitharu.kotatsu.core.os + +import android.content.Context +import android.net.ConnectivityManager.NetworkCallback +import android.net.Network +import android.net.NetworkRequest +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.first +import org.koitharu.kotatsu.utils.MediatorStateFlow +import org.koitharu.kotatsu.utils.ext.connectivityManager +import org.koitharu.kotatsu.utils.ext.isNetworkAvailable +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class NetworkState @Inject constructor( + @ApplicationContext context: Context, +) : MediatorStateFlow() { + + private val connectivityManager = context.connectivityManager + private val callback = NetworkCallbackImpl() + + override val initialValue: Boolean + get() = connectivityManager.isNetworkAvailable + + override fun onActive() { + val request = NetworkRequest.Builder().build() + connectivityManager.registerNetworkCallback(request, callback) + } + + override fun onInactive() { + connectivityManager.unregisterNetworkCallback(callback) + } + + suspend fun awaitForConnection() { + if (value) { + return + } + first { it } + } + + private inner class NetworkCallbackImpl : NetworkCallback() { + + override fun onAvailable(network: Network) = update() + + override fun onLost(network: Network) = update() + + override fun onUnavailable() = update() + + private fun update() { + publishValue(connectivityManager.isNetworkAvailable) + } + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkStateObserver.kt b/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkStateObserver.kt deleted file mode 100644 index 8450028e9..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkStateObserver.kt +++ /dev/null @@ -1,78 +0,0 @@ -package org.koitharu.kotatsu.core.os - -import android.content.Context -import android.net.ConnectivityManager.NetworkCallback -import android.net.Network -import android.net.NetworkRequest -import dagger.hilt.android.qualifiers.ApplicationContext -import kotlinx.coroutines.channels.ProducerScope -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.channels.onSuccess -import kotlinx.coroutines.channels.trySendBlocking -import kotlinx.coroutines.flow.FlowCollector -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.first -import org.koitharu.kotatsu.utils.ext.connectivityManager -import org.koitharu.kotatsu.utils.ext.isNetworkAvailable -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class NetworkStateObserver @Inject constructor( - @ApplicationContext context: Context, -) : StateFlow { - - private val connectivityManager = context.connectivityManager - - override val replayCache: List - get() = listOf(value) - - override val value: Boolean - get() = connectivityManager.isNetworkAvailable - - override suspend fun collect(collector: FlowCollector): Nothing { - collector.emit(value) - while (true) { - observeImpl().collect(collector) - } - } - - suspend fun awaitForConnection(): Unit { - if (value) { - return - } - first { it } - } - - private fun observeImpl() = callbackFlow { - val request = NetworkRequest.Builder().build() - val callback = FlowNetworkCallback(this) - connectivityManager.registerNetworkCallback(request, callback) - awaitClose { - connectivityManager.unregisterNetworkCallback(callback) - } - } - - private inner class FlowNetworkCallback( - private val producerScope: ProducerScope, - ) : NetworkCallback() { - - private var prevValue = value - - override fun onAvailable(network: Network) = update() - - override fun onLost(network: Network) = update() - - override fun onUnavailable() = update() - - private fun update() { - val newValue = connectivityManager.isNetworkAvailable - if (newValue != prevValue) { - producerScope.trySendBlocking(newValue).onSuccess { - prevValue = newValue - } - } - } - } -} diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt index 03380ff51..a5f032ff6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt @@ -5,7 +5,7 @@ import androidx.annotation.CallSuper import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.LayoutPageInfoBinding import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings @@ -14,12 +14,12 @@ abstract class BasePageHolder( protected val binding: B, loader: PageLoader, settings: ReaderSettings, - networkStateObserver: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ) : RecyclerView.ViewHolder(binding.root), PageHolderDelegate.Callback { @Suppress("LeakingThis") - protected val delegate = PageHolderDelegate(loader, settings, this, networkStateObserver, exceptionResolver) + protected val delegate = PageHolderDelegate(loader, settings, this, networkState, exceptionResolver) protected val bindingInfo = LayoutPageInfoBinding.bind(binding.root) val context: Context diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BaseReaderAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BaseReaderAdapter.kt index 1a914b41e..3144ef655 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BaseReaderAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/BaseReaderAdapter.kt @@ -5,7 +5,7 @@ import androidx.recyclerview.widget.AsyncListDiffer import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings import org.koitharu.kotatsu.utils.ext.resetTransformations @@ -16,7 +16,7 @@ import kotlin.coroutines.suspendCoroutine abstract class BaseReaderAdapter>( private val loader: PageLoader, private val readerSettings: ReaderSettings, - private val networkState: NetworkStateObserver, + private val networkState: NetworkState, private val exceptionResolver: ExceptionResolver, ) : RecyclerView.Adapter() { @@ -70,7 +70,7 @@ abstract class BaseReaderAdapter>( parent: ViewGroup, loader: PageLoader, settings: ReaderSettings, - networkState: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ): H diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt index 27431e75b..51db77550 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.plus import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings @@ -28,7 +28,7 @@ class PageHolderDelegate( private val loader: PageLoader, private val readerSettings: ReaderSettings, private val callback: Callback, - private val networkState: NetworkStateObserver, + private val networkState: NetworkState, private val exceptionResolver: ExceptionResolver, ) : DefaultOnImageEventListener, Observer { diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt index 8e686ae81..f907de4a9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt @@ -6,7 +6,7 @@ import android.widget.FrameLayout import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.model.ZoomMode -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.ItemPageBinding import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings @@ -16,7 +16,7 @@ class ReversedPageHolder( binding: ItemPageBinding, loader: PageLoader, settings: ReaderSettings, - networkState: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ) : PageHolder(binding, loader, settings, networkState, exceptionResolver) { diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt index d68f39334..4c6eeb28e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt @@ -3,7 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.reversed import android.view.LayoutInflater import android.view.ViewGroup import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.ItemPageBinding import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings @@ -12,7 +12,7 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter class ReversedPagesAdapter( loader: PageLoader, settings: ReaderSettings, - networkState: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ) : BaseReaderAdapter(loader, settings, networkState, exceptionResolver) { @@ -20,7 +20,7 @@ class ReversedPagesAdapter( parent: ViewGroup, loader: PageLoader, settings: ReaderSettings, - networkState: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ) = ReversedPageHolder( binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false), diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt index df4a739ac..0302134dd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt @@ -8,7 +8,7 @@ import android.view.ViewGroup import androidx.core.view.children import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.async -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding import org.koitharu.kotatsu.reader.ui.ReaderState import org.koitharu.kotatsu.reader.ui.pager.BaseReader @@ -26,7 +26,7 @@ import kotlin.math.absoluteValue class ReversedReaderFragment : BaseReader() { @Inject - lateinit var networkStateObserver: NetworkStateObserver + lateinit var networkState: NetworkState private var pagerAdapter: ReversedPagesAdapter? = null @@ -41,7 +41,7 @@ class ReversedReaderFragment : BaseReader() { pagerAdapter = ReversedPagesAdapter( viewModel.pageLoader, viewModel.readerSettings, - networkStateObserver, + networkState, exceptionResolver, ) with(binding.pager) { diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt index b56163f54..c2501e499 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt @@ -10,7 +10,7 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.model.ZoomMode -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.ItemPageBinding import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings @@ -22,7 +22,7 @@ open class PageHolder( binding: ItemPageBinding, loader: PageLoader, settings: ReaderSettings, - networkState: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ) : BasePageHolder(binding, loader, settings, networkState, exceptionResolver), View.OnClickListener { diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt index 889f5189f..07633f5e2 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt @@ -8,7 +8,7 @@ import android.view.ViewGroup import androidx.core.view.children import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.async -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding import org.koitharu.kotatsu.reader.ui.ReaderState import org.koitharu.kotatsu.reader.ui.pager.BaseReader @@ -25,7 +25,7 @@ import kotlin.math.absoluteValue class PagerReaderFragment : BaseReader() { @Inject - lateinit var networkStateObserver: NetworkStateObserver + lateinit var networkState: NetworkState private var pagesAdapter: PagesAdapter? = null @@ -40,7 +40,7 @@ class PagerReaderFragment : BaseReader() { pagesAdapter = PagesAdapter( viewModel.pageLoader, viewModel.readerSettings, - networkStateObserver, + networkState, exceptionResolver, ) with(binding.pager) { diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt index 293ca6273..a36057bf7 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt @@ -3,7 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.standard import android.view.LayoutInflater import android.view.ViewGroup import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.ItemPageBinding import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings @@ -12,15 +12,15 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter class PagesAdapter( loader: PageLoader, settings: ReaderSettings, - networkStateObserver: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, -) : BaseReaderAdapter(loader, settings, networkStateObserver, exceptionResolver) { +) : BaseReaderAdapter(loader, settings, networkState, exceptionResolver) { override fun onCreateViewHolder( parent: ViewGroup, loader: PageLoader, settings: ReaderSettings, - networkState: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ) = PageHolder( binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false), diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt index 6d92ff321..e47711f49 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt @@ -3,7 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon import android.view.LayoutInflater import android.view.ViewGroup import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings @@ -12,7 +12,7 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter class WebtoonAdapter( loader: PageLoader, settings: ReaderSettings, - networkState: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ) : BaseReaderAdapter(loader, settings, networkState, exceptionResolver) { @@ -20,7 +20,7 @@ class WebtoonAdapter( parent: ViewGroup, loader: PageLoader, settings: ReaderSettings, - networkState: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ) = WebtoonHolder( binding = ItemPageWebtoonBinding.inflate( diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt index 086081097..81ce8fb80 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt @@ -8,7 +8,7 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.decoder.SkiaPooledImageRegionDecoder import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings @@ -25,7 +25,7 @@ class WebtoonHolder( binding: ItemPageWebtoonBinding, loader: PageLoader, settings: ReaderSettings, - networkState: NetworkStateObserver, + networkState: NetworkState, exceptionResolver: ExceptionResolver, ) : BasePageHolder(binding, loader, settings, networkState, exceptionResolver), View.OnClickListener { diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt index 7fe5fb1f4..1142fedcb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt @@ -7,7 +7,7 @@ import android.view.ViewGroup import android.view.animation.AccelerateDecelerateInterpolator import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.async -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.FragmentReaderWebtoonBinding import org.koitharu.kotatsu.reader.ui.ReaderState import org.koitharu.kotatsu.reader.ui.pager.BaseReader @@ -22,7 +22,7 @@ import javax.inject.Inject class WebtoonReaderFragment : BaseReader() { @Inject - lateinit var networkStateObserver: NetworkStateObserver + lateinit var networkState: NetworkState private val scrollInterpolator = AccelerateDecelerateInterpolator() private var webtoonAdapter: WebtoonAdapter? = null @@ -37,7 +37,7 @@ class WebtoonReaderFragment : BaseReader() { webtoonAdapter = WebtoonAdapter( viewModel.pageLoader, viewModel.readerSettings, - networkStateObserver, + networkState, exceptionResolver, ) with(binding.recyclerView) { diff --git a/app/src/main/java/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt index a56d848ea..78cb8050a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt @@ -12,7 +12,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseViewModel import org.koitharu.kotatsu.base.ui.util.ReversibleAction import org.koitharu.kotatsu.core.model.FavouriteCategory -import org.koitharu.kotatsu.core.os.NetworkStateObserver +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.prefs.observeAsFlow @@ -46,14 +46,14 @@ class ShelfViewModel @Inject constructor( private val favouritesRepository: FavouritesRepository, private val trackingRepository: TrackingRepository, private val settings: AppSettings, - networkStateObserver: NetworkStateObserver, + networkState: NetworkState, ) : BaseViewModel(), ListExtraProvider { val onActionDone = SingleLiveEvent() val content: LiveData> = combine( settings.observeAsFlow(AppSettings.KEY_SHELF_SECTIONS) { shelfSections }, - networkStateObserver, + networkState, repository.observeShelfContent(), ) { sections, isConnected, content -> mapList(content, sections, isConnected) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/MediatorStateFlow.kt b/app/src/main/java/org/koitharu/kotatsu/utils/MediatorStateFlow.kt new file mode 100644 index 000000000..618d098b0 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/MediatorStateFlow.kt @@ -0,0 +1,42 @@ +package org.koitharu.kotatsu.utils + +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import java.util.concurrent.atomic.AtomicInteger + +abstract class MediatorStateFlow : StateFlow { + + @Suppress("LeakingThis") + private val delegate = MutableStateFlow(initialValue) + private val collectors = AtomicInteger(0) + + protected abstract val initialValue: T + + final override val replayCache: List + get() = delegate.replayCache + + final override val value: T + get() = delegate.value + + final override suspend fun collect(collector: FlowCollector): Nothing { + try { + if (collectors.getAndIncrement() == 0) { + onActive() + } + delegate.collect(collector) + } finally { + if (collectors.decrementAndGet() == 0) { + onInactive() + } + } + } + + protected fun publishValue(v: T) { + delegate.value = v + } + + abstract fun onActive() + + abstract fun onInactive() +} From 0c4b7b0586f9e243a6c6b317860047e642b3588c Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 28 Nov 2022 19:59:32 +0200 Subject: [PATCH 04/88] Replace ArrayMap with an AndroidX implementation --- .../base/ui/list/SectionedSelectionController.kt | 4 ++-- .../core/exceptions/resolve/ExceptionResolver.kt | 2 +- .../koitharu/kotatsu/sync/domain/SyncController.kt | 14 +++++++++----- .../org/koitharu/kotatsu/utils/CompositeMutex.kt | 12 ++++++------ 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/SectionedSelectionController.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/SectionedSelectionController.kt index 3f7abea0b..d210c6991 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/SectionedSelectionController.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/SectionedSelectionController.kt @@ -2,20 +2,20 @@ package org.koitharu.kotatsu.base.ui.list import android.app.Activity import android.os.Bundle -import android.util.ArrayMap import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode +import androidx.collection.ArrayMap import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView import androidx.savedstate.SavedStateRegistry import androidx.savedstate.SavedStateRegistryOwner -import kotlin.coroutines.EmptyCoroutineContext import kotlinx.coroutines.Dispatchers import org.koitharu.kotatsu.base.ui.list.decor.AbstractSelectionItemDecoration +import kotlin.coroutines.EmptyCoroutineContext private const val PROVIDER_NAME = "selection_decoration_sectioned" diff --git a/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt b/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt index 8ae3565e5..b7147aadd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt @@ -1,9 +1,9 @@ package org.koitharu.kotatsu.core.exceptions.resolve -import android.util.ArrayMap import androidx.activity.result.ActivityResultCallback import androidx.activity.result.ActivityResultLauncher import androidx.annotation.StringRes +import androidx.collection.ArrayMap import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import kotlinx.coroutines.suspendCancellableCoroutine diff --git a/app/src/main/java/org/koitharu/kotatsu/sync/domain/SyncController.kt b/app/src/main/java/org/koitharu/kotatsu/sync/domain/SyncController.kt index 9dff00923..c0c00aeab 100644 --- a/app/src/main/java/org/koitharu/kotatsu/sync/domain/SyncController.kt +++ b/app/src/main/java/org/koitharu/kotatsu/sync/domain/SyncController.kt @@ -5,16 +5,17 @@ import android.accounts.AccountManager import android.content.ContentResolver import android.content.Context import android.os.Bundle -import android.util.ArrayMap +import androidx.collection.ArrayMap import androidx.room.InvalidationTracker import androidx.room.withTransaction import dagger.hilt.android.qualifiers.ApplicationContext -import java.util.concurrent.TimeUnit -import javax.inject.Inject -import javax.inject.Singleton -import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.db.MangaDatabase @@ -22,6 +23,9 @@ import org.koitharu.kotatsu.core.db.TABLE_FAVOURITES import org.koitharu.kotatsu.core.db.TABLE_FAVOURITE_CATEGORIES import org.koitharu.kotatsu.core.db.TABLE_HISTORY import org.koitharu.kotatsu.utils.ext.processLifecycleScope +import java.util.concurrent.TimeUnit +import javax.inject.Inject +import javax.inject.Singleton @Singleton class SyncController @Inject constructor( diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/CompositeMutex.kt b/app/src/main/java/org/koitharu/kotatsu/utils/CompositeMutex.kt index 5f4f12fda..859e7e391 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/CompositeMutex.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/CompositeMutex.kt @@ -1,14 +1,14 @@ package org.koitharu.kotatsu.utils -import android.util.ArrayMap -import java.util.* -import kotlin.coroutines.coroutineContext -import kotlin.coroutines.resume +import androidx.collection.ArrayMap import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.isActive import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import java.util.LinkedList +import kotlin.coroutines.coroutineContext +import kotlin.coroutines.resume class CompositeMutex : Set { @@ -27,7 +27,7 @@ class CompositeMutex : Set { } override fun isEmpty(): Boolean { - return data.isEmpty() + return data.isEmpty } override fun iterator(): Iterator { @@ -59,7 +59,7 @@ class CompositeMutex : Set { private suspend fun waitForRemoval(element: T) { val list = data[element] ?: return - suspendCancellableCoroutine { continuation -> + suspendCancellableCoroutine { continuation -> list.add(continuation) continuation.invokeOnCancellation { list.remove(continuation) From d1e7e7a2a6e518e5f0779c981d896574d42ed3f4 Mon Sep 17 00:00:00 2001 From: john d Date: Sat, 26 Nov 2022 04:47:53 +0100 Subject: [PATCH 05/88] Translated using Weblate (Greek) Currently translated at 20.8% (83 of 398 strings) Translated using Weblate (Greek) Currently translated at 2.2% (9 of 398 strings) Translated using Weblate (Greek) Currently translated at 87.5% (7 of 8 strings) Added translation using Weblate (Greek) Added translation using Weblate (Greek) Co-authored-by: john d Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/el/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/el/ Translation: Kotatsu/Strings Translation: Kotatsu/plurals --- app/src/main/res/values-el/plurals.xml | 35 +++++++++++ app/src/main/res/values-el/strings.xml | 81 ++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 app/src/main/res/values-el/plurals.xml create mode 100644 app/src/main/res/values-el/strings.xml diff --git a/app/src/main/res/values-el/plurals.xml b/app/src/main/res/values-el/plurals.xml new file mode 100644 index 000000000..497f12234 --- /dev/null +++ b/app/src/main/res/values-el/plurals.xml @@ -0,0 +1,35 @@ + + + + %1$d μέρα πριν + %1$d μέρες πριν + + + %1$dστοιχείο + %1$dστοιχεία + + + %1$dνέο κεφάλαιο + %1$dνέα κεφάλαια + + + %1$dκεφάλαιο%2$d + %1$dκεφάλαια%2$d + + + %1$dώρα πριν + %1$dώρες πριν + + + %1$dκεφάλαιο + %1$dκεφάλαια + + + Σύνολο%1$dσελίδα + Σύνολο%1$dσελίδες + + + %1$dλεπτό πριν + %1$d λεπτά πριν + + \ No newline at end of file diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml new file mode 100644 index 000000000..43914a6a4 --- /dev/null +++ b/app/src/main/res/values-el/strings.xml @@ -0,0 +1,81 @@ + + + Εσωτερικός χώρος + Κλείσιμο μενού + Άνοιγμα μενού + Αγαπημένα + Ιστορικό + Προέκυψε σφάλμα + Επανάληψη + Πλέγμα + Εμφάνιση ως λίστα + Ρυθμίσεις + Απομακρυσμένες πηγές + Επεξεργασία… + Κλείσιμο + Εκκαθάριση ιστορικού + Δεν βρέθηκε τίποτα + Κενό ιστορικό + Διάβασε + Προσθήκη στα αγαπημένα + Νέα κατηγορία + Αποθήκευση + Κοινοποιήση + Δημιουργία συντόμευσης… + Κοινοποίηση %s + Αναζήτηση + Αναζήτηση μάνγκα + Λήψη… + Κατεβασμένο + Λήψεις + Ενημερωμένο + Νεότερο + Βαθμολογία + Φίλτρο + Σκοτεινό + Όπως στο σύστημα + Εκκαθάριση + Να διαγράψετε μόνιμα όλο το ιστορικό ανάγνωσης; + Διαγραφή + Αποθήκευση σελίδας + Αποθηκευμένα + Κοινή χρήση εικόνας + Εισαγωγή + Διαγραφή + Επιλέξτε ένα αρχείο ZIP ή CBZ. + Χωρίς περιγραφή + Ιστορικό και μνήμη cache + Εκκαθάριση μνήμης cache της σελίδας + Προσωρινή Μνήμη + B|kB|MB|GB|TB + Τυπικό + Μάνχγουα + Αναζήτηση στο %s + Διαγραφή μάνγκα + Μόνιμη διαγραφή του \"%s\" από τη συσκευή; + Ρυθμίσεις λειτουργίας ανάγνωσης + Αλλαγή σελίδων + Αδυναμία σύνδεσης στο ίντερνετ + Κεφάλαια + Πληροφορίες + Λίστα + Λεπτομερής λίστα + Φόρτωση… + Κεφάλαιο%1$d από %2$d + Δεν υπάρχουν αγαπημένα + Προσθήκη + Εισαγωγή ονόματος κατηγορίας + Επεξεργασία… + Όνομα + Δημοφιλή + Τρόπος Ταξινόμησης + Το \"%s\" αφαιρέθηκε από το ιστορικό + Θέμα + Φωτεινό + Σελίδες + Περιμένετε να ολοκληρωθεί η φόρτωση… + Το \"%s\" διαγράφηκε από τον τοπικό χώρο αποθήκευσης + Αυτή η λειτουργία δεν υποστηρίζεται + Λειτουργία ανάγνωσης + Μέγεθος πλέγματος + \ No newline at end of file From 7bb7736f180be1de5175f7f4640898b44eb95fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C6=B0=E1=BB=9Dng=20B=C3=A1?= Date: Sat, 26 Nov 2022 04:47:54 +0100 Subject: [PATCH 06/88] Translated using Weblate (Vietnamese) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 87.5% (7 of 8 strings) Co-authored-by: Cường Bá Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/vi/ Translation: Kotatsu/plurals --- app/src/main/res/values-vi/plurals.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-vi/plurals.xml b/app/src/main/res/values-vi/plurals.xml index 79cfd3ceb..ba58d3cb8 100644 --- a/app/src/main/res/values-vi/plurals.xml +++ b/app/src/main/res/values-vi/plurals.xml @@ -15,4 +15,10 @@ %1$d ngày trước + + %1$d chương từ %2$d + + + Tổng %1$d trang + \ No newline at end of file From 1ddcaed4838b3fa34406e232b982096d956e2c97 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 30 Nov 2022 08:26:56 +0200 Subject: [PATCH 07/88] Update parsers --- app/build.gradle | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e20e6641c..5f2583e1e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 33 - versionCode 504 - versionName '4.0.4' + versionCode 505 + versionName '4.0.5' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -83,7 +83,7 @@ afterEvaluate { } } dependencies { - implementation('com.github.KotatsuApp:kotatsu-parsers:1e49d4095b') { + implementation('com.github.KotatsuApp:kotatsu-parsers:2ab03cb668') { exclude group: 'org.json', module: 'json' } @@ -118,8 +118,8 @@ dependencies { implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl:4.3.2' implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl-viewbinding:4.3.2' - implementation "com.google.dagger:hilt-android:2.44" - kapt "com.google.dagger:hilt-compiler:2.44" + implementation 'com.google.dagger:hilt-android:2.44.2' + kapt 'com.google.dagger:hilt-compiler:2.44.2' implementation 'androidx.hilt:hilt-work:1.0.0' kapt 'androidx.hilt:hilt-compiler:1.0.0' @@ -128,10 +128,10 @@ dependencies { implementation 'com.github.KotatsuApp:subsampling-scale-image-view:f8a38b08fe' implementation 'com.github.solkin:disk-lru-cache:1.4' - implementation 'ch.acra:acra-http:5.9.6' - implementation 'ch.acra:acra-dialog:5.9.6' + implementation 'ch.acra:acra-http:5.9.7' + implementation 'ch.acra:acra-dialog:5.9.7' - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10' testImplementation 'junit:junit:4.13.2' testImplementation 'org.json:json:20220924' @@ -147,6 +147,6 @@ dependencies { androidTestImplementation 'androidx.room:room-testing:2.4.3' androidTestImplementation 'com.squareup.moshi:moshi-kotlin:1.14.0' - androidTestImplementation 'com.google.dagger:hilt-android-testing:2.44' - kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.44' + androidTestImplementation 'com.google.dagger:hilt-android-testing:2.44.2' + kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.44.2' } From f469369b1486aa69659b303f08bc1a13171591ff Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 30 Nov 2022 09:08:40 +0200 Subject: [PATCH 08/88] Fix manga search suggestions #268 --- .../main/java/org/koitharu/kotatsu/core/db/dao/MangaDao.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/dao/MangaDao.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/dao/MangaDao.kt index ee8255dfc..efca0e36b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/db/dao/MangaDao.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/dao/MangaDao.kt @@ -14,11 +14,11 @@ abstract class MangaDao { abstract suspend fun find(id: Long): MangaWithTags? @Transaction - @Query("SELECT * FROM manga WHERE title LIKE :query OR alt_title LIKE :query LIMIT :limit") + @Query("SELECT * FROM manga WHERE (title LIKE :query OR alt_title LIKE :query) AND manga_id IN (SELECT manga_id FROM favourites UNION SELECT manga_id FROM history) LIMIT :limit") abstract suspend fun searchByTitle(query: String, limit: Int): List @Transaction - @Query("SELECT * FROM manga WHERE (title LIKE :query OR alt_title LIKE :query) AND source = :source LIMIT :limit") + @Query("SELECT * FROM manga WHERE (title LIKE :query OR alt_title LIKE :query) AND source = :source AND manga_id IN (SELECT manga_id FROM favourites UNION SELECT manga_id FROM history) LIMIT :limit") abstract suspend fun searchByTitle(query: String, source: String, limit: Int): List @Insert(onConflict = OnConflictStrategy.IGNORE) @@ -47,4 +47,4 @@ abstract class MangaDao { } } } -} \ No newline at end of file +} From 1cbfe017eae355f4317e3649600898b857b690a9 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 30 Nov 2022 09:22:51 +0200 Subject: [PATCH 09/88] Fix network state observer --- .../org/koitharu/kotatsu/core/AppModule.kt | 8 +++++ .../koitharu/kotatsu/core/os/NetworkState.kt | 32 +++++++------------ .../kotatsu/utils/MediatorStateFlow.kt | 5 +-- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt b/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt index 459ac9e8b..b5cf78270 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt @@ -25,6 +25,7 @@ import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.base.ui.util.ActivityRecreationHandle import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.network.* +import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.ShortcutsUpdater import org.koitharu.kotatsu.core.parser.MangaLoaderContextImpl import org.koitharu.kotatsu.core.parser.MangaRepository @@ -39,6 +40,7 @@ import org.koitharu.kotatsu.search.ui.MangaSuggestionsProvider import org.koitharu.kotatsu.settings.backup.BackupObserver import org.koitharu.kotatsu.sync.domain.SyncController import org.koitharu.kotatsu.utils.IncognitoModeIndicator +import org.koitharu.kotatsu.utils.ext.connectivityManager import org.koitharu.kotatsu.utils.ext.isLowRamDevice import org.koitharu.kotatsu.utils.image.CoilImageGetter import org.koitharu.kotatsu.widget.WidgetUpdater @@ -81,6 +83,12 @@ interface AppModule { }.build() } + @Provides + @Singleton + fun provideNetworkState( + @ApplicationContext context: Context + ) = NetworkState(context.connectivityManager) + @Provides @Singleton fun provideMangaDatabase( diff --git a/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkState.kt b/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkState.kt index 49d1704d6..207886065 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkState.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/os/NetworkState.kt @@ -1,29 +1,21 @@ package org.koitharu.kotatsu.core.os -import android.content.Context +import android.net.ConnectivityManager import android.net.ConnectivityManager.NetworkCallback import android.net.Network import android.net.NetworkRequest -import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.first import org.koitharu.kotatsu.utils.MediatorStateFlow -import org.koitharu.kotatsu.utils.ext.connectivityManager import org.koitharu.kotatsu.utils.ext.isNetworkAvailable -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class NetworkState @Inject constructor( - @ApplicationContext context: Context, -) : MediatorStateFlow() { +class NetworkState( + private val connectivityManager: ConnectivityManager, +) : MediatorStateFlow(connectivityManager.isNetworkAvailable) { - private val connectivityManager = context.connectivityManager private val callback = NetworkCallbackImpl() - override val initialValue: Boolean - get() = connectivityManager.isNetworkAvailable - override fun onActive() { + invalidate() val request = NetworkRequest.Builder().build() connectivityManager.registerNetworkCallback(request, callback) } @@ -39,16 +31,16 @@ class NetworkState @Inject constructor( first { it } } + private fun invalidate() { + publishValue(connectivityManager.isNetworkAvailable) + } + private inner class NetworkCallbackImpl : NetworkCallback() { - override fun onAvailable(network: Network) = update() + override fun onAvailable(network: Network) = invalidate() - override fun onLost(network: Network) = update() + override fun onLost(network: Network) = invalidate() - override fun onUnavailable() = update() - - private fun update() { - publishValue(connectivityManager.isNetworkAvailable) - } + override fun onUnavailable() = invalidate() } } diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/MediatorStateFlow.kt b/app/src/main/java/org/koitharu/kotatsu/utils/MediatorStateFlow.kt index 618d098b0..01c637b38 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/MediatorStateFlow.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/MediatorStateFlow.kt @@ -5,14 +5,11 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import java.util.concurrent.atomic.AtomicInteger -abstract class MediatorStateFlow : StateFlow { +abstract class MediatorStateFlow(initialValue: T) : StateFlow { - @Suppress("LeakingThis") private val delegate = MutableStateFlow(initialValue) private val collectors = AtomicInteger(0) - protected abstract val initialValue: T - final override val replayCache: List get() = delegate.replayCache From 59fa61864a8a62f277f58a67dbf9af9cfe6e0906 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 9 Dec 2022 18:19:39 +0200 Subject: [PATCH 10/88] Update parsers --- app/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5f2583e1e..13fcc44c3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 33 - versionCode 505 - versionName '4.0.5' + versionCode 506 + versionName '4.0.6' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -83,7 +83,7 @@ afterEvaluate { } } dependencies { - implementation('com.github.KotatsuApp:kotatsu-parsers:2ab03cb668') { + implementation('com.github.KotatsuApp:kotatsu-parsers:add70b4790') { exclude group: 'org.json', module: 'json' } @@ -91,7 +91,7 @@ dependencies { implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.activity:activity-ktx:1.6.1' - implementation 'androidx.fragment:fragment-ktx:1.5.4' + implementation 'androidx.fragment:fragment-ktx:1.5.5' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1' implementation 'androidx.lifecycle:lifecycle-service:2.5.1' From 1261a6790d7a9a529dd006d8bff5ad77babc3f81 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 9 Dec 2022 18:24:55 +0200 Subject: [PATCH 11/88] Improve pages cache creation --- .../koitharu/kotatsu/local/data/PagesCache.kt | 19 ++++++++++++++++--- .../org/koitharu/kotatsu/utils/ext/FileExt.kt | 4 +++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt index f8321b597..e78628f9d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt @@ -10,6 +10,7 @@ import org.koitharu.kotatsu.utils.ext.copyToSuspending import org.koitharu.kotatsu.utils.ext.longHashCode import org.koitharu.kotatsu.utils.ext.subdir import org.koitharu.kotatsu.utils.ext.takeIfReadable +import org.koitharu.kotatsu.utils.ext.takeIfWriteable import java.io.File import java.io.InputStream import javax.inject.Inject @@ -18,9 +19,14 @@ import javax.inject.Singleton @Singleton class PagesCache @Inject constructor(@ApplicationContext context: Context) { - private val cacheDir = context.externalCacheDir ?: context.cacheDir + private val cacheDir = checkNotNull(findSuitableDir(context)) { + val dirs = (context.externalCacheDirs + context.cacheDir).joinToString(";") { + it.absolutePath + } + "Cannot find any suitable directory for PagesCache: [$dirs]" + } private val lruCache = createDiskLruCacheSafe( - dir = cacheDir.subdir(CacheDir.PAGES.dir), + dir = cacheDir, size = FileSize.MEGABYTES.convert(200, FileSize.BYTES), ) @@ -29,7 +35,7 @@ class PagesCache @Inject constructor(@ApplicationContext context: Context) { } suspend fun put(url: String, inputStream: InputStream): File = withContext(Dispatchers.IO) { - val file = File(cacheDir, url.longHashCode().toString()) + val file = File(cacheDir.parentFile, url.longHashCode().toString()) try { file.outputStream().use { out -> inputStream.copyToSuspending(out) @@ -50,3 +56,10 @@ private fun createDiskLruCacheSafe(dir: File, size: Long): DiskLruCache { DiskLruCache.create(dir, size) } } + +private fun findSuitableDir(context: Context): File? { + val dirs = context.externalCacheDirs + context.cacheDir + return dirs.firstNotNullOfOrNull { + it.subdir(CacheDir.PAGES.dir).takeIfWriteable() + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt index cab41519f..c40f4e01c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt @@ -23,6 +23,8 @@ fun File.subdir(name: String) = File(this, name).also { fun File.takeIfReadable() = takeIf { it.exists() && it.canRead() } +fun File.takeIfWriteable() = takeIf { it.exists() && it.canWrite() } + fun ZipFile.readText(entry: ZipEntry) = getInputStream(entry).bufferedReader().use { it.readText() } @@ -74,4 +76,4 @@ private fun computeSizeInternal(file: File): Long { } else { return file.length() } -} \ No newline at end of file +} From 24908e52afe8eaf6b26dd3421f4e3613093b85f3 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 9 Dec 2022 18:32:10 +0200 Subject: [PATCH 12/88] Update network error message --- .../org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt | 2 ++ app/src/main/res/values/strings.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt index 51db77550..2bb76f37f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt @@ -21,6 +21,7 @@ import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings +import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import java.io.File import java.io.IOException @@ -138,6 +139,7 @@ class PageHolderDelegate( } catch (e: CancellationException) { throw e } catch (e: Throwable) { + e.printStackTraceDebug() state = State.ERROR error = e callback.onError(e) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b078c48ca..5fb25e1e3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,7 +7,7 @@ Favourites History An error occurred - Could not connect to the Internet + Network error Details Chapters List From 86da3217d18d1b3ee5f73fa2e2c749b8e7c122cb Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 26 Dec 2022 19:13:48 +0200 Subject: [PATCH 13/88] Add A13 locale list --- app/src/main/AndroidManifest.xml | 1 + app/src/main/res/xml/locales.xml | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 app/src/main/res/xml/locales.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4ca5eaf80..ebe4fbdf1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -29,6 +29,7 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true" + android:localeConfig="@xml/locales" android:networkSecurityConfig="@xml/network_security_config" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" diff --git a/app/src/main/res/xml/locales.xml b/app/src/main/res/xml/locales.xml new file mode 100644 index 000000000..77223ddc2 --- /dev/null +++ b/app/src/main/res/xml/locales.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 9088f77ae5e494bf82085110381a67fddab4c86e Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 26 Dec 2022 19:15:27 +0200 Subject: [PATCH 14/88] Update dependencies --- app/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 13fcc44c3..dc3abd532 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 33 - versionCode 506 - versionName '4.0.6' + versionCode 507 + versionName '4.1' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -83,7 +83,7 @@ afterEvaluate { } } dependencies { - implementation('com.github.KotatsuApp:kotatsu-parsers:add70b4790') { + implementation('com.github.KotatsuApp:kotatsu-parsers:9ee1c21a67') { 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-svg:2.2.2' - implementation 'com.github.KotatsuApp:subsampling-scale-image-view:f8a38b08fe' + implementation 'com.github.KotatsuApp:subsampling-scale-image-view:95e6c188c6' implementation 'com.github.solkin:disk-lru-cache:1.4' implementation 'ch.acra:acra-http:5.9.7' From 400b91278fe7fafc4ba067a0ac08590a0c495291 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 26 Dec 2022 19:27:38 +0200 Subject: [PATCH 15/88] Allow source login on error --- .../java/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt index 4542b1fca..91561b2cd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt @@ -86,7 +86,6 @@ class SourceSettingsFragment : BasePreferenceFragment(0) { }.onSuccess { username -> preference.title = getString(R.string.logged_in_as, username) }.onFailure { error -> - preference.isEnabled = error is AuthRequiredException when { error is AuthRequiredException -> Unit ExceptionResolver.canResolve(error) -> { From f41425f03d09e6a8e8afa4972767f97ddf8f4162 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 26 Dec 2022 20:02:02 +0200 Subject: [PATCH 16/88] Popup menu on sources in Explore fragment --- .../kotatsu/explore/ui/ExploreFragment.kt | 47 ++++++++++++++++++- .../kotatsu/explore/ui/ExploreViewModel.kt | 22 ++++++++- app/src/main/res/menu/popup_source.xml | 13 +++++ app/src/main/res/values/strings.xml | 1 + 4 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/menu/popup_source.xml diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt index bcb83c411..98086832c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt @@ -2,8 +2,10 @@ package org.koitharu.kotatsu.explore.ui import android.os.Bundle import android.view.LayoutInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.appcompat.widget.PopupMenu import androidx.core.graphics.Insets import androidx.core.view.updatePadding import androidx.fragment.app.viewModels @@ -11,11 +13,12 @@ import androidx.recyclerview.widget.RecyclerView import coil.ImageLoader import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.domain.reverseAsync import org.koitharu.kotatsu.base.ui.BaseFragment import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner +import org.koitharu.kotatsu.base.ui.util.ReversibleAction import org.koitharu.kotatsu.bookmarks.ui.BookmarksActivity import org.koitharu.kotatsu.databinding.FragmentExploreBinding import org.koitharu.kotatsu.details.ui.DetailsActivity @@ -31,6 +34,7 @@ import org.koitharu.kotatsu.search.ui.MangaListActivity import org.koitharu.kotatsu.settings.SettingsActivity import org.koitharu.kotatsu.suggestions.ui.SuggestionsActivity import org.koitharu.kotatsu.utils.ext.getDisplayMessage +import javax.inject.Inject @AndroidEntryPoint class ExploreFragment : @@ -67,6 +71,7 @@ class ExploreFragment : } viewModel.onError.observe(viewLifecycleOwner, ::onError) viewModel.onOpenManga.observe(viewLifecycleOwner, ::onOpenManga) + viewModel.onActionDone.observe(viewLifecycleOwner, ::onActionDone) } override fun onDestroyView() { @@ -95,6 +100,7 @@ class ExploreFragment : viewModel.openRandom() return } + else -> return } startActivity(intent) @@ -105,6 +111,14 @@ class ExploreFragment : startActivity(intent) } + override fun onItemLongClick(item: ExploreItem.Source, view: View): Boolean { + val menu = PopupMenu(view.context, view) + menu.inflate(R.menu.popup_source) + menu.setOnMenuItemClickListener(SourceMenuListener(item)) + menu.show() + return true + } + override fun onRetryClick(error: Throwable) = Unit override fun onEmptyActionClick() = onManageClick(requireView()) @@ -124,6 +138,37 @@ class ExploreFragment : startActivity(intent) } + private fun onActionDone(action: ReversibleAction) { + val handle = action.handle + val length = if (handle == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG + val snackbar = Snackbar.make(binding.recyclerView, action.stringResId, length) + if (handle != null) { + snackbar.setAction(R.string.undo) { handle.reverseAsync() } + } + snackbar.anchorView = (activity as? BottomNavOwner)?.bottomNav + snackbar.show() + } + + private inner class SourceMenuListener( + private val sourceItem: ExploreItem.Source, + ) : PopupMenu.OnMenuItemClickListener { + + override fun onMenuItemClick(item: MenuItem): Boolean { + when (item.itemId) { + R.id.action_settings -> { + startActivity(SettingsActivity.newSourceSettingsIntent(requireContext(), sourceItem.source)) + } + + R.id.action_hide -> { + viewModel.hideSource(sourceItem.source) + } + + else -> return false + } + return true + } + } + companion object { fun newInstance() = ExploreFragment() diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt index 6d2657368..7783ebac0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt @@ -4,11 +4,17 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.asFlow import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.domain.ReversibleHandle import org.koitharu.kotatsu.base.ui.BaseViewModel +import org.koitharu.kotatsu.base.ui.util.ReversibleAction import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.explore.domain.ExploreRepository import org.koitharu.kotatsu.explore.ui.model.ExploreItem @@ -16,6 +22,7 @@ import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.utils.SingleLiveEvent import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct +import javax.inject.Inject @HiltViewModel class ExploreViewModel @Inject constructor( @@ -24,6 +31,7 @@ class ExploreViewModel @Inject constructor( ) : BaseViewModel() { val onOpenManga = SingleLiveEvent() + val onActionDone = SingleLiveEvent() val content: LiveData> = isLoading.asFlow().flatMapLatest { loading -> if (loading) { @@ -40,6 +48,16 @@ class ExploreViewModel @Inject constructor( } } + fun hideSource(source: MangaSource) { + launchJob(Dispatchers.Default) { + settings.hiddenSources += source.name + val rollback = ReversibleHandle { + settings.hiddenSources -= source.name + } + onActionDone.postCall(ReversibleAction(R.string.source_disabled, rollback)) + } + } + private fun createContentFlow() = settings.observe() .filter { it == AppSettings.KEY_SOURCES_HIDDEN || diff --git a/app/src/main/res/menu/popup_source.xml b/app/src/main/res/menu/popup_source.xml new file mode 100644 index 000000000..60e497a39 --- /dev/null +++ b/app/src/main/res/menu/popup_source.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5fb25e1e3..10218f426 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -398,4 +398,5 @@ Server side error (%1$d). Please try again later Also clear information about new chapters Compact + Source disabled From 03e0eefe4d83e7ff0a237015c1fa4c3f9d4d6977 Mon Sep 17 00:00:00 2001 From: NOTMASTER09 Date: Mon, 26 Dec 2022 21:06:50 +0200 Subject: [PATCH 17/88] Fix DirMangaImporter --- .../koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt b/app/src/main/java/org/koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt index d569af6c3..a00fa3da1 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt @@ -58,7 +58,7 @@ class DirMangaImporter( private suspend fun addPages(output: CbzMangaOutput, root: DocumentFile, path: String, state: State) { var number = 0 - for (file in root.listFiles()) { + for (file in root.listFiles().sortedBy {it.name}) { when { file.isDirectory -> { addPages(output, file, path + "/" + file.name, state) From 34c7cafdfec0fc292789fbc1b0ab119532f0a92b Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 27 Dec 2022 08:39:27 +0200 Subject: [PATCH 18/88] Use AlphanumComparator for importing manga dir --- .../koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt b/app/src/main/java/org/koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt index a00fa3da1..b117f1395 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/domain/importer/DirMangaImporter.kt @@ -13,6 +13,7 @@ import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN +import org.koitharu.kotatsu.utils.AlphanumComparator import org.koitharu.kotatsu.utils.ext.copyToSuspending import org.koitharu.kotatsu.utils.ext.deleteAwait import org.koitharu.kotatsu.utils.ext.longOf @@ -58,7 +59,7 @@ class DirMangaImporter( private suspend fun addPages(output: CbzMangaOutput, root: DocumentFile, path: String, state: State) { var number = 0 - for (file in root.listFiles().sortedBy {it.name}) { + for (file in root.listFiles().sortedWith(compareBy(AlphanumComparator()) { it.name.orEmpty() })) { when { file.isDirectory -> { addPages(output, file, path + "/" + file.name, state) From 375e72cb985825eddf21852f07bab9ad6e4d71d7 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 27 Dec 2022 08:55:39 +0200 Subject: [PATCH 19/88] Pass language to voice search --- .../java/org/koitharu/kotatsu/utils/VoiceInputContract.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/VoiceInputContract.kt b/app/src/main/java/org/koitharu/kotatsu/utils/VoiceInputContract.kt index e95e0fb96..ddb42ab45 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/VoiceInputContract.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/VoiceInputContract.kt @@ -5,12 +5,16 @@ import android.content.Context import android.content.Intent import android.speech.RecognizerIntent import androidx.activity.result.contract.ActivityResultContract +import androidx.core.os.ConfigurationCompat +import java.util.Locale class VoiceInputContract : ActivityResultContract() { override fun createIntent(context: Context, input: String?): Intent { val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH) intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM) + val locale = ConfigurationCompat.getLocales(context.resources.configuration).get(0) ?: Locale.getDefault() + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, locale.toLanguageTag()) intent.putExtra(RecognizerIntent.EXTRA_PROMPT, input) return intent } @@ -23,4 +27,4 @@ class VoiceInputContract : ActivityResultContract() { null } } -} \ No newline at end of file +} From d647a32e9f939b11a15776df180f48fce8a45035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Tue, 27 Dec 2022 07:59:24 +0100 Subject: [PATCH 20/88] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (399 of 399 strings) Translated using Weblate (Turkish) Currently translated at 100.0% (398 of 398 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/ Translation: Kotatsu/Strings --- app/src/main/res/values-tr/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 8834a5dee..be29d252e 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -1,6 +1,6 @@ - İnternete bağlı olduğunuzdan emin olunuz + Ağ hatası Menüyü kapat Menüyü aç Dahili Depolama @@ -395,4 +395,5 @@ Kaydedilen mangalar Uygulama simgesine uzun basarak son mangaları kullanılabilir hale getirin Sağ kenara dokunulduğunda veya sağ tuşa basıldığında her zaman bir sonraki sayfaya geçilir + Kaynak devre dışı \ No newline at end of file From 662f08e115fff4bfdca9204f70def21a8f9e20e2 Mon Sep 17 00:00:00 2001 From: kuragehime Date: Tue, 27 Dec 2022 07:59:25 +0100 Subject: [PATCH 21/88] Translated using Weblate (Japanese) Currently translated at 100.0% (398 of 398 strings) Co-authored-by: kuragehime Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/ Translation: Kotatsu/Strings --- app/src/main/res/values-ja/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 1117570fe..28773c9a2 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -63,7 +63,7 @@ ダークテーマ ページ テーマ - インターネットに接続出来ませんでした + ネットワークエラー カテゴリー名を入力してください アップデート キャッシュ @@ -395,4 +395,5 @@ Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます Webtoonズーム ウェブトゥーンモードでズームイン/ズームアウトのジェスチャーを可能にする(ベータ版) + コンパクト \ No newline at end of file From 0f1c9ff05d95c01095fdb5d2fb96c4311bc3eb76 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 27 Dec 2022 07:59:25 +0100 Subject: [PATCH 22/88] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (398 of 398 strings) Co-authored-by: Eric Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/ Translation: Kotatsu/Strings --- app/src/main/res/values-zh-rCN/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index d38116018..67e51d65a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -5,7 +5,7 @@ 喜欢 历史 发生了一个错误 - 未能连接到互联网 + 网络错误 章节 列表 数据被恢复了,但有错误 From ba403c936035e3476c72a3eda6413537f9d8dbe6 Mon Sep 17 00:00:00 2001 From: "J. Lavoie" Date: Tue, 27 Dec 2022 07:59:25 +0100 Subject: [PATCH 23/88] Translated using Weblate (French) Currently translated at 100.0% (398 of 398 strings) Translated using Weblate (German) Currently translated at 96.2% (383 of 398 strings) Co-authored-by: J. Lavoie Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/ Translation: Kotatsu/Strings --- app/src/main/res/values-de/strings.xml | 16 +++++++++++++++- app/src/main/res/values-fr/strings.xml | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 0354d02f7..8aee5c9f8 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -70,7 +70,7 @@ Liste Kapitel Einzelheiten - Keine Verbindung zum Internet möglich + Netzwerkfehler Es ist ein Fehler aufgetreten Verlauf Favoriten @@ -372,4 +372,18 @@ Import abgeschlossen Du kannst die Originaldatei aus dem Speicher löschen, um Platz zu sparen Import wird bald beginnen + Serverseitiger Fehler (%1$d). Bitte versuchen Sie es später noch einmal + Kompakt + Kontrast + Schalten Sie Wi-Fi oder ein mobiles Netzwerk ein, um Manga online zu lesen + Auch klare Informationen über neue Kapitel + Ungespeicherte Änderungen speichern oder verwerfen\? + Verwerfen + Zurücksetzen + Helligkeit + Die gewählten Farbeinstellungen werden für diesen Manga in Erinnerung bleiben + Farbkorrektur + Kein Platz mehr auf dem Gerät + Verschiedene Sprachen + Netzwerk ist nicht verfügbar \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index cd3975284..aa9cc0ea3 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -202,7 +202,7 @@ Liste Chapitres Détails - Impossible de se connecter à Internet + Erreur réseau Une erreur s\'est produite Historique Favoris From 560e669700efe990ce08a505bd58d8c5b8955185 Mon Sep 17 00:00:00 2001 From: mondstern Date: Tue, 27 Dec 2022 07:59:26 +0100 Subject: [PATCH 24/88] Translated using Weblate (German) Currently translated at 97.2% (387 of 398 strings) Co-authored-by: mondstern Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/ Translation: Kotatsu/Strings --- app/src/main/res/values-de/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 8aee5c9f8..5733508b0 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -386,4 +386,8 @@ Kein Platz mehr auf dem Gerät Verschiedene Sprachen Netzwerk ist nicht verfügbar + Vergrößerungs-/Verkleinerungsgesten im Webtoon-Modus zulassen (beta) + Ergonomische Leserkontrolle + Tippe auf den rechten Rand oder drücke die rechte Taste, um immer zur nächsten Seite zu wechseln + Seitenwechsel-Schieberegler anzeigen \ No newline at end of file From 607dfc9be3ce8f6f30079f9476b708594fcb4bda Mon Sep 17 00:00:00 2001 From: Andy Hong Date: Tue, 27 Dec 2022 07:59:26 +0100 Subject: [PATCH 25/88] Translated using Weblate (Korean) Currently translated at 26.8% (107 of 398 strings) Added translation using Weblate (Korean) Added translation using Weblate (Korean) Co-authored-by: Andy Hong Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ko/ Translation: Kotatsu/Strings --- app/src/main/res/values-ko/plurals.xml | 2 + app/src/main/res/values-ko/strings.xml | 108 +++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 app/src/main/res/values-ko/plurals.xml create mode 100644 app/src/main/res/values-ko/strings.xml diff --git a/app/src/main/res/values-ko/plurals.xml b/app/src/main/res/values-ko/plurals.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/app/src/main/res/values-ko/plurals.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml new file mode 100644 index 000000000..69701e235 --- /dev/null +++ b/app/src/main/res/values-ko/strings.xml @@ -0,0 +1,108 @@ + + + 정렬 기준 + 불러오기 + 네트워크 오류 + 목록 + 저장 + 공유하기 + %s 공유 + 검색하기 + 경고 + 내부 저장소 + 외부 저장소 + 도메인 + 새 버전이 존재합니다 + 웹 브라우저에서 열기 + 저장 + 알림 + 처음부터 읽기 + LED 표시 + 진동 + 이름 바꾸기 + 즐겨찾기에서 \"%s\" 카테고리를 제거하시겠습니까\? +\n포함된 모든 만화가 지워집니다. + 지우기 + 쿼리를 재구성하십시오. + 사이드 메뉴에서 만화를 탐색해보세요. + 만화가 여기에 표시됩니다 + «탐색» 섹션에서 만화를 탐색해보세요 + 페이지 전환 효과 + 사용 가능한 저장소 없음 + 완료 + 빈 카테고리 + 업데이트 + 새 버전: %s + 네트워크 연결을 기다리는 중… + 업데이트 피드 지우기 + 메뉴 닫기 + 메뉴 열기 + 내장 메모리 + 즐겨찾기 + 지우기 + 설정 + 불러오는 중… + 닫기 + 다시 시도 + 즐겨찾기가 비어있음 + 필터링 + 밝게 + 어둡게 + 페이지 + 지금 읽기 + 이름 순 + 인기 순 + %2$d화 중 %1$d화 + 다운로드 + 평점 순 + 페이지 저장 + 저장됨 + 이미지 공유하기 + ZIP 혹은 CBZ 파일을 선택하세요. + 기록 및 캐시 + 캐시 + 만화 제거 + 볼륨 키 + 결과 없음 + 즐겨찾기 추가 + 다운로드 완료 + 새 카테고리 + 만화를 검색하세요 + 다운로드 중… + 처리중… + 최근 업데이트 순 + 최근 발간 순 + 시스템 설정 + 지우기 + 잠시만 기다려주세요… + 바이트|kB|MB|GB|TB + 페이지 캐시 지우기 + 읽기 모드 + 격자 크기 + %s에서 검색 + 장치에서 \"%s\"를 영구적으로 삭제하시겠습니까\? + 페이지 전환 + 가장자리 탭 + 웹툰 + 검색 기록 지우기 + 읽기 모드 + 이 동작은 많은 데이터 사용을 + 썸네일 캐시 지우기 + 다시 묻지 않음 + 취소 중… + 오류 + 업데이트 확인 + 업데이트 가능 시 알림 설정 + 이 만화에는 %s가 있습니다. 모두 저장하시겠습니까\? + 즐겨찾기 카테고리 + 다운로드 + 알림 설정 + 알림음 + 카테고리… + 읽은 내용이 여기에 표시됩니다 + 사용할 수 없음 + 모든 즐겨찾기 + 나중에 읽기 + 검색 결과 + 크기: %s + \ No newline at end of file From 25974af229f7eda46bae1891bb2dc5ca47195839 Mon Sep 17 00:00:00 2001 From: Neko Nekowazarashi Date: Tue, 27 Dec 2022 07:59:26 +0100 Subject: [PATCH 26/88] Translated using Weblate (Indonesian) Currently translated at 90.2% (359 of 398 strings) Co-authored-by: Neko Nekowazarashi Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/ Translation: Kotatsu/Strings --- app/src/main/res/values-in/strings.xml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 0f98d4f67..4e8b326f2 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -102,15 +102,15 @@ Suara pemberitahuan Kategori… Ubah Nama - "Hapus kategori \"%s\" dari favorit Anda\? -\nSemua manga disana akan hilang." + Hapus kategori \"%s\" dari favorit Anda\? +\nSemua manga di situ akan hilang. Sepi juga di sini… Anda bisa menggunakan kategori untuk mengelola favorit Anda. Tekan «+» untuk membuat kategori Apa yang Anda baca akan ditampilkan di sini Cari apa untuk di baca di bilah samping. Simpan sesuatu dulu Rak - Terbaru + Baru-baru ini Animasi halaman Folder untuk unduhan Tidak tersedia @@ -298,7 +298,7 @@ Selesai Dibatalkan Sinkronisasi data Anda - Masukkan email Anda untuk melanjutkan + Masukkan surel Anda untuk melanjutkan Pelacakan Keluar Sinkronisasi @@ -329,7 +329,7 @@ Tekan Kembali dua kali untuk keluar dari aplikasi Konfirmasi keluar Tembolok halaman - Cache lainnya + Tembolok lainnya Penggunaan penyimpanan Tersedia Mode Incognito @@ -356,14 +356,14 @@ Ada sesuatu yang salah. Mohon untuk mengirim laporan kutu (bug) ke pengembang untuk membantu kami memperbaikinya. Lapor Manga yang ditandai sebagai NSFW tidak akan ditambahkan ke riwayat dan progres Anda tidak akan disimpan - Bisa membantu dalam beberapa masalah. Seluruh otorisasi akan menjadi tidak valid. + Bisa membantu dalam beberapa masalah. Seluruh otorisasi akan menjadi tidak valid Kelola Aktifkan sumber manga untuk membaca manga daring Apakah Anda yakin ingin menghapus kategori favorit yang dipilih\? \n Semua manga di sana akan hilang dan ini tidak bisa diurungkan. Atur Ulang Manga tersimpan - Tekan lagi untuk keluar + Tekan Kembali lagi untuk keluar Tidak ada bab Tampilkan pintasan manga baru-baru ini Buat manga baru-baru ini tersedia dengan menekan panjang pada ikon aplikasi @@ -372,4 +372,5 @@ Hanya gestur DNS melalui HTTPS Istirahat + Mati \ No newline at end of file From a6c30d33d46207a7e83772a5a2493953bae2fcd8 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Tue, 27 Dec 2022 07:59:27 +0100 Subject: [PATCH 27/88] Translated using Weblate (Spanish) Currently translated at 100.0% (398 of 398 strings) Co-authored-by: gallegonovato Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/ Translation: Kotatsu/Strings --- app/src/main/res/values-es/strings.xml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 150053d37..779e98d4d 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -6,7 +6,7 @@ Favoritos Historial Ocurrió un error - No se pudo conectar a Internet + Error en la red Detalles Capítulos Lista @@ -266,7 +266,7 @@ Excluir géneros Especifica los géneros que no quieres ver en las sugerencias Remoción completada - ¿Estás seguro de que quieres descargar todos los manga seleccionados con todos sus capítulos\? Esta acción puede consumir mucho tráfico y almacenamiento + ¿Descargar todos los mangas seleccionados y sus capítulos\? Esto puede consumir mucho tráfico y almacenamiento. ¿Eliminar elementos seleccionados del dispositivo de forma permanente\? Ocultar Ralentización de la descarga @@ -375,7 +375,7 @@ Detalles del error:<br><tt>%1$s</tt><br><br>1. Intenta <a href=%2$s>abrir el manga en un navegador web</a> para asegurarte de que está disponible en tu fuente<br>2. Si está disponible, envía un informe de error a los desarrolladores. Hacer que los mangas recientes estén disponibles mediante una pulsación larga en el icono de la aplicación Los ajustes de color elegidos serán recordados para este manga - Feed + Fuente Descargando manga Mostrar los accesos directos a los mangas recientes Tocando el borde derecho o pulsando la tecla derecha se pasa siempre a la página siguiente @@ -384,10 +384,16 @@ Brillo Contraste Restablecer - Tienes cambios sin guardar. ¿Quieres guardarlos o descartarlos\? + ¿Guardar o descartar los cambios no guardados\? Descartar Sin espacio en dispositivo Zoom de webtoon Permitir el gesto de acercamiento/alejamiento en modo webtoon (beta) Mostrar el deslizador de cambio de página + Error del servidor (%1$d). Vuelva a intentarlo más tarde + Información clara sobre los nuevos capítulos + Diferentes idiomas + La red no está disponible + Compacta + Enciende la Wi-Fi o la red móvil para leer los mangas en línea \ No newline at end of file From 9c52545f636a97994368a92a2e3b0adb2380f78b Mon Sep 17 00:00:00 2001 From: Evgeniy Khramov Date: Tue, 27 Dec 2022 07:59:27 +0100 Subject: [PATCH 28/88] Translated using Weblate (Russian) Currently translated at 100.0% (398 of 398 strings) Translated using Weblate (Russian) Currently translated at 100.0% (8 of 8 strings) Co-authored-by: Evgeniy Khramov Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ru/ Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/ Translation: Kotatsu/Strings Translation: Kotatsu/plurals --- app/src/main/res/values-ru/plurals.xml | 82 +++++++++++++------------- app/src/main/res/values-ru/strings.xml | 2 +- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/app/src/main/res/values-ru/plurals.xml b/app/src/main/res/values-ru/plurals.xml index 779694d73..ca03bb638 100644 --- a/app/src/main/res/values-ru/plurals.xml +++ b/app/src/main/res/values-ru/plurals.xml @@ -1,44 +1,44 @@ - - Всего %1$d страница - Всего %1$d страницы - Всего %1$d страниц - - - %1$d элемент - %1$d элемента - %1$d элементов - - - %1$d новая глава - %1$d новых главы - %1$d новых глав - - - %1$d глава - %1$d главы - %1$d глав - - - %1$d глава из %2$d - %1$d главы из %2$d - %1$d глав из %2$d - - - - %1$d минуту назад - %1$d минуты назад - %1$d минут назад - - - %1$d час назад - %1$d часа назад - %1$d часов назад - - - %1$d день назад - %1$d дня назад - %1$d дней назад - + + Всего %1$d страница + Всего %1$d страницы + Всего %1$d страниц + + + %1$d элемент + %1$d элемента + %1$d элементов + + + %1$d новая глава + %1$d новые главы + %1$d новых глав + %1$d новых глав + + + %1$d глава + %1$d главы + %1$d глав + + + %1$d глава из %2$d + %1$d главы из %2$d + %1$d глав из %2$d + + + %1$d минуту назад + %1$d минуты назад + %1$d минут назад + + + %1$d час назад + %1$d часа назад + %1$d часов назад + + + %1$d день назад + %1$d дня назад + %1$d дней назад + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3d4a096bf..5f2d2fd29 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -6,7 +6,7 @@ Избранное История Произошла ошибка - Не удалось подключиться к интернету + Ошибка сети Подробности Главы Список From 08764cb3cbe9062f0f5dd5f74219a1f08a7766d5 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 27 Dec 2022 07:59:27 +0100 Subject: [PATCH 29/88] Translated using Weblate (Russian) Currently translated at 100.0% (399 of 399 strings) Co-authored-by: Koitharu Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/ Translation: Kotatsu/Strings --- app/src/main/res/values-ru/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 5f2d2fd29..b160b14b3 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -396,4 +396,5 @@ Также очистить информацию о новых главах Внутренняя ошибка сервера (%1$d). Повторите попытку позже Компактно + Источник отключен \ No newline at end of file From 3a62e2e6c0cc2a2073fc483e2b6238f4a49e8870 Mon Sep 17 00:00:00 2001 From: Zakhar Timoshenko Date: Sat, 31 Dec 2022 15:08:47 +0300 Subject: [PATCH 30/88] Add monochrome icon on One UI 5.0 --- app/src/main/AndroidManifest.xml | 3 +++ app/src/main/res/values-v33/bools.xml | 4 ++++ app/src/main/res/values/bools.xml | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/values-v33/bools.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ebe4fbdf1..be81140ca 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -248,6 +248,9 @@ + diff --git a/app/src/main/res/values-v33/bools.xml b/app/src/main/res/values-v33/bools.xml new file mode 100644 index 000000000..7b34e7f9c --- /dev/null +++ b/app/src/main/res/values-v33/bools.xml @@ -0,0 +1,4 @@ + + + false + diff --git a/app/src/main/res/values/bools.xml b/app/src/main/res/values/bools.xml index 5cb31b523..79442ec80 100644 --- a/app/src/main/res/values/bools.xml +++ b/app/src/main/res/values/bools.xml @@ -3,4 +3,5 @@ false true false - \ No newline at end of file + true + From 0e1b8db688f3ccfd9e01a2fe2286a7ebaab5954a Mon Sep 17 00:00:00 2001 From: Zakhar Timoshenko Date: Sat, 31 Dec 2022 22:32:35 +0300 Subject: [PATCH 31/88] Update parsers, Happy New Year! --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index dc3abd532..3a812af6a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -83,7 +83,7 @@ afterEvaluate { } } dependencies { - implementation('com.github.KotatsuApp:kotatsu-parsers:9ee1c21a67') { + implementation('com.github.KotatsuApp:kotatsu-parsers:c4acb9725f') { exclude group: 'org.json', module: 'json' } From 9bf53114de729db41d4cbc8fb68e5e7d07a47e6a Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Wed, 28 Dec 2022 16:47:27 +0100 Subject: [PATCH 32/88] Translated using Weblate (Spanish) Currently translated at 100.0% (399 of 399 strings) Co-authored-by: gallegonovato Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/ Translation: Kotatsu/Strings --- app/src/main/res/values-es/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 779e98d4d..40f11e537 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -396,4 +396,5 @@ La red no está disponible Compacta Enciende la Wi-Fi o la red móvil para leer los mangas en línea + Fuente desactivada \ No newline at end of file From 731e998eb229de0ce67c239321680c0042a05c0b Mon Sep 17 00:00:00 2001 From: "J. Lavoie" Date: Wed, 28 Dec 2022 16:47:28 +0100 Subject: [PATCH 33/88] 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 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 --- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 2 ++ 3 files changed, 4 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 5733508b0..060dc6671 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -390,4 +390,5 @@ Ergonomische Leserkontrolle Tippe auf den rechten Rand oder drücke die rechte Taste, um immer zur nächsten Seite zu wechseln Seitenwechsel-Schieberegler anzeigen + Quelle deaktiviert \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index aa9cc0ea3..939a3fb19 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -395,4 +395,5 @@ Compact Erreur côté serveur (%1$d). Veuillez réessayer plus tard Effacer aussi les informations sur les nouveaux chapitres + Source désactivée \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index cfcbf91fb..eaeb7ef74 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -320,4 +320,6 @@ Dominio non valido Seleziona l\'intervallo Contenuto non trovato o rimosso + Compatto + Fonte disabilitata \ No newline at end of file From 72336d4f71e5007c044c6af21247d03261cda428 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 28 Dec 2022 16:47:28 +0100 Subject: [PATCH 34/88] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (399 of 399 strings) Co-authored-by: Eric Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/ Translation: Kotatsu/Strings --- app/src/main/res/values-zh-rCN/strings.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 67e51d65a..ed8da9133 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -31,7 +31,7 @@ 清除cookies 检查新的章节: %1$d/%2$d 你必须输入一个名称 - 新的漫画来源 + 有新的漫画源可用 根据你的喜好推荐漫画 所有的数据都在这个设备上进行本地分析. 您的个人数据不会被转移到任何服务机构 从不 @@ -48,7 +48,7 @@ 详细列表 网格 列表模式 - 远程资源 + 远程源 加载中… 计算中… %1$d/%2$d章节 @@ -230,7 +230,7 @@ 关于4PDA主题 授权 不支持在%s上登录 - 你将被从所有来源中注销 + 你将退出登录所有来源 类型 连载中 已完结 @@ -395,4 +395,5 @@ 同样清除新章节信息 服务器端错误 (%1$d)。请稍后再试 紧凑 + 已禁用图源 \ No newline at end of file From 689670b3ff13adefa96383033d92be224134b12b Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 28 Dec 2022 14:28:28 +0200 Subject: [PATCH 35/88] Show inconito mode indicator on Read button --- .../kotatsu/details/ui/DetailsActivity.kt | 10 +++--- .../kotatsu/details/ui/DetailsFragment.kt | 31 ++++++++++++++----- .../kotatsu/details/ui/DetailsViewModel.kt | 28 +++++++++++------ .../kotatsu/details/ui/model/HistoryInfo.kt | 16 +++++++--- .../koitharu/kotatsu/main/ui/MainViewModel.kt | 10 ++++-- 5 files changed, 66 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 7a14f2403..91c534ea4 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -228,18 +228,18 @@ class DetailsActivity : } } - private fun onHistoryChanged(info: HistoryInfo?) { + private fun onHistoryChanged(info: HistoryInfo) { with(binding.buttonRead) { - if (info?.history != null) { + if (info.history != null) { setText(R.string._continue) - setIconResource(R.drawable.ic_play) + setIconResource(if (info.isIncognitoMode) R.drawable.ic_incognito else R.drawable.ic_play) } else { 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 { - 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.totalChapters == 0 -> getString(R.string.no_chapters) else -> resources.getQuantityString(R.plurals.chapters, info.totalChapters, info.totalChapters) diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index c3de6fa13..6d2203632 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -18,7 +18,6 @@ import coil.request.ImageRequest import coil.util.CoilUtils import com.google.android.material.chip.Chip import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject import kotlinx.coroutines.launch import org.koitharu.kotatsu.R 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.bookmarks.domain.Bookmark 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.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.ScrollingInfoAdapter 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.SearchActivity 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 javax.inject.Inject @AndroidEntryPoint class DetailsFragment : @@ -75,7 +86,7 @@ class DetailsFragment : binding.chipsTags.onChipClickListener = this viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated) viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged) - viewModel.readingHistory.observe(viewLifecycleOwner, ::onHistoryChanged) + viewModel.historyInfo.observe(viewLifecycleOwner, ::onHistoryChanged) viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged) viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged) viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged) @@ -123,12 +134,14 @@ class DetailsFragment : drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_finished) } } + MangaState.ONGOING -> { infoLayout.textViewState.apply { textAndVisible = resources.getString(R.string.state_ongoing) drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_ongoing) } } + else -> infoLayout.textViewState.isVisible = false } if (manga.source == MangaSource.LOCAL) { @@ -178,8 +191,8 @@ class DetailsFragment : } } - private fun onHistoryChanged(history: MangaHistory?) { - binding.progressView.setPercent(history?.percent ?: PROGRESS_NONE, animate = true) + private fun onHistoryChanged(history: HistoryInfo) { + binding.progressView.setPercent(history.history?.percent ?: PROGRESS_NONE, animate = true) } private fun onLoadingStateChanged(isLoading: Boolean) { @@ -229,6 +242,7 @@ class DetailsFragment : ), ) } + R.id.textView_source -> { startActivity( MangaListActivity.newIntent( @@ -237,6 +251,7 @@ class DetailsFragment : ), ) } + R.id.imageView_cover -> { startActivity( ImageActivity.newIntent(v.context, manga.largeCoverUrl.ifNullOrEmpty { manga.coverUrl }), @@ -249,7 +264,7 @@ class DetailsFragment : override fun onLongClick(v: View): Boolean { when (v.id) { R.id.button_read -> { - if (viewModel.readingHistory.value == null) { + if (viewModel.historyInfo.value?.history == null) { return false } val menu = PopupMenu(v.context, v) @@ -271,12 +286,14 @@ class DetailsFragment : ) true } + else -> false } } menu.show() return true } + else -> return false } } diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index 62f340539..b49b1adf8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -13,10 +13,18 @@ import androidx.lifecycle.viewModelScope import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import java.io.IOException import kotlinx.coroutines.Dispatchers 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.plus 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.printStackTraceDebug import org.koitharu.kotatsu.utils.ext.runCatchingCancellable +import java.io.IOException class DetailsViewModel @AssistedInject constructor( @Assisted intent: MangaIntent, @@ -91,17 +100,18 @@ class DetailsViewModel @AssistedInject constructor( val manga = delegate.manga.filterNotNull().asLiveData(viewModelScope.coroutineContext) val favouriteCategories = favourite.asLiveData(viewModelScope.coroutineContext) val newChaptersCount = newChapters.asLiveData(viewModelScope.coroutineContext) - - @Deprecated("") - val readingHistory = history.asLiveData(viewModelScope.coroutineContext) val isChaptersReversed = chaptersReversed.asLiveData(viewModelScope.coroutineContext) - val historyInfo = combine( + val historyInfo: LiveData = combine( delegate.manga, history, - ) { m, h -> - HistoryInfo(m, h) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, null) + settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled }, + ) { m, h, im -> + HistoryInfo(m, h, im) + }.asFlowLiveData( + context = viewModelScope.coroutineContext + Dispatchers.Default, + defaultValue = HistoryInfo(null, null, false), + ) val bookmarks = delegate.manga.flatMapLatest { if (it != null) bookmarksRepository.observeBookmarks(it) else flowOf(emptyList()) diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/model/HistoryInfo.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/model/HistoryInfo.kt index a3fd7f9fa..ae314be62 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/model/HistoryInfo.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/model/HistoryInfo.kt @@ -7,8 +7,12 @@ class HistoryInfo( val totalChapters: Int, val currentChapter: Int, val history: MangaHistory?, + val isIncognitoMode: Boolean, ) { + val isValid: Boolean + get() = totalChapters >= 0 + override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -18,6 +22,7 @@ class HistoryInfo( if (totalChapters != other.totalChapters) return false if (currentChapter != other.currentChapter) return false if (history != other.history) return false + if (isIncognitoMode != other.isIncognitoMode) return false return true } @@ -26,20 +31,21 @@ class HistoryInfo( var result = totalChapters result = 31 * result + currentChapter result = 31 * result + (history?.hashCode() ?: 0) + result = 31 * result + isIncognitoMode.hashCode() return result } } -@Suppress("FunctionName") -fun HistoryInfo(manga: Manga?, history: MangaHistory?): HistoryInfo? { - val chapters = manga?.chapters ?: return null +fun HistoryInfo(manga: Manga?, history: MangaHistory?, isIncognitoMode: Boolean): HistoryInfo { + val chapters = manga?.chapters return HistoryInfo( - totalChapters = chapters.size, - currentChapter = if (history != null) { + totalChapters = chapters?.size ?: -1, + currentChapter = if (history != null && !chapters.isNullOrEmpty()) { chapters.indexOfFirst { it.id == history.chapterId } } else { -1 }, history = history, + isIncognitoMode = isIncognitoMode, ) } diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt index 7d35e99cf..423b88fbb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt @@ -12,6 +12,7 @@ import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException import org.koitharu.kotatsu.core.github.AppUpdateRepository 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.history.domain.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga @@ -34,9 +35,12 @@ class MainViewModel @Inject constructor( val onOpenReader = SingleLiveEvent() - val isResumeEnabled = historyRepository - .observeHasItems() - .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) + val isResumeEnabled = combine( + historyRepository.observeHasItems(), + settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled }, + ) { hasItems, incognito -> + hasItems && !incognito + }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) val isFeedAvailable = settings.observeAsLiveData( context = viewModelScope.coroutineContext + Dispatchers.Default, From 04afe7a93415c46415ce91f84e528e85b0cedb18 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 28 Dec 2022 14:59:07 +0200 Subject: [PATCH 36/88] Bind ssiv with lifecycle --- app/build.gradle | 2 +- .../reader/ui/pager/reversed/ReversedPageHolder.kt | 4 +++- .../reader/ui/pager/reversed/ReversedPagesAdapter.kt | 3 +++ .../reader/ui/pager/reversed/ReversedReaderFragment.kt | 9 +++++---- .../kotatsu/reader/ui/pager/standard/PageHolder.kt | 3 +++ .../reader/ui/pager/standard/PagerReaderFragment.kt | 9 +++++---- .../kotatsu/reader/ui/pager/standard/PagesAdapter.kt | 3 +++ .../kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt | 3 +++ .../kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt | 3 +++ .../reader/ui/pager/webtoon/WebtoonReaderFragment.kt | 9 +++++---- 10 files changed, 34 insertions(+), 14 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3a812af6a..7f27b4808 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -125,7 +125,7 @@ dependencies { implementation 'io.coil-kt:coil-base: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 'ch.acra:acra-http:5.9.7' diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt index f907de4a9..2348965a0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPageHolder.kt @@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.reversed import android.graphics.PointF import android.view.Gravity import android.widget.FrameLayout +import androidx.lifecycle.LifecycleOwner import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver 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 class ReversedPageHolder( + owner: LifecycleOwner, binding: ItemPageBinding, loader: PageLoader, settings: ReaderSettings, networkState: NetworkState, exceptionResolver: ExceptionResolver, -) : PageHolder(binding, loader, settings, networkState, exceptionResolver) { +) : PageHolder(owner, binding, loader, settings, networkState, exceptionResolver) { init { (binding.textViewNumber.layoutParams as FrameLayout.LayoutParams) diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt index 4c6eeb28e..e81b1cfec 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedPagesAdapter.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui.pager.reversed import android.view.LayoutInflater import android.view.ViewGroup +import androidx.lifecycle.LifecycleOwner import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.os.NetworkState 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 class ReversedPagesAdapter( + private val lifecycleOwner: LifecycleOwner, loader: PageLoader, settings: ReaderSettings, networkState: NetworkState, @@ -23,6 +25,7 @@ class ReversedPagesAdapter( networkState: NetworkState, exceptionResolver: ExceptionResolver, ) = ReversedPageHolder( + owner = lifecycleOwner, binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false), loader = loader, settings = settings, diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt index 0302134dd..d8f7b9b99 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt @@ -39,10 +39,11 @@ class ReversedReaderFragment : BaseReader() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) pagerAdapter = ReversedPagesAdapter( - viewModel.pageLoader, - viewModel.readerSettings, - networkState, - exceptionResolver, + lifecycleOwner = viewLifecycleOwner, + loader = viewModel.pageLoader, + settings = viewModel.readerSettings, + networkState = networkState, + exceptionResolver = exceptionResolver, ) with(binding.pager) { adapter = pagerAdapter diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt index c2501e499..efa8e4dcd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt @@ -5,6 +5,7 @@ import android.graphics.PointF import android.net.Uri import android.view.View import androidx.core.view.isVisible +import androidx.lifecycle.LifecycleOwner import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import org.koitharu.kotatsu.R @@ -19,6 +20,7 @@ import org.koitharu.kotatsu.reader.ui.pager.ReaderPage import org.koitharu.kotatsu.utils.ext.* open class PageHolder( + owner: LifecycleOwner, binding: ItemPageBinding, loader: PageLoader, settings: ReaderSettings, @@ -28,6 +30,7 @@ open class PageHolder( View.OnClickListener { init { + binding.ssiv.bindToLifecycle(owner) binding.ssiv.isEagerLoadingEnabled = !isLowRamDevice(context) binding.ssiv.addOnImageEventListener(delegate) @Suppress("LeakingThis") diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt index 07633f5e2..af20be177 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt @@ -38,10 +38,11 @@ class PagerReaderFragment : BaseReader() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) pagesAdapter = PagesAdapter( - viewModel.pageLoader, - viewModel.readerSettings, - networkState, - exceptionResolver, + lifecycleOwner = viewLifecycleOwner, + loader = viewModel.pageLoader, + settings = viewModel.readerSettings, + networkState = networkState, + exceptionResolver = exceptionResolver, ) with(binding.pager) { adapter = pagesAdapter diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt index a36057bf7..0c562ae4d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagesAdapter.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui.pager.standard import android.view.LayoutInflater import android.view.ViewGroup +import androidx.lifecycle.LifecycleOwner import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.os.NetworkState 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 class PagesAdapter( + private val lifecycleOwner: LifecycleOwner, loader: PageLoader, settings: ReaderSettings, networkState: NetworkState, @@ -23,6 +25,7 @@ class PagesAdapter( networkState: NetworkState, exceptionResolver: ExceptionResolver, ) = PageHolder( + owner = lifecycleOwner, binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false), loader = loader, settings = settings, diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt index e47711f49..607f33ad6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonAdapter.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon import android.view.LayoutInflater import android.view.ViewGroup +import androidx.lifecycle.LifecycleOwner import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.os.NetworkState 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 class WebtoonAdapter( + private val lifecycleOwner: LifecycleOwner, loader: PageLoader, settings: ReaderSettings, networkState: NetworkState, @@ -23,6 +25,7 @@ class WebtoonAdapter( networkState: NetworkState, exceptionResolver: ExceptionResolver, ) = WebtoonHolder( + owner = lifecycleOwner, binding = ItemPageWebtoonBinding.inflate( LayoutInflater.from(parent.context), parent, diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt index 81ce8fb80..c8cfa3714 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt @@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon import android.net.Uri import android.view.View import androidx.core.view.isVisible +import androidx.lifecycle.LifecycleOwner import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView 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 class WebtoonHolder( + owner: LifecycleOwner, binding: ItemPageWebtoonBinding, loader: PageLoader, settings: ReaderSettings, @@ -34,6 +36,7 @@ class WebtoonHolder( private val goneOnInvisibleListener = GoneOnInvisibleListener(bindingInfo.progressBar) init { + binding.ssiv.bindToLifecycle(owner) binding.ssiv.regionDecoderFactory = SkiaPooledImageRegionDecoder.Factory() binding.ssiv.addOnImageEventListener(delegate) bindingInfo.buttonRetry.setOnClickListener(this) diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt index 1142fedcb..072e42169 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt @@ -35,10 +35,11 @@ class WebtoonReaderFragment : BaseReader() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) webtoonAdapter = WebtoonAdapter( - viewModel.pageLoader, - viewModel.readerSettings, - networkState, - exceptionResolver, + lifecycleOwner = viewLifecycleOwner, + loader = viewModel.pageLoader, + settings = viewModel.readerSettings, + networkState = networkState, + exceptionResolver = exceptionResolver, ) with(binding.recyclerView) { setHasFixedSize(true) From 656a707b4c49a8cb3b129672918c0dba29100e63 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 1 Jan 2023 08:49:15 +0200 Subject: [PATCH 37/88] Bump version --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7f27b4808..0f2d3fad3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 33 - versionCode 507 - versionName '4.1' + versionCode 508 + versionName '4.1.1' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From 75cc9e9030fb07403a74d9e144a474cac8911d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Antonik?= Date: Mon, 2 Jan 2023 23:00:46 +0100 Subject: [PATCH 38/88] Translate to Polish --- app/src/main/res/values-pl/plurals.xml | 43 +++ app/src/main/res/values-pl/strings.xml | 397 +++++++++++++++++++++++++ app/src/main/res/xml/locales.xml | 1 + 3 files changed, 441 insertions(+) create mode 100644 app/src/main/res/values-pl/plurals.xml create mode 100644 app/src/main/res/values-pl/strings.xml diff --git a/app/src/main/res/values-pl/plurals.xml b/app/src/main/res/values-pl/plurals.xml new file mode 100644 index 000000000..3682362dc --- /dev/null +++ b/app/src/main/res/values-pl/plurals.xml @@ -0,0 +1,43 @@ + + + + %1$d nowy rozdział + %1$d nowe rozdziały + %1$d nowych rozdziałów + + + %1$d minutę temu + %1$d minuty temu + %1$d minut temu + + + Łącznie %1$d strona + Łącznie %1$d strony + Łącznie %1$d stron + + + %1$d godzinę temu + %1$d godziny temu + %1$d godzin temu + + + %1$d dzień temu + %1$d dni temu + %1$d dni temu + + + %1$d przedmiot + %1$d przedmioty + %1$d przedmiotów + + + %1$d rozdział z %2$d + %1$d rozdziały z %2$d + %1$d rozdziałów z %2$d + + + %1$d rozdział + %1$d rozdziały + %1$d rozdziałów + + diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml new file mode 100644 index 000000000..8eaf3aab0 --- /dev/null +++ b/app/src/main/res/values-pl/strings.xml @@ -0,0 +1,397 @@ + + + Ulubione + Historia + Napotkano błąd + Szczegółowy + Rozdziały + Lista + Lista szczegółowa + Siatka + Tryb listy + Ustawienia + Ładowanie… + Rozdział %1$d z %2$d + Zamknij + Wyczyść historię + Dodaj + Zapisz + Udostępnij + Szukaj + Szukaj mang + Pobieranie… + Pobrano + Pobrane + Nazwa + Popularność + Najnowsze + Ocena + Filtry + Jasny + Ciemny + Strony + Wyczyść + Usuń + Udostępnij zdjęcie + Usuń + Brak opisu + Tryb czytania + Błąd sieci + Obliczanie… + Spróbuj ponownie + Nic nie znaleziono + Brak historii + Czytaj + Brak ulubionych + Dodaj do ulubionych + Nowa kategoria + Stwórz skrót + Udostępnij %s + Przetwarzanie… + Zaktualizowane + „%s” usunięte z historii + Zapisz stronę + Zapisano + Wibracje + Biblioteka + Ostatnie + Tryb czarny + Przygotowywanie… + Plik nieznaleziony + Wczoraj + Dawno temu + Grupa + Dzisiaj + Zaloguj + Dalej + Potwierdź + Witaj + Skończone + W trakcie + Zezwól + Proponowane + Włącz propozycje + Włączone + Wyłączone + Nigdy + Zawsze + Znajdź rozdział + %1$s%% + Wygląd + Schowaj + Synchronizacja + Synchronizuj swoje dane + Nazwa + Edytuj + Wyloguj + Cofnij + Wyślij + Planowane + Czytane + Czytane ponownie + Skończone + Pokaż wszystkie + Wybierz zakres + Wyczyść całą historię + Ostatnie 2 godziny + Historia wyczyszczona + Zarządzaj + Losowe + Puste + Lista zmian + Przeglądaj + Dostępne + Ustawienia + Źródło wyłączone + Kompaktowy + Błąd po stronie serwera (%1$d). Sprónuj ponownie później + Sieć niedostępna + Inne języki + Odrzuć + Jasność + Kontrast + Korekcja kolorów + %ss + Wyłącz + Automatyczne przewijanie + Brak rozdziałów + Tryb incognito + Pobieranie mangi + Usunięto z ulubionych + Wprowadź swój email aby kontynuować + Wykorzystana pamięć + Zapisane mangi + Brak zakładek + Możesz tworzyć zakładki w trakcie czytania mangi + Zakładki usunięte + Twoje ostatnio czytane mangi + Wyłącz wszystkie + Wyłącz optymalizację baterii + Autowykrywanie trybu czytania + Usunięte z historii + Dodano zakładkę + Usunięto zakładkę + Zakładki + Usuń zakładkę + Dodaj zakładkę + Brak ulubionych kategorii + Edytuj kategorię + Włącz powiadomienia + Wróć + Konto już istnieje + Anulowano + Zwolnienie pobierania + Brak rozdziałów w tej mandze + Różne języki + Tylko na Wi-Fi + Zawsze blokuj + Format daty + Gatunki + Znajdź gatunek + Czytaj więcej + Inne + Rozwiąż + Wymagane CAPTCHA + Cichy + Dotknij aby spróbować ponownie + Teraz + Przywrócone + Dopasuj do szerokości + Dopasuj do wysokości + Dopasuj do środka + Nowa kategoria + Brak nowych aktualizacji + Sprawdź dostępność aktualizacji + Sprawdzanie aktualizacji… + Wersja %s + O aplikacji + Kategorie… + Zmień nazwę + Usuń + Jest tu dosyć pusto… + Ulubione kategorie + Powiadomienie LED + Nowe rozdziały + Zamknij kartę + Otwórz kartę + Pamięć wewnętrzna + Tutaj będą wyświetlane Twoje mangi + Znajdź materiały do czytania w zakładce „Przeglądaj” + W tym miejscu pojawią się powiadomienia o nowych rozdziałach z mang które czytasz + Strony w pamięci podręcznej + Animacja przewracania strony + Inne rzeczy w pamięci podręcznej + Otwórz w przeglądarce + Numerowane strony + Powiadomienia + Dźwięk powiadomień + Ustawienia powiadomień + Zewnętrzne źródła + Motyw + Systemowy + Historia i pamięć podręczna + Wyczyść pamięć podręczną stron + Pamięć podręczna + B|kB|MB|GB|TB + Wielkość siatki + Szukaj na %s + Usuń mangę + Dalej + Nie pytaj ponownie + Anulowanie… + Błąd + Wyczyszczone + Pamięć wewnętrzna + Pamięć zewnętrzna + Domena + Sprawdź dostępność nowej wersji aplikacji + Nowa wersja aplikacji jest dostępna + Pokaż powiadomienie gdy nowa wersja jest dostępna + Ta manga ma %s. Zapisać wszystko? + Zapisz + Pobierz + Czytaj od początku + Usunąć kategorię „%s” z Twoich ulubionych? Wszystkie mangi w niej będą z niej usunięte. + Możesz użyć kategorii do organizowania swoich ulubionych. Kliknij «+» aby stworzyć kategorię + Najpierw coś zapisz + Niedostępne + Zapisz + Wszystkie ulubione + Pusta kategoria + Czytaj później + Aktualizacje + Nowa wersja: %s + Wielkość: %s + Czekanie na sieć… + Obróć ekran + Odśwież + Szukaj aktualizacji + Nie sprawdzaj + Wprowadź hasło + Złe hasło + Chroń aplikację + Pytaj o hasło przy starcie Kotatsu + Wprowadź ponownie hasło + Zużywa mniej prądu na ekranach AMOLED + Kopia zapasowa i przywracanie + Utwórz kopię zapasową danych + Przywróć z kopii zapasowej + 18+ + %1$d na %2$d włączone + Wprowadź nazwę kategorii + Standardowy + Webtoon + Ustawienia czytnika + Zmiana strony + Przyciski głośności + Uwaga + Dotknięcie krawędzi + Wyczyszczone + Tryb skalowania + Wyczyść ciasteczka + Wszystkie ciasteczka wyczyszczone + Szukaj tylko na %s + Przetłumacz tą aplikację + Tłumaczenie + Musisz wpisać nazwę + Dostępne źródła + Motyw dynamiczny + Tylko gesty + Brak dostępnej pamięci + Inny + Wyniki wyszukiwania + Szukaj podobnych + Wszystkie dane zostały przywrócone + Dane zostały przywrócone, ale z błędami + Od tyłu + Brak aktywnych pobrań + Domyślny + Polityka zrzutów ekranu + Wyklucz gatunki + Określ gatunki, których nie chcesz widzieć w sugestiach + Zalogowano jako %s + Wybierz języki, w których chcesz czytać mangi. Możesz zmienić to później w ustawieniach. + Zgłoś + Usuwanie danych + Nieważna domena + Zmień kolejność + Potwierdzenie wyjścia + %s - %s + Rozdz. %1$d/%2$d Str. %3$d/%4$d + Włącz Wi-Fi lub sieć komórkową, aby czytać mangę online + Importuj + Wybierz plik ZIP lub CBZ. + Uruchom ponownie + Wyczyść historię wyszukiwania + Ta operacja nie jest obsługiwana + Poczekaj na zakończenie ładowania… + Tryb sortowania + Treści + Nie można załadować listy gatunków + Wstrzymane + Porzucone + Użyj odcisku palca, jeśli jest dostępny + Mangi z Twoich ulubionych + Pokaż wskaźniki postępu czytania + Pokaż procent przeczytania w historii i ulubionych + Manga oznaczona jako NSFW nigdy nie zostanie dodana do historii, a Twoje postępy nie zostaną zapisane + DNS przez HTTPS + Tryb domyślny + Trwale wyczyścić całą historię czytania? + „%s” usunięte z pamięci lokalnej + Wyczyść tablicę aktualizacji + Tablica + Usunąć trwale „%s” z urządzenia? + Może to spowodować przeniesienie dużej ilości danych + Wyczyść pamięć podręczną miniatur + Spróbuj przeformułować zapytanie. + To co czytasz będzie wyświetlane tutaj + Znajdź to, co warto przeczytać, w menu bocznym. + Zapisz ze źródeł online lub zaimportuj pliki. + Folder pobranych + Aktualizacja tablicy rozpocznie się wkrótce + Niezgodne hasła + Nie można wyszukać aktualizacji + Od prawej do lewej + Trzymaj na starcie + Utwórz problem na GitHubie + Możesz utworzyć kopię zapasową swojej historii i ulubionych oraz przywrócić ją + Wybrana konfiguracja zostanie zapamiętana dla tej mangi + Sprawdzanie nowych rozdziałów: %1$d z %2$d + Wyczyść tablicę + Wyczyścić trwale całą historię aktualizacji? + Szukanie nowych rozdziałów + Zaloguj się, aby wyświetlić tę zawartość + Domyślnie: %s + …i jeszcze %1$d + Wprowadź hasło, aby uruchomić aplikację + Hasło musi mieć co najmniej 4 znaki + Trwale usunąć wszystkie ostatnie zapytania wyszukiwania? + Zapisano kopię zapasową + Systemy niektórych urządzeń inaczej się zachowują. Może to zakłócać wykonywanie zadań w tle. + W kolejce + Pobierz lub przeczytaj ten brakujący rozdział online. + Brak rozdziału + Komentarz + Temat na 4PDA + Uprawniony + Logowanie na %s nie jest obsługiwane + Zostaniesz wylogowany ze wszystkich źródeł + Wyklucz mangi NSFW z historii + Wykorzystane źródła + Stosuje motyw utworzony na podstawie schematu kolorów Twojej tapety + Importowanie mangi: %1$d z %2$d + Zablokuj na NSFW + Proponuj mangi na podstawie Twoich preferencji + Wszystkie dane są analizowane lokalnie na tym urządzeniu. Twoje dane osobowe nie są przekazywane do żadnych usług + Zacznij czytać mangę, a otrzymasz spersonalizowane sugestie + Nie proponuj mang NSFW + Zresetuj filtr + Ładuj wstępnie strony + Aktualizowanie sugestii + Trwale usunąć wybrane elementy z urządzenia? + Usuwanie zakończone + Pobrać wszystkie wybrane mangi i ich rozdziały? Może to zużyć dużo danych i pamięci. + Pobieranie równoległe + Pomaga uniknąć blokowania Twojego adresu IP + Przetwarzanie zapisanej mangi + Rozdziały zostaną usunięte w tle. Może to zająć trochę czasu + Wpisz swój adres e-mail, aby kontynuować + Dostępne są nowe źródła mang + Sprawdzaj dostępność nowych rozdziałów i informuj o nich + Będziesz otrzymywać powiadomienia o aktualizacjach mang, które czytasz + Nie będziesz otrzymywać powiadomień, ale nowe rozdziały będą podświetlane na listach + Śledzenie + Automatycznie wykryj, czy manga to webtoon + Pomaga w sprawdzaniu aktualizacji w tle + Coś poszło nie tak. Zgłoś błąd programistom, aby pomóc nam go naprawić. + Może pomóc w przypadku niektórych problemów. Wszystkie autoryzacje zostaną unieważnione + Brak źródeł mang + Włącz źródła mang do czytania mang online + Czy na pewno chcesz usunąć wybrane ulubione kategorie? Wszystkie w nich mangi zostaną usunięte i nie będzie można tego cofnąć. + Naciśnij ponownie Wstecz, aby wyjść + Naciśnij dwukrotnie przycisk Wstecz, aby wyjść z aplikacji + Usunięto z „%s” + Treść nie została znaleziona lub została usunięta + Dostępna aktualizacja aplikacji: %s + Pokaż pasek informacji w czytniku + Archiwum komiksów + Folder z obrazami + Importowanie mangi + Importowanie zakończone + Możesz usunąć oryginalny plik z pamięci, aby zaoszczędzić miejsce + Import rozpocznie się wkrótce + Wybrane ustawienia kolorów zostaną zapamiętane dla tej mangi + Pokaż ostatnie skróty do mang + Pokaż ostatnie mangi po długim naciśnięciu ikony aplikacji + Stuknięcie w prawą krawędź lub naciśnięcie prawego klawisza zawsze powoduje przejście do następnej strony + Ergonomiczne sterowanie czytnikiem + Zapisać czy odrzucić niezapisane zmiany? + Brak miejsca w urządzeniu + Pokaż suwak przełączania stron + Powiększanie webtoon + Zezwalaj na gest powiększania/pomniejszania w trybie webtoon (beta) + Wyczyść też informacje o nowych rozdziałach + Resetuj + Szczegóły błędu:<br><tt>%1$s</tt><br><br>1. Spróbuj <a href=%2$s>otworzyć mangę w przeglądarce internetowej</a> aby upewnić się, że jest dostępna w źródle<br>2. Jeśli jest dostępna, wyślij raport o błędzie do programistów. + diff --git a/app/src/main/res/xml/locales.xml b/app/src/main/res/xml/locales.xml index 77223ddc2..0e10b2cc8 100644 --- a/app/src/main/res/xml/locales.xml +++ b/app/src/main/res/xml/locales.xml @@ -15,6 +15,7 @@ + From 571b85dfd8eddb45f8300fa49b44cbd7598e75f8 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 4 Jan 2023 13:26:18 +0200 Subject: [PATCH 39/88] Fix fast scroller NPE --- .../kotatsu/base/ui/list/fastscroll/FastScroller.kt | 4 ++-- .../kotatsu/details/ui/adapter/ChaptersAdapter.kt | 7 ++++--- .../org/koitharu/kotatsu/history/ui/HistoryListAdapter.kt | 8 ++++---- .../org/koitharu/kotatsu/shelf/ui/adapter/ShelfAdapter.kt | 6 +++--- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/fastscroll/FastScroller.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/fastscroll/FastScroller.kt index 23c79d7a2..e5cb94dd4 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/fastscroll/FastScroller.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/fastscroll/FastScroller.kt @@ -516,6 +516,6 @@ class FastScroller @JvmOverloads constructor( interface SectionIndexer { - fun getSectionText(context: Context, position: Int): CharSequence + fun getSectionText(context: Context, position: Int): CharSequence? } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/adapter/ChaptersAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/adapter/ChaptersAdapter.kt index 766ffb0e3..7b91abef5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/adapter/ChaptersAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/adapter/ChaptersAdapter.kt @@ -42,7 +42,8 @@ class ChaptersAdapter( } } - override fun getSectionText(context: Context, position: Int): CharSequence { - return items[position].chapter.number.toString() + override fun getSectionText(context: Context, position: Int): CharSequence? { + val item = items.getOrNull(position) ?: return null + return item.chapter.number.toString() } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListAdapter.kt index b44f5db90..4f0805690 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListAdapter.kt @@ -14,14 +14,14 @@ class HistoryListAdapter( listener: MangaListListener ) : MangaListAdapter(coil, lifecycleOwner, listener), FastScroller.SectionIndexer { - override fun getSectionText(context: Context, position: Int): CharSequence { + override fun getSectionText(context: Context, position: Int): CharSequence? { val list = items for (i in (0..position).reversed()) { - val item = list[i] + val item = list.getOrNull(i) ?: continue if (item is DateTimeAgo) { return item.format(context.resources) } } - return "" + return null } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/shelf/ui/adapter/ShelfAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/shelf/ui/adapter/ShelfAdapter.kt index 691db99ac..1a19dbb17 100644 --- a/app/src/main/java/org/koitharu/kotatsu/shelf/ui/adapter/ShelfAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/shelf/ui/adapter/ShelfAdapter.kt @@ -46,9 +46,9 @@ class ShelfAdapter( .addDelegate(errorStateListAD(listener)) } - override fun getSectionText(context: Context, position: Int): CharSequence { - val item = items.getOrNull(position) as? ShelfSectionModel - return item?.getTitle(context.resources) ?: "" + override fun getSectionText(context: Context, position: Int): CharSequence? { + val item = items.getOrNull(position) as? ShelfSectionModel ?: return null + return item.getTitle(context.resources) } private class DiffCallback : DiffUtil.ItemCallback() { From f115031846179ed8aa5cf43cc1f8d216a8835a91 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 4 Jan 2023 14:39:36 +0200 Subject: [PATCH 40/88] Fix error handling in CoroutineIntentService --- .../koitharu/kotatsu/base/ui/CoroutineIntentService.kt | 3 +++ .../main/java/org/koitharu/kotatsu/core/zip/ZipOutput.kt | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/CoroutineIntentService.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/CoroutineIntentService.kt index 32c9c2904..e7b6fc6db 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/CoroutineIntentService.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/CoroutineIntentService.kt @@ -31,6 +31,9 @@ abstract class CoroutineIntentService : BaseService() { processIntent(startId, intent) } } + } catch (e: Throwable) { + e.printStackTraceDebug() + onError(startId, e) } finally { stopSelf(startId) } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/zip/ZipOutput.kt b/app/src/main/java/org/koitharu/kotatsu/core/zip/ZipOutput.kt index 4a3dd8ed5..fd38f1c04 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/zip/ZipOutput.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/zip/ZipOutput.kt @@ -52,10 +52,13 @@ class ZipOutput( return if (entryNames.add(entry.name)) { val zipEntry = ZipEntry(entry.name) output.putNextEntry(zipEntry) - other.getInputStream(entry).use { input -> - input.copyTo(output) + try { + other.getInputStream(entry).use { input -> + input.copyTo(output) + } + } finally { + output.closeEntry() } - output.closeEntry() true } else { false From 1493aa39a38e48d8314b605cdbe7e6dbefeaec92 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 4 Jan 2023 15:59:31 +0200 Subject: [PATCH 41/88] CookieJar implementation for non-WebView environment --- .../browser/cloudflare/CloudFlareClient.kt | 6 +- .../browser/cloudflare/CloudFlareDialog.kt | 6 +- .../org/koitharu/kotatsu/core/AppModule.kt | 17 +++- .../network/{ => cookies}/AndroidCookieJar.kt | 17 ++-- .../core/network/cookies/CookieWrapper.kt | 84 +++++++++++++++++ .../core/network/cookies/MutableCookieJar.kt | 17 ++++ .../network/cookies/PreferencesCookieJar.kt | 89 +++++++++++++++++++ .../core/parser/MangaLoaderContextImpl.kt | 14 +-- .../settings/HistorySettingsFragment.kt | 4 +- 9 files changed, 229 insertions(+), 25 deletions(-) rename app/src/main/java/org/koitharu/kotatsu/core/network/{ => cookies}/AndroidCookieJar.kt (73%) create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/network/cookies/CookieWrapper.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/network/cookies/MutableCookieJar.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/network/cookies/PreferencesCookieJar.kt diff --git a/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareClient.kt b/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareClient.kt index 264134e52..c6ad65f5f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareClient.kt +++ b/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareClient.kt @@ -4,12 +4,12 @@ import android.graphics.Bitmap import android.webkit.WebView import android.webkit.WebViewClient import okhttp3.HttpUrl.Companion.toHttpUrl -import org.koitharu.kotatsu.core.network.AndroidCookieJar +import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar private const val CF_CLEARANCE = "cf_clearance" class CloudFlareClient( - private val cookieJar: AndroidCookieJar, + private val cookieJar: MutableCookieJar, private val callback: CloudFlareCallback, private val targetUrl: String, ) : WebViewClient() { @@ -42,4 +42,4 @@ class CloudFlareClient( return cookieJar.loadForRequest(targetUrl.toHttpUrl()) .find { it.name == CF_CLEARANCE }?.value } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt b/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt index dc18898b3..c2359ad91 100644 --- a/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt @@ -12,13 +12,13 @@ import androidx.core.view.isInvisible import androidx.fragment.app.setFragmentResult import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject import org.koitharu.kotatsu.base.ui.AlertDialogFragment -import org.koitharu.kotatsu.core.network.AndroidCookieJar import org.koitharu.kotatsu.core.network.UserAgentInterceptor +import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.databinding.FragmentCloudflareBinding import org.koitharu.kotatsu.utils.ext.stringArgument import org.koitharu.kotatsu.utils.ext.withArgs +import javax.inject.Inject @AndroidEntryPoint class CloudFlareDialog : AlertDialogFragment(), CloudFlareCallback { @@ -27,7 +27,7 @@ class CloudFlareDialog : AlertDialogFragment(), Cloud private val pendingResult = Bundle(1) @Inject - lateinit var cookieJar: AndroidCookieJar + lateinit var cookieJar: MutableCookieJar override fun onInflateView( inflater: LayoutInflater, diff --git a/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt b/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt index b5cf78270..576e5f5a6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/AppModule.kt @@ -4,6 +4,7 @@ import android.app.Application import android.content.Context import android.provider.SearchRecentSuggestions import android.text.Html +import android.util.AndroidRuntimeException import androidx.collection.arraySetOf import androidx.room.InvalidationTracker import coil.ComponentRegistry @@ -25,6 +26,9 @@ import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.base.ui.util.ActivityRecreationHandle import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.network.* +import org.koitharu.kotatsu.core.network.cookies.AndroidCookieJar +import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar +import org.koitharu.kotatsu.core.network.cookies.PreferencesCookieJar import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.ShortcutsUpdater import org.koitharu.kotatsu.core.parser.MangaLoaderContextImpl @@ -52,7 +56,7 @@ import javax.inject.Singleton interface AppModule { @Binds - fun bindCookieJar(androidCookieJar: AndroidCookieJar): CookieJar + fun bindCookieJar(androidCookieJar: MutableCookieJar): CookieJar @Binds fun bindMangaLoaderContext(mangaLoaderContextImpl: MangaLoaderContextImpl): MangaLoaderContext @@ -62,6 +66,17 @@ interface AppModule { companion object { + @Provides + @Singleton + fun provideCookieJar( + @ApplicationContext context: Context + ): MutableCookieJar = try { + AndroidCookieJar() + } catch (e: AndroidRuntimeException) { + // WebView is not available + PreferencesCookieJar(context) + } + @Provides @Singleton fun provideOkHttpClient( diff --git a/app/src/main/java/org/koitharu/kotatsu/core/network/AndroidCookieJar.kt b/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/AndroidCookieJar.kt similarity index 73% rename from app/src/main/java/org/koitharu/kotatsu/core/network/AndroidCookieJar.kt rename to app/src/main/java/org/koitharu/kotatsu/core/network/cookies/AndroidCookieJar.kt index bb221d743..5b0c3d822 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/network/AndroidCookieJar.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/AndroidCookieJar.kt @@ -1,19 +1,17 @@ -package org.koitharu.kotatsu.core.network +package org.koitharu.kotatsu.core.network.cookies import android.webkit.CookieManager -import javax.inject.Inject -import javax.inject.Singleton +import androidx.annotation.WorkerThread +import okhttp3.Cookie +import okhttp3.HttpUrl import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine -import okhttp3.Cookie -import okhttp3.CookieJar -import okhttp3.HttpUrl -@Singleton -class AndroidCookieJar @Inject constructor() : CookieJar { +class AndroidCookieJar : MutableCookieJar { private val cookieManager = CookieManager.getInstance() + @WorkerThread override fun loadForRequest(url: HttpUrl): List { val rawCookie = cookieManager.getCookie(url.toString()) ?: return emptyList() return rawCookie.split(';').mapNotNull { @@ -21,6 +19,7 @@ class AndroidCookieJar @Inject constructor() : CookieJar { } } + @WorkerThread override fun saveFromResponse(url: HttpUrl, cookies: List) { if (cookies.isEmpty()) { return @@ -31,7 +30,7 @@ class AndroidCookieJar @Inject constructor() : CookieJar { } } - suspend fun clear() = suspendCoroutine { continuation -> + override suspend fun clear() = suspendCoroutine { continuation -> cookieManager.removeAllCookies(continuation::resume) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/CookieWrapper.kt b/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/CookieWrapper.kt new file mode 100644 index 000000000..6254d720b --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/CookieWrapper.kt @@ -0,0 +1,84 @@ +package org.koitharu.kotatsu.core.network.cookies + +import android.util.Base64 +import okhttp3.Cookie +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.ObjectInputStream +import java.io.ObjectOutputStream + + +class CookieWrapper( + val cookie: Cookie, +) { + + constructor(encodedString: String) : this( + ObjectInputStream(ByteArrayInputStream(Base64.decode(encodedString, Base64.NO_WRAP))).use { + val name = it.readUTF() + val value = it.readUTF() + val expiresAt = it.readLong() + val domain = it.readUTF() + val path = it.readUTF() + val secure = it.readBoolean() + val httpOnly = it.readBoolean() + val persistent = it.readBoolean() + val hostOnly = it.readBoolean() + Cookie.Builder().also { c -> + c.name(name) + c.value(value) + if (persistent) { + c.expiresAt(expiresAt) + } + if (hostOnly) { + c.hostOnlyDomain(domain) + } else { + c.domain(domain) + } + c.path(path) + if (secure) { + c.secure() + } + if (httpOnly) { + c.httpOnly() + } + }.build() + }, + ) + + fun encode(): String { + val output = ByteArrayOutputStream() + ObjectOutputStream(output).use { + it.writeUTF(cookie.name) + it.writeUTF(cookie.value) + it.writeLong(cookie.expiresAt) + it.writeUTF(cookie.domain) + it.writeUTF(cookie.path) + it.writeBoolean(cookie.secure) + it.writeBoolean(cookie.httpOnly) + it.writeBoolean(cookie.persistent) + it.writeBoolean(cookie.hostOnly) + } + return Base64.encodeToString(output.toByteArray(), Base64.NO_WRAP) + } + + fun isExpired() = cookie.expiresAt < System.currentTimeMillis() + + fun key(): String { + return (if (cookie.secure) "https" else "http") + "://" + cookie.domain + cookie.path + "|" + cookie.name + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as CookieWrapper + + if (cookie != other.cookie) return false + + return true + } + + override fun hashCode(): Int { + return cookie.hashCode() + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/MutableCookieJar.kt b/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/MutableCookieJar.kt new file mode 100644 index 000000000..9059e5a6f --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/MutableCookieJar.kt @@ -0,0 +1,17 @@ +package org.koitharu.kotatsu.core.network.cookies + +import androidx.annotation.WorkerThread +import okhttp3.Cookie +import okhttp3.CookieJar +import okhttp3.HttpUrl + +interface MutableCookieJar : CookieJar { + + @WorkerThread + override fun loadForRequest(url: HttpUrl): List + + @WorkerThread + override fun saveFromResponse(url: HttpUrl, cookies: List) + + suspend fun clear(): Boolean +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/PreferencesCookieJar.kt b/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/PreferencesCookieJar.kt new file mode 100644 index 000000000..cce51f827 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/network/cookies/PreferencesCookieJar.kt @@ -0,0 +1,89 @@ +package org.koitharu.kotatsu.core.network.cookies + +import android.content.Context +import androidx.annotation.WorkerThread +import androidx.collection.ArrayMap +import androidx.core.content.edit +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.Cookie +import okhttp3.HttpUrl +import org.koitharu.kotatsu.utils.ext.printStackTraceDebug + +private const val PREFS_NAME = "cookies" + +class PreferencesCookieJar( + context: Context, +) : MutableCookieJar { + + private val cache = ArrayMap() + private val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + private var isLoaded = false + + @WorkerThread + override fun loadForRequest(url: HttpUrl): List { + loadPersistent() + val expired = HashSet() + val result = ArrayList() + for ((key, cookie) in cache) { + if (cookie.isExpired()) { + expired += key + } else if (cookie.cookie.matches(url)) { + result += cookie.cookie + } + } + if (expired.isNotEmpty()) { + cache.removeAll(expired) + removePersistent(expired) + } + return result + } + + @WorkerThread + override fun saveFromResponse(url: HttpUrl, cookies: List) { + val wrapped = cookies.map { CookieWrapper(it) } + prefs.edit(commit = true) { + for (cookie in wrapped) { + val key = cookie.key() + cache[key] = cookie + if (cookie.cookie.persistent) { + putString(key, cookie.encode()) + } + } + } + } + + override suspend fun clear(): Boolean { + cache.clear() + withContext(Dispatchers.IO) { + prefs.edit(commit = true) { clear() } + } + return true + } + + @Synchronized + private fun loadPersistent() { + if (!isLoaded) { + val map = prefs.all + cache.ensureCapacity(map.size) + for ((k, v) in map) { + val cookie = try { + CookieWrapper(v as String) + } catch (e: Exception) { + e.printStackTraceDebug() + continue + } + cache[k] = cookie + } + isLoaded = true + } + } + + private fun removePersistent(keys: Collection) { + prefs.edit(commit = true) { + for (key in keys) { + remove(key) + } + } + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt index 1d4d9784f..4bf8e8b7b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt @@ -6,25 +6,25 @@ import android.util.Base64 import android.webkit.WebView import androidx.core.os.LocaleListCompat import dagger.hilt.android.qualifiers.ApplicationContext -import java.util.* -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.OkHttpClient -import org.koitharu.kotatsu.core.network.AndroidCookieJar +import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.core.prefs.SourceSettings import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.config.MangaSourceConfig import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.utils.ext.toList +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine @Singleton class MangaLoaderContextImpl @Inject constructor( override val httpClient: OkHttpClient, - override val cookieJar: AndroidCookieJar, + override val cookieJar: MutableCookieJar, @ApplicationContext private val androidContext: Context, ) : MangaLoaderContext() { diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt index 595d47caa..a51e26271 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt @@ -12,7 +12,7 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.launch import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BasePreferenceFragment -import org.koitharu.kotatsu.core.network.AndroidCookieJar +import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.core.os.ShortcutsUpdater import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.local.data.CacheDir @@ -41,7 +41,7 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach lateinit var shikimoriRepository: ShikimoriRepository @Inject - lateinit var cookieJar: AndroidCookieJar + lateinit var cookieJar: MutableCookieJar @Inject lateinit var shortcutsUpdater: ShortcutsUpdater From c8b6dc27b29d61013e0d28effcf4beb3aca75123 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 4 Jan 2023 17:39:06 +0200 Subject: [PATCH 42/88] Fix branch selection in reader --- .../main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index feb64b21b..d059e1325 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -313,7 +313,7 @@ class ReaderViewModel @AssistedInject constructor( } ?: ReaderState(manga, preselectedBranch) } - val branch = chapters[currentState.value?.chapterId ?: 0L].branch + val branch = chapters[currentState.value?.chapterId ?: 0L]?.branch mangaData.value = manga.filterChapters(branch) readerMode.postValue(mode) From bd692fc60cbae42eb18baa7f8210282d40c65abd Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 6 Jan 2023 08:04:05 +0200 Subject: [PATCH 43/88] Update dependencies --- .idea/kotlinc.xml | 2 +- app/build.gradle | 7 ++++--- build.gradle | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index dd185e22b..22dcb880f 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -4,6 +4,6 @@