Compare commits

...

4 Commits

Author SHA1 Message Date
Koitharu
809e7d8701 Ability to check proxy connection 2024-08-12 18:22:05 +03:00
Koitharu
0015c5704a Fix ignoring external sources in global search 2024-08-12 17:30:21 +03:00
Koitharu
a7ff1610eb Fix crashes 2024-08-12 17:17:02 +03:00
Koitharu
22c402fc5e Update parers 2024-08-12 16:51:03 +03:00
8 changed files with 108 additions and 18 deletions

View File

@@ -16,8 +16,8 @@ android {
applicationId 'org.koitharu.kotatsu'
minSdk = 21
targetSdk = 35
versionCode = 658
versionName = '7.4.1'
versionCode = 659
versionName = '7.4.2'
generatedDensities = []
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
ksp {
@@ -82,7 +82,7 @@ afterEvaluate {
}
dependencies {
//noinspection GradleDependency
implementation('com.github.KotatsuApp:kotatsu-parsers:3b5a018f8c') {
implementation('com.github.KotatsuApp:kotatsu-parsers:ca212ca692') {
exclude group: 'org.json', module: 'json'
}
@@ -95,7 +95,7 @@ dependencies {
implementation 'androidx.activity:activity-ktx:1.9.1'
implementation 'androidx.fragment:fragment-ktx:1.8.2'
implementation 'androidx.transition:transition-ktx:1.5.1'
implementation 'androidx.collection:collection-ktx:1.4.2'
implementation 'androidx.collection:collection-ktx:1.4.3'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4'
implementation 'androidx.lifecycle:lifecycle-service:2.8.4'
implementation 'androidx.lifecycle:lifecycle-process:2.8.4'
@@ -109,7 +109,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-common-java8:2.8.4'
implementation 'androidx.webkit:webkit:1.11.0'
implementation 'androidx.work:work-runtime:2.9.0'
implementation 'androidx.work:work-runtime:2.9.1'
//noinspection GradleDependency
implementation('com.google.guava:guava:32.0.1-android') {
exclude group: 'com.google.guava', module: 'failureaccess'

View File

@@ -704,6 +704,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
const val KEY_LOGS_SHARE = "logs_share"
const val KEY_APP_UPDATE = "app_update"
const val KEY_APP_TRANSLATION = "about_app_translation"
const val PROXY_TEST = "proxy_test"
// old keys are for migration only
private const val KEY_IMAGES_PROXY_OLD = "images_proxy"

View File

@@ -61,7 +61,13 @@ class MangaSourcesRepository @Inject constructor(
suspend fun getEnabledSources(): List<MangaSource> {
assimilateNewSources()
val order = settings.sourcesSortOrder
return dao.findAllEnabled(order).toSources(settings.isNsfwContentDisabled, order)
return dao.findAllEnabled(order).toSources(settings.isNsfwContentDisabled, order).let { enabled ->
val external = getExternalSources()
val list = ArrayList<MangaSourceInfo>(enabled.size + external.size)
external.mapTo(list) { MangaSourceInfo(it, isEnabled = true, isPinned = true) }
list.addAll(enabled)
list
}
}
suspend fun getPinnedSources(): Set<MangaSource> {
@@ -308,8 +314,6 @@ class MangaSourcesRepository @Inject constructor(
}
private fun observeExternalSources(): Flow<List<ExternalMangaSource>> {
val intent = Intent("app.kotatsu.parser.PROVIDE_MANGA")
val pm = context.packageManager
return callbackFlow {
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
@@ -333,15 +337,19 @@ class MangaSourcesRepository @Inject constructor(
}.onStart {
emit(null)
}.map {
pm.queryIntentContentProviders(intent, 0).map { resolveInfo ->
ExternalMangaSource(
packageName = resolveInfo.providerInfo.packageName,
authority = resolveInfo.providerInfo.authority,
)
}
getExternalSources()
}.distinctUntilChanged()
}
private fun getExternalSources() = context.packageManager.queryIntentContentProviders(
Intent("app.kotatsu.parser.PROVIDE_MANGA"), 0,
).map { resolveInfo ->
ExternalMangaSource(
packageName = resolveInfo.providerInfo.packageName,
authority = resolveInfo.providerInfo.authority,
)
}
private fun List<MangaSourceEntity>.toSources(
skipNsfwSources: Boolean,
sortOrder: SourcesSortOrder?,

View File

@@ -176,8 +176,10 @@ class WebtoonScalingFrame @JvmOverloads constructor(
val targetChild = findTargetChild()
adjustBounds()
targetChild.run {
scaleX = scale
scaleY = scale
if (!scale.isNaN()) {
scaleX = scale
scaleY = scale
}
translationX = transX
translationY = transY
if (pendingScroll != 0) {
@@ -298,7 +300,7 @@ class WebtoonScalingFrame @JvmOverloads constructor(
distanceX: Float,
distanceY: Float,
): Boolean {
if (scale <= 1f) return false
if (scale <= 1f || scale.isNaN()) return false
transformMatrix.postTranslate(-distanceX, -distanceY)
invalidateTarget()
return true
@@ -323,7 +325,7 @@ class WebtoonScalingFrame @JvmOverloads constructor(
velocityX: Float,
velocityY: Float,
): Boolean {
if (scale <= 1) return false
if (scale <= 1 || scale.isNaN()) return false
prevPos.set(transX.toInt(), transY.toInt())
overScroller.fling(

View File

@@ -7,20 +7,40 @@ import android.view.inputmethod.EditorInfo
import androidx.preference.EditTextPreference
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.network.BaseHttpClient
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope
import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.settings.utils.EditTextBindListener
import org.koitharu.kotatsu.settings.utils.PasswordSummaryProvider
import org.koitharu.kotatsu.settings.utils.validation.DomainValidator
import org.koitharu.kotatsu.settings.utils.validation.PortNumberValidator
import java.net.Proxy
import javax.inject.Inject
import kotlin.coroutines.cancellation.CancellationException
@AndroidEntryPoint
class ProxySettingsFragment : BasePreferenceFragment(R.string.proxy),
SharedPreferences.OnSharedPreferenceChangeListener {
private var testJob: Job? = null
@Inject
@BaseHttpClient
lateinit var okHttpClient: OkHttpClient
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_proxy)
findPreference<EditTextPreference>(AppSettings.KEY_PROXY_ADDRESS)?.setOnBindEditTextListener(
@@ -60,6 +80,15 @@ class ProxySettingsFragment : BasePreferenceFragment(R.string.proxy),
super.onDestroyView()
}
override fun onPreferenceTreeClick(preference: Preference): Boolean = when (preference.key) {
AppSettings.PROXY_TEST -> {
testConnection()
true
}
else -> super.onPreferenceTreeClick(preference)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
when (key) {
AppSettings.KEY_PROXY_TYPE -> updateDependencies()
@@ -73,5 +102,47 @@ class ProxySettingsFragment : BasePreferenceFragment(R.string.proxy),
findPreference<PreferenceCategory>(AppSettings.KEY_PROXY_AUTH)?.isEnabled = isProxyEnabled
findPreference<Preference>(AppSettings.KEY_PROXY_LOGIN)?.isEnabled = isProxyEnabled
findPreference<Preference>(AppSettings.KEY_PROXY_PASSWORD)?.isEnabled = isProxyEnabled
findPreference<Preference>(AppSettings.PROXY_TEST)?.isEnabled = isProxyEnabled && testJob?.isActive != true
}
private fun testConnection() {
testJob?.cancel()
testJob = viewLifecycleScope.launch {
val pref = findPreference<Preference>(AppSettings.PROXY_TEST)
pref?.run {
setSummary(R.string.loading_)
isEnabled = false
}
try {
withContext(Dispatchers.Default) {
val request = Request.Builder()
.get()
.url("http://neverssl.com")
.build()
val response = okHttpClient.newCall(request).await()
check(response.isSuccessful) { response.message }
}
showTestResult(null)
} catch (e: CancellationException) {
throw e
} catch (e: Throwable) {
e.printStackTraceDebug()
showTestResult(e)
} finally {
pref?.run {
isEnabled = true
summary = null
}
}
}
}
private fun showTestResult(error: Throwable?) {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.proxy)
.setMessage(error?.getDisplayMessage(resources) ?: getString(R.string.connection_ok))
.setPositiveButton(android.R.string.ok, null)
.setCancelable(true)
.show()
}
}

View File

@@ -26,6 +26,7 @@ class UpdatesFragment : MangaListFragment() {
return when (item.itemId) {
R.id.action_remove -> {
viewModel.remove(controller.snapshot())
mode.finish()
true
}

View File

@@ -670,4 +670,5 @@
<string name="chapters_left">Chapters left</string>
<string name="external_source">External/plugin</string>
<string name="plugin_incompatible">Incompatible plugin or internal error. Make sure you are using the latest version of the plugin and Kotatsu</string>
<string name="connection_ok">Connection is OK</string>
</resources>

View File

@@ -36,4 +36,10 @@
</PreferenceCategory>
<Preference
android:key="proxy_test"
android:persistent="false"
android:title="Test connection"
app:allowDividerAbove="true" />
</PreferenceScreen>