Merge pull request #74 from InsanusMokrassar/0.5.10

0.5.10
This commit is contained in:
InsanusMokrassar 2021-06-15 14:38:26 +06:00 committed by GitHub
commit 8c08801460
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 154 additions and 34 deletions

View File

@ -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`

View File

@ -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
)

View File

@ -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)
}

View File

@ -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()
}
}

View File

@ -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

View File

@ -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) {

View File

@ -10,17 +10,18 @@ import kotlinx.serialization.Serializable
class ApplicationRoutingConfigurator(
private val elements: List<@Contextual Element>
) : KtorApplicationConfigurator {
interface Element { operator fun Route.invoke() }
fun interface Element { operator fun Route.invoke() }
private val rootInstaller = Element {
elements.forEach {
it.apply { invoke() }
}
}
override fun Application.configure() {
try {
feature(Routing)
} catch (e: IllegalStateException) {
install(Routing) {
elements.forEach {
it.apply { invoke() }
}
}
featureOrNull(Routing) ?.apply {
rootInstaller.apply { invoke() }
} ?: install(Routing) {
rootInstaller.apply { invoke() }
}
}
}

View File

@ -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) {

View File

@ -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) {

View File

@ -33,3 +33,8 @@ suspend fun <T> doAllWithCurrentPaging(
block
)
}
suspend fun <T> doForAllWithCurrentPaging(
initialPagination: Pagination = FirstPagePagination(),
block: suspend (Pagination) -> PaginationResult<T>
) = doAllWithCurrentPaging(initialPagination, block)

View File

@ -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(

View File

@ -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")

View File

@ -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 { "?" }
}

View File

@ -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
}
}
@ -124,7 +123,7 @@ class OneToManyAndroidRepo<Key, Value>(
}
}
override suspend fun count(): Long =helper.blockingReadableTransaction {
override suspend fun count(): Long = helper.blockingReadableTransaction {
select(
tableName
).use {
@ -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()

View File

@ -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>(

View File

@ -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,
@ -75,4 +84,4 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
BodyPair(keyValueMapSerializer, toSet),
Unit.serializer(),
)
}
}

View File

@ -14,4 +14,5 @@ const val onDataClearedRoute = "onDataCleared"
const val addRoute = "add"
const val removeRoute = "remove"
const val clearRoute = "clear"
const val setRoute = "set"
const val clearWithValueRoute = "clearWithValue"
const val setRoute = "set"

View File

@ -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)