mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-11-17 22:03:50 +00:00
commit
8c08801460
24
CHANGELOG.md
24
CHANGELOG.md
@ -1,5 +1,29 @@
|
||||
# Changelog
|
||||
|
||||
## 0.5.10
|
||||
|
||||
* `Versions`
|
||||
* `Core KTX`: `1.3.2` -> `1.5.0`
|
||||
* `AndroidX Recycler`: `1.2.0` -> `1.2.1`
|
||||
* `AppCompat`: `1.2.0` -> `1.3.0`
|
||||
* `Android`
|
||||
* `RecyclerView`:
|
||||
* `data` of `RecyclerViewAdapter` became an abstract field
|
||||
* New function `RecyclerViewAdapter`
|
||||
* `Common`:
|
||||
* New extension `View#changeVisibility`
|
||||
* `Repos`:
|
||||
* `Common`:
|
||||
* `WriteOneToManyRepo` got new function `clearWithValue`
|
||||
* `Android`:
|
||||
* New extension `SQLiteDatabase#selectDistinct`
|
||||
* Fixes in `OneToManyAndroidRepo`
|
||||
* `Ktor`
|
||||
* `Server`
|
||||
* All elements in configurators became a `fun interface`
|
||||
* `Pagination`
|
||||
* New function `doForAllWithCurrentPaging`
|
||||
|
||||
## 0.5.9
|
||||
|
||||
* `Repos`
|
||||
|
@ -35,9 +35,9 @@ class ActionViewHolder(
|
||||
}
|
||||
|
||||
class ActionsRecyclerViewAdapter(
|
||||
data: List<AlertAction>,
|
||||
override val data: List<AlertAction>,
|
||||
private val dialogInterfaceGetter: () -> DialogInterface
|
||||
) : RecyclerViewAdapter<AlertAction>(data) {
|
||||
) : RecyclerViewAdapter<AlertAction>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder<AlertAction> = ActionViewHolder(
|
||||
parent, dialogInterfaceGetter
|
||||
)
|
||||
|
@ -1,12 +1,13 @@
|
||||
package dev.inmo.micro_utils.android.recyclerview
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
|
||||
abstract class RecyclerViewAdapter<T>(
|
||||
val data: List<T>
|
||||
): RecyclerView.Adapter<AbstractViewHolder<T>>() {
|
||||
abstract class RecyclerViewAdapter<T>: RecyclerView.Adapter<AbstractViewHolder<T>>() {
|
||||
protected abstract val data: List<T>
|
||||
|
||||
var emptyView: View? = null
|
||||
set(value) {
|
||||
field = value
|
||||
@ -66,3 +67,11 @@ abstract class RecyclerViewAdapter<T>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> RecyclerViewAdapter(
|
||||
data: List<T>,
|
||||
onCreateViewHolder: (parent: ViewGroup, viewType: Int) -> AbstractViewHolder<T>
|
||||
) = object : RecyclerViewAdapter<T>() {
|
||||
override val data: List<T> = data
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder<T> = onCreateViewHolder(parent, viewType)
|
||||
}
|
||||
|
@ -33,3 +33,15 @@ fun View.toggleVisibility(goneOnHide: Boolean = true) {
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
fun View.changeVisibility(show: Boolean = !isShown, goneOnHide: Boolean = true) {
|
||||
if (show) {
|
||||
if (goneOnHide) {
|
||||
gone()
|
||||
} else {
|
||||
hide()
|
||||
}
|
||||
} else {
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,9 @@ uuidVersion=0.3.0
|
||||
|
||||
# ANDROID
|
||||
|
||||
core_ktx_version=1.3.2
|
||||
androidx_recycler_version=1.2.0
|
||||
appcompat_version=1.2.0
|
||||
core_ktx_version=1.5.0
|
||||
androidx_recycler_version=1.2.1
|
||||
appcompat_version=1.3.0
|
||||
|
||||
android_minSdkVersion=19
|
||||
android_compileSdkVersion=30
|
||||
@ -45,5 +45,5 @@ dokka_version=1.4.32
|
||||
# Project data
|
||||
|
||||
group=dev.inmo
|
||||
version=0.5.9
|
||||
android_code_version=50
|
||||
version=0.5.10
|
||||
android_code_version=51
|
||||
|
@ -8,7 +8,7 @@ import kotlinx.serialization.Contextual
|
||||
data class ApplicationCachingHeadersConfigurator(
|
||||
private val elements: List<@Contextual Element>
|
||||
) : KtorApplicationConfigurator {
|
||||
interface Element { operator fun CachingHeaders.Configuration.invoke() }
|
||||
fun interface Element { operator fun CachingHeaders.Configuration.invoke() }
|
||||
|
||||
override fun Application.configure() {
|
||||
install(CachingHeaders) {
|
||||
|
@ -10,17 +10,18 @@ import kotlinx.serialization.Serializable
|
||||
class ApplicationRoutingConfigurator(
|
||||
private val elements: List<@Contextual Element>
|
||||
) : KtorApplicationConfigurator {
|
||||
interface Element { operator fun Route.invoke() }
|
||||
|
||||
override fun Application.configure() {
|
||||
try {
|
||||
feature(Routing)
|
||||
} catch (e: IllegalStateException) {
|
||||
install(Routing) {
|
||||
fun interface Element { operator fun Route.invoke() }
|
||||
private val rootInstaller = Element {
|
||||
elements.forEach {
|
||||
it.apply { invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun Application.configure() {
|
||||
featureOrNull(Routing) ?.apply {
|
||||
rootInstaller.apply { invoke() }
|
||||
} ?: install(Routing) {
|
||||
rootInstaller.apply { invoke() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import kotlinx.serialization.Contextual
|
||||
class ApplicationSessionsConfigurator(
|
||||
private val elements: List<@Contextual Element>
|
||||
) : KtorApplicationConfigurator {
|
||||
interface Element { operator fun Sessions.Configuration.invoke() }
|
||||
fun interface Element { operator fun Sessions.Configuration.invoke() }
|
||||
|
||||
override fun Application.configure() {
|
||||
install(Sessions) {
|
||||
|
@ -8,7 +8,7 @@ import kotlinx.serialization.Contextual
|
||||
class StatusPagesConfigurator(
|
||||
private val elements: List<@Contextual Element>
|
||||
) : KtorApplicationConfigurator {
|
||||
interface Element { operator fun StatusPages.Configuration.invoke() }
|
||||
fun interface Element { operator fun StatusPages.Configuration.invoke() }
|
||||
|
||||
override fun Application.configure() {
|
||||
install(StatusPages) {
|
||||
|
@ -33,3 +33,8 @@ suspend fun <T> doAllWithCurrentPaging(
|
||||
block
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun <T> doForAllWithCurrentPaging(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
block: suspend (Pagination) -> PaginationResult<T>
|
||||
) = doAllWithCurrentPaging(initialPagination, block)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.inmo.micro_utils.repos
|
||||
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithCurrentPaging
|
||||
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@ -47,6 +48,7 @@ interface WriteOneToManyKeyValueRepo<Key, Value> : Repo {
|
||||
suspend fun remove(toRemove: Map<Key, List<Value>>)
|
||||
|
||||
suspend fun clear(k: Key)
|
||||
suspend fun clearWithValue(v: Value)
|
||||
|
||||
suspend fun set(toSet: Map<Key, List<Value>>) {
|
||||
toSet.keys.forEach { key -> clear(key) }
|
||||
@ -87,7 +89,19 @@ suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.set(
|
||||
k: Key, vararg v: Value
|
||||
) = set(k, v.toList())
|
||||
|
||||
interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Value>, WriteOneToManyKeyValueRepo<Key, Value>
|
||||
interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Value>, WriteOneToManyKeyValueRepo<Key, Value> {
|
||||
override suspend fun clearWithValue(v: Value) {
|
||||
doWithPagination {
|
||||
val keysResult = keys(v, it)
|
||||
|
||||
if (keysResult.results.isNotEmpty()) {
|
||||
remove(keysResult.results.map { it to listOf(v) })
|
||||
}
|
||||
|
||||
keysResult.currentPageIfNotEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
typealias KeyValuesRepo<Key,Value> = OneToManyKeyValueRepo<Key, Value>
|
||||
|
||||
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
|
||||
|
@ -114,6 +114,7 @@ open class MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||
}
|
||||
|
||||
override suspend fun clear(k: FromKey) = to.clear(k.toOutKey())
|
||||
override suspend fun clearWithValue(v: FromValue) = to.clearWithValue(v.toOutValue())
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
|
@ -74,6 +74,19 @@ fun SQLiteDatabase.select(
|
||||
table, columns, selection, selectionArgs, groupBy, having, orderBy, limit
|
||||
)
|
||||
|
||||
fun SQLiteDatabase.selectDistinct(
|
||||
table: String,
|
||||
columns: Array<String>? = null,
|
||||
selection: String? = null,
|
||||
selectionArgs: Array<String>? = null,
|
||||
groupBy: String? = null,
|
||||
having: String? = null,
|
||||
orderBy: String? = null,
|
||||
limit: String? = null
|
||||
) = query(
|
||||
true, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit
|
||||
)
|
||||
|
||||
fun makePlaceholders(count: Int): String {
|
||||
return (0 until count).joinToString { "?" }
|
||||
}
|
||||
|
@ -3,10 +3,7 @@ package dev.inmo.micro_utils.repos.onetomany
|
||||
import android.database.sqlite.SQLiteOpenHelper
|
||||
import androidx.core.content.contentValuesOf
|
||||
import dev.inmo.micro_utils.common.mapNotNullA
|
||||
import dev.inmo.micro_utils.pagination.FirstPagePagination
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.pagination.createPaginationResult
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.pagination.utils.reverse
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -38,7 +35,9 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
override val onDataCleared: Flow<Key> = _onDataCleared.asSharedFlow()
|
||||
|
||||
private val idColumnName = "id"
|
||||
private val idColumnArray = arrayOf(idColumnName)
|
||||
private val valueColumnName = "value"
|
||||
private val valueColumnArray = arrayOf(valueColumnName)
|
||||
|
||||
init {
|
||||
helper.blockingWritableTransaction {
|
||||
@ -108,7 +107,7 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
}
|
||||
|
||||
override suspend fun contains(k: Key): Boolean = helper.blockingReadableTransaction {
|
||||
select(tableName, selection = "$idColumnName=?", selectionArgs = arrayOf(k.keyAsString()), limit = FirstPagePagination(1).limitClause()).use {
|
||||
select(tableName, selection = "$idColumnName=?", selectionArgs = arrayOf(k.keyAsString()), limit = firstPageWithOneElementPagination.limitClause()).use {
|
||||
it.count > 0
|
||||
}
|
||||
}
|
||||
@ -133,7 +132,7 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
}.toLong()
|
||||
|
||||
override suspend fun count(k: Key): Long = helper.blockingReadableTransaction {
|
||||
select(tableName, selection = "$idColumnName=?", selectionArgs = arrayOf(k.keyAsString()), limit = FirstPagePagination(1).limitClause()).use {
|
||||
selectDistinct(tableName, columns = valueColumnArray, selection = "$idColumnName=?", selectionArgs = arrayOf(k.keyAsString()), limit = FirstPagePagination(1).limitClause()).use {
|
||||
it.count
|
||||
}
|
||||
}.toLong()
|
||||
@ -143,10 +142,17 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
pagination: Pagination,
|
||||
reversed: Boolean
|
||||
): PaginationResult<Value> = count(k).let { count ->
|
||||
if (pagination.firstIndex >= count) {
|
||||
return@let emptyList<Value>().createPaginationResult(
|
||||
pagination,
|
||||
count
|
||||
)
|
||||
}
|
||||
val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
|
||||
helper.blockingReadableTransaction {
|
||||
select(
|
||||
tableName,
|
||||
valueColumnArray,
|
||||
selection = "$idColumnName=?",
|
||||
selectionArgs = arrayOf(k.keyAsString()),
|
||||
limit = resultPagination.limitClause()
|
||||
@ -169,10 +175,17 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
pagination: Pagination,
|
||||
reversed: Boolean
|
||||
): PaginationResult<Key> = count().let { count ->
|
||||
if (pagination.firstIndex >= count) {
|
||||
return@let emptyList<Key>().createPaginationResult(
|
||||
pagination,
|
||||
count
|
||||
)
|
||||
}
|
||||
val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
|
||||
helper.blockingReadableTransaction {
|
||||
select(
|
||||
selectDistinct(
|
||||
tableName,
|
||||
idColumnArray,
|
||||
limit = resultPagination.limitClause()
|
||||
).use { c ->
|
||||
mutableListOf<Key>().also {
|
||||
@ -196,8 +209,9 @@ class OneToManyAndroidRepo<Key, Value>(
|
||||
): PaginationResult<Key> = count().let { count ->
|
||||
val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
|
||||
helper.blockingReadableTransaction {
|
||||
select(
|
||||
selectDistinct(
|
||||
tableName,
|
||||
idColumnArray,
|
||||
selection = "$valueColumnName=?",
|
||||
selectionArgs = arrayOf(v.valueAsString()),
|
||||
limit = resultPagination.limitClause()
|
||||
|
@ -86,6 +86,12 @@ class MapWriteOneToManyKeyValueRepo<Key, Value>(
|
||||
override suspend fun clear(k: Key) {
|
||||
map.remove(k) ?.also { _onDataCleared.emit(k) }
|
||||
}
|
||||
|
||||
override suspend fun clearWithValue(v: Value) {
|
||||
map.forEach { (k, values) ->
|
||||
if (values.remove(v)) _onValueRemoved.emit(k to v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MapOneToManyKeyValueRepo<Key, Value>(
|
||||
|
@ -67,6 +67,15 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
||||
Unit.serializer(),
|
||||
)
|
||||
|
||||
override suspend fun clearWithValue(v: Value) = unifiedRequester.unipost(
|
||||
buildStandardUrl(
|
||||
baseUrl,
|
||||
clearWithValueRoute,
|
||||
),
|
||||
BodyPair(valueSerializer, v),
|
||||
Unit.serializer(),
|
||||
)
|
||||
|
||||
override suspend fun set(toSet: Map<Key, List<Value>>) = unifiedRequester.unipost(
|
||||
buildStandardUrl(
|
||||
baseUrl,
|
||||
|
@ -14,4 +14,5 @@ const val onDataClearedRoute = "onDataCleared"
|
||||
const val addRoute = "add"
|
||||
const val removeRoute = "remove"
|
||||
const val clearRoute = "clear"
|
||||
const val clearWithValueRoute = "clearWithValue"
|
||||
const val setRoute = "set"
|
@ -72,6 +72,17 @@ fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
|
||||
}
|
||||
}
|
||||
|
||||
post(clearWithValueRoute) {
|
||||
unifiedRouter.apply {
|
||||
val v = uniload(valueSerializer)
|
||||
|
||||
unianswer(
|
||||
Unit.serializer(),
|
||||
originalRepo.clearWithValue(v),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
post(setRoute) {
|
||||
unifiedRouter.apply {
|
||||
val obj = uniload(keyValueMapSerializer)
|
||||
|
Loading…
Reference in New Issue
Block a user