Merge branch 'devel' into feature/nextgen
# Conflicts: # app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.preference.Preference
|
||||
import coil.target.Target
|
||||
|
||||
class PreferenceIconTarget(
|
||||
private val preference: Preference,
|
||||
) : Target {
|
||||
|
||||
override fun onError(error: Drawable?) {
|
||||
preference.icon = error
|
||||
}
|
||||
|
||||
override fun onStart(placeholder: Drawable?) {
|
||||
preference.icon = placeholder
|
||||
}
|
||||
|
||||
override fun onSuccess(result: Drawable) {
|
||||
preference.icon = result
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ class ScreenOrientationHelper(private val activity: Activity) {
|
||||
isLandscape = !isLandscape
|
||||
}
|
||||
|
||||
fun observeAutoOrientation() = callbackFlow<Boolean> {
|
||||
fun observeAutoOrientation() = callbackFlow {
|
||||
val observer = object : ContentObserver(Handler(activity.mainLooper)) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
trySendBlocking(isAutoRotationEnabled)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.graphics.Color
|
||||
import android.net.ConnectivityManager
|
||||
@@ -15,7 +16,14 @@ import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.coroutineScope
|
||||
import androidx.work.CoroutineWorker
|
||||
import com.google.android.material.elevation.ElevationOverlayProvider
|
||||
import kotlin.coroutines.resume
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.channels.trySendBlocking
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import org.koitharu.kotatsu.utils.InternalResourceHelper
|
||||
@@ -65,6 +73,25 @@ fun <I> ActivityResultLauncher<I>.tryLaunch(input: I, options: ActivityOptionsCo
|
||||
}.isSuccess
|
||||
}
|
||||
|
||||
fun SharedPreferences.observe() = callbackFlow<String> {
|
||||
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
||||
trySendBlocking(key)
|
||||
}
|
||||
registerOnSharedPreferenceChangeListener(listener)
|
||||
awaitClose {
|
||||
unregisterOnSharedPreferenceChangeListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> SharedPreferences.observe(key: String, valueProducer: suspend () -> T): Flow<T> = flow {
|
||||
emit(valueProducer())
|
||||
observe().collect { upstreamKey ->
|
||||
if (upstreamKey == key) {
|
||||
emit(valueProducer())
|
||||
}
|
||||
}
|
||||
}.distinctUntilChanged()
|
||||
|
||||
fun Lifecycle.postDelayed(runnable: Runnable, delay: Long) {
|
||||
coroutineScope.launch {
|
||||
delay(delay)
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.google.android.material.progressindicator.BaseProgressIndicator
|
||||
import org.koitharu.kotatsu.core.network.CommonHeaders
|
||||
import org.koitharu.kotatsu.utils.progress.ImageRequestIndicatorListener
|
||||
|
||||
fun ImageView.newImageRequest(url: String) = ImageRequest.Builder(context)
|
||||
fun ImageView.newImageRequest(url: String?) = ImageRequest.Builder(context)
|
||||
.data(url)
|
||||
.crossfade(true)
|
||||
.target(this)
|
||||
|
||||
@@ -34,4 +34,13 @@ fun <T> List<T>.asArrayList(): ArrayList<T> = if (this is ArrayList<*>) {
|
||||
this as ArrayList<T>
|
||||
} else {
|
||||
ArrayList(this)
|
||||
}
|
||||
|
||||
fun <K, V> Map<K, V>.findKey(value: V): K? {
|
||||
for ((k, v) in entries) {
|
||||
if (v == value) {
|
||||
return k
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
10
app/src/main/java/org/koitharu/kotatsu/utils/ext/HttpExt.kt
Normal file
10
app/src/main/java/org/koitharu/kotatsu/utils/ext/HttpExt.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.json.JSONObject
|
||||
|
||||
private val TYPE_JSON = "application/json".toMediaType()
|
||||
|
||||
fun JSONObject.toRequestBody() = toString().toRequestBody(TYPE_JSON)
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.graphics.Insets
|
||||
|
||||
fun Insets.getStart(view: View): Int {
|
||||
return if (view.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
|
||||
right
|
||||
} else {
|
||||
left
|
||||
}
|
||||
}
|
||||
|
||||
fun Insets.getEnd(view: View): Int {
|
||||
return if (view.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
|
||||
left
|
||||
} else {
|
||||
right
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,11 @@ import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.liveData
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.koitharu.kotatsu.utils.BufferedObserver
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.koitharu.kotatsu.utils.BufferedObserver
|
||||
|
||||
fun <T> LiveData<T?>.observeNotNull(owner: LifecycleOwner, observer: Observer<T>) {
|
||||
this.observe(owner) {
|
||||
@@ -18,6 +18,10 @@ fun <T> LiveData<T?>.observeNotNull(owner: LifecycleOwner, observer: Observer<T>
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> LiveData<T>.requireValue(): T = checkNotNull(value) {
|
||||
"LiveData value is null"
|
||||
}
|
||||
|
||||
fun <T> LiveData<T>.observeWithPrevious(owner: LifecycleOwner, observer: BufferedObserver<T>) {
|
||||
var previous: T? = null
|
||||
this.observe(owner) {
|
||||
@@ -26,6 +30,7 @@ fun <T> LiveData<T>.observeWithPrevious(owner: LifecycleOwner, observer: Buffere
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Use variant with default value")
|
||||
fun <T> Flow<T>.asLiveDataDistinct(
|
||||
context: CoroutineContext = EmptyCoroutineContext
|
||||
): LiveData<T> = liveData(context) {
|
||||
@@ -36,6 +41,10 @@ fun <T> Flow<T>.asLiveDataDistinct(
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> StateFlow<T>.asLiveDataDistinct(
|
||||
context: CoroutineContext = EmptyCoroutineContext
|
||||
): LiveData<T> = asLiveDataDistinct(context, value)
|
||||
|
||||
fun <T> Flow<T>.asLiveDataDistinct(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
defaultValue: T
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.res.Resources
|
||||
import okio.FileNotFoundException
|
||||
import org.acra.ACRA
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
|
||||
import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException
|
||||
import org.koitharu.kotatsu.core.exceptions.WrongPasswordException
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import java.io.FileNotFoundException
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import java.net.SocketTimeoutException
|
||||
|
||||
fun Throwable.getDisplayMessage(resources: Resources) = when (this) {
|
||||
is AuthRequiredException -> resources.getString(R.string.auth_required)
|
||||
is CloudFlareProtectedException -> resources.getString(R.string.captcha_required)
|
||||
is ActivityNotFoundException,
|
||||
is UnsupportedOperationException -> resources.getString(R.string.operation_not_supported)
|
||||
is UnsupportedFileException -> resources.getString(R.string.text_file_not_supported)
|
||||
is FileNotFoundException -> resources.getString(R.string.file_not_found)
|
||||
@@ -20,4 +24,6 @@ fun Throwable.getDisplayMessage(resources: Resources) = when (this) {
|
||||
is SocketTimeoutException -> resources.getString(R.string.network_error)
|
||||
is WrongPasswordException -> resources.getString(R.string.wrong_password)
|
||||
else -> localizedMessage ?: resources.getString(R.string.error_occurred)
|
||||
}
|
||||
}
|
||||
|
||||
fun ACRA.setCurrentManga(manga: Manga?) = errorReporter.putCustomData("manga", manga?.publicUrl.toString())
|
||||
@@ -5,8 +5,6 @@ import android.graphics.Rect
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.TooltipCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
Reference in New Issue
Block a user