Merge branch 'devel' into feature/shikimori

This commit is contained in:
Koitharu
2022-06-21 13:31:44 +03:00
247 changed files with 5766 additions and 2342 deletions

View File

@@ -10,7 +10,7 @@ import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class LifecycleAwareServiceConnection private constructor(
class LifecycleAwareServiceConnection(
private val host: Activity,
) : ServiceConnection, DefaultLifecycleObserver {
@@ -31,19 +31,15 @@ class LifecycleAwareServiceConnection private constructor(
super.onDestroy(owner)
host.unbindService(this)
}
}
companion object {
fun bindService(
host: Activity,
lifecycleOwner: LifecycleOwner,
service: Intent,
flags: Int,
): LifecycleAwareServiceConnection {
val connection = LifecycleAwareServiceConnection(host)
host.bindService(service, connection, flags)
lifecycleOwner.lifecycle.addObserver(connection)
return connection
}
}
fun Activity.bindServiceWithLifecycle(
owner: LifecycleOwner,
service: Intent,
flags: Int
): LifecycleAwareServiceConnection {
val connection = LifecycleAwareServiceConnection(this)
bindService(service, connection, flags)
owner.lifecycle.addObserver(connection)
return connection
}

View File

@@ -10,14 +10,18 @@ import android.net.Uri
import android.os.Build
import androidx.activity.result.ActivityResultLauncher
import androidx.core.app.ActivityOptionsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import androidx.work.CoroutineWorker
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
val Context.connectivityManager: ConnectivityManager
@@ -81,4 +85,11 @@ fun <T> SharedPreferences.observe(key: String, valueProducer: suspend () -> T):
emit(valueProducer())
}
}
}.distinctUntilChanged()
}.distinctUntilChanged()
fun Lifecycle.postDelayed(runnable: Runnable, delay: Long) {
coroutineScope.launch {
delay(delay)
runnable.run()
}
}

View File

@@ -3,10 +3,6 @@ package org.koitharu.kotatsu.utils.ext
import androidx.collection.ArraySet
import java.util.*
fun <T : Enum<T>> Array<T>.names() = Array(size) { i ->
this[i].name
}
fun <T> MutableList<T>.move(sourceIndex: Int, targetIndex: Int) {
if (sourceIndex <= targetIndex) {
Collections.rotate(subList(sourceIndex, targetIndex + 1), -1)

View File

@@ -3,15 +3,6 @@ package org.koitharu.kotatsu.utils.ext
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineExceptionHandler
import org.koitharu.kotatsu.BuildConfig
val IgnoreErrors
get() = CoroutineExceptionHandler { _, e ->
if (BuildConfig.DEBUG) {
e.printStackTrace()
}
}
val processLifecycleScope: LifecycleCoroutineScope
inline get() = ProcessLifecycleOwner.get().lifecycleScope

View File

@@ -0,0 +1,15 @@
package org.koitharu.kotatsu.utils.ext
import android.content.Context
import android.os.Build
import android.view.Display
import android.view.WindowManager
import androidx.core.content.getSystemService
val Context.displayCompat: Display?
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
display
} else {
@Suppress("DEPRECATION")
getSystemService<WindowManager>()?.defaultDisplay
}

View File

@@ -2,9 +2,11 @@ package org.koitharu.kotatsu.utils.ext
import android.os.Bundle
import android.os.Parcelable
import androidx.core.view.MenuProvider
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import java.io.Serializable
@@ -43,4 +45,8 @@ fun DialogFragment.showAllowStateLoss(manager: FragmentManager, tag: String?) {
if (!manager.isStateSaved) {
show(manager, tag)
}
}
fun Fragment.addMenuProvider(provider: MenuProvider) {
requireActivity().addMenuProvider(provider, viewLifecycleOwner, Lifecycle.State.RESUMED)
}

View File

@@ -4,6 +4,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.liveData
import kotlinx.coroutines.Deferred
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlinx.coroutines.flow.Flow

View File

@@ -3,12 +3,14 @@ package org.koitharu.kotatsu.utils.ext
import androidx.core.os.LocaleListCompat
import java.util.*
fun LocaleListCompat.toList(): List<Locale> = createList(size()) { i -> get(i) }
fun LocaleListCompat.getOrThrow(index: Int) = get(index) ?: throw kotlin.NoSuchElementException()
fun LocaleListCompat.toList(): List<Locale> = createList(size()) { i -> getOrThrow(i) }
operator fun LocaleListCompat.iterator() = object : Iterator<Locale> {
private var index = 0
override fun hasNext(): Boolean = index < size()
override fun next(): Locale = get(index++)
override fun next(): Locale = getOrThrow(index++)
}
inline fun <R, C : MutableCollection<in R>> LocaleListCompat.mapTo(
@@ -17,7 +19,7 @@ inline fun <R, C : MutableCollection<in R>> LocaleListCompat.mapTo(
): C {
val len = size()
for (i in 0 until len) {
val item = get(i)
val item = get(i) ?: continue
destination.add(block(item))
}
return destination

View File

@@ -2,4 +2,13 @@ package org.koitharu.kotatsu.utils.ext
inline fun String?.ifNullOrEmpty(defaultValue: () -> String): String {
return if (this.isNullOrEmpty()) defaultValue() else this
}
fun String.longHashCode(): Long {
var h = 1125899906842597L
val len: Int = this.length
for (i in 0 until len) {
h = 31 * h + this[i].code
}
return h
}

View File

@@ -3,7 +3,10 @@ package org.koitharu.kotatsu.utils.ext
import android.app.Activity
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
@@ -138,4 +141,19 @@ val RecyclerView.isScrolledToTop: Boolean
}
val holder = findViewHolderForAdapterPosition(0)
return holder != null && holder.itemView.top >= 0
}
}
fun <T : View> ViewGroup.findViewsByType(clazz: Class<T>): Sequence<T> {
if (childCount == 0) {
return emptySequence()
}
return sequence {
for (view in children) {
if (clazz.isInstance(view)) {
yield(clazz.cast(view)!!)
} else if (view is ViewGroup && view.childCount != 0) {
yieldAll(view.findViewsByType(clazz))
}
}
}
}