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 # 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 ## 0.5.9
* `Repos` * `Repos`

View File

@ -35,9 +35,9 @@ class ActionViewHolder(
} }
class ActionsRecyclerViewAdapter( class ActionsRecyclerViewAdapter(
data: List<AlertAction>, override val data: List<AlertAction>,
private val dialogInterfaceGetter: () -> DialogInterface private val dialogInterfaceGetter: () -> DialogInterface
) : RecyclerViewAdapter<AlertAction>(data) { ) : RecyclerViewAdapter<AlertAction>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder<AlertAction> = ActionViewHolder( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder<AlertAction> = ActionViewHolder(
parent, dialogInterfaceGetter parent, dialogInterfaceGetter
) )

View File

@ -1,12 +1,13 @@
package dev.inmo.micro_utils.android.recyclerview package dev.inmo.micro_utils.android.recyclerview
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
abstract class RecyclerViewAdapter<T>( abstract class RecyclerViewAdapter<T>: RecyclerView.Adapter<AbstractViewHolder<T>>() {
val data: List<T> protected abstract val data: List<T>
): RecyclerView.Adapter<AbstractViewHolder<T>>() {
var emptyView: View? = null var emptyView: View? = null
set(value) { set(value) {
field = 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() 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 # ANDROID
core_ktx_version=1.3.2 core_ktx_version=1.5.0
androidx_recycler_version=1.2.0 androidx_recycler_version=1.2.1
appcompat_version=1.2.0 appcompat_version=1.3.0
android_minSdkVersion=19 android_minSdkVersion=19
android_compileSdkVersion=30 android_compileSdkVersion=30
@ -45,5 +45,5 @@ dokka_version=1.4.32
# Project data # Project data
group=dev.inmo group=dev.inmo
version=0.5.9 version=0.5.10
android_code_version=50 android_code_version=51

View File

@ -8,7 +8,7 @@ import kotlinx.serialization.Contextual
data class ApplicationCachingHeadersConfigurator( data class ApplicationCachingHeadersConfigurator(
private val elements: List<@Contextual Element> private val elements: List<@Contextual Element>
) : KtorApplicationConfigurator { ) : KtorApplicationConfigurator {
interface Element { operator fun CachingHeaders.Configuration.invoke() } fun interface Element { operator fun CachingHeaders.Configuration.invoke() }
override fun Application.configure() { override fun Application.configure() {
install(CachingHeaders) { install(CachingHeaders) {

View File

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

View File

@ -8,7 +8,7 @@ import kotlinx.serialization.Contextual
class ApplicationSessionsConfigurator( class ApplicationSessionsConfigurator(
private val elements: List<@Contextual Element> private val elements: List<@Contextual Element>
) : KtorApplicationConfigurator { ) : KtorApplicationConfigurator {
interface Element { operator fun Sessions.Configuration.invoke() } fun interface Element { operator fun Sessions.Configuration.invoke() }
override fun Application.configure() { override fun Application.configure() {
install(Sessions) { install(Sessions) {

View File

@ -8,7 +8,7 @@ import kotlinx.serialization.Contextual
class StatusPagesConfigurator( class StatusPagesConfigurator(
private val elements: List<@Contextual Element> private val elements: List<@Contextual Element>
) : KtorApplicationConfigurator { ) : KtorApplicationConfigurator {
interface Element { operator fun StatusPages.Configuration.invoke() } fun interface Element { operator fun StatusPages.Configuration.invoke() }
override fun Application.configure() { override fun Application.configure() {
install(StatusPages) { install(StatusPages) {

View File

@ -33,3 +33,8 @@ suspend fun <T> doAllWithCurrentPaging(
block 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 package dev.inmo.micro_utils.repos
import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.doForAllWithCurrentPaging
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -47,6 +48,7 @@ interface WriteOneToManyKeyValueRepo<Key, Value> : Repo {
suspend fun remove(toRemove: Map<Key, List<Value>>) suspend fun remove(toRemove: Map<Key, List<Value>>)
suspend fun clear(k: Key) suspend fun clear(k: Key)
suspend fun clearWithValue(v: Value)
suspend fun set(toSet: Map<Key, List<Value>>) { suspend fun set(toSet: Map<Key, List<Value>>) {
toSet.keys.forEach { key -> clear(key) } toSet.keys.forEach { key -> clear(key) }
@ -87,7 +89,19 @@ suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.set(
k: Key, vararg v: Value k: Key, vararg v: Value
) = set(k, v.toList()) ) = 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> typealias KeyValuesRepo<Key,Value> = OneToManyKeyValueRepo<Key, Value>
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove( 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 clear(k: FromKey) = to.clear(k.toOutKey())
override suspend fun clearWithValue(v: FromValue) = to.clearWithValue(v.toOutValue())
} }
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")

View File

@ -74,6 +74,19 @@ fun SQLiteDatabase.select(
table, columns, selection, selectionArgs, groupBy, having, orderBy, limit 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 { fun makePlaceholders(count: Int): String {
return (0 until count).joinToString { "?" } return (0 until count).joinToString { "?" }
} }

View File

@ -3,10 +3,7 @@ package dev.inmo.micro_utils.repos.onetomany
import android.database.sqlite.SQLiteOpenHelper import android.database.sqlite.SQLiteOpenHelper
import androidx.core.content.contentValuesOf import androidx.core.content.contentValuesOf
import dev.inmo.micro_utils.common.mapNotNullA import dev.inmo.micro_utils.common.mapNotNullA
import dev.inmo.micro_utils.pagination.FirstPagePagination import dev.inmo.micro_utils.pagination.*
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.utils.reverse import dev.inmo.micro_utils.pagination.utils.reverse
import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -38,7 +35,9 @@ class OneToManyAndroidRepo<Key, Value>(
override val onDataCleared: Flow<Key> = _onDataCleared.asSharedFlow() override val onDataCleared: Flow<Key> = _onDataCleared.asSharedFlow()
private val idColumnName = "id" private val idColumnName = "id"
private val idColumnArray = arrayOf(idColumnName)
private val valueColumnName = "value" private val valueColumnName = "value"
private val valueColumnArray = arrayOf(valueColumnName)
init { init {
helper.blockingWritableTransaction { helper.blockingWritableTransaction {
@ -108,7 +107,7 @@ class OneToManyAndroidRepo<Key, Value>(
} }
override suspend fun contains(k: Key): Boolean = helper.blockingReadableTransaction { 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 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( select(
tableName tableName
).use { ).use {
@ -133,7 +132,7 @@ class OneToManyAndroidRepo<Key, Value>(
}.toLong() }.toLong()
override suspend fun count(k: Key): Long = helper.blockingReadableTransaction { 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 it.count
} }
}.toLong() }.toLong()
@ -143,10 +142,17 @@ class OneToManyAndroidRepo<Key, Value>(
pagination: Pagination, pagination: Pagination,
reversed: Boolean reversed: Boolean
): PaginationResult<Value> = count(k).let { count -> ): 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 } val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
helper.blockingReadableTransaction { helper.blockingReadableTransaction {
select( select(
tableName, tableName,
valueColumnArray,
selection = "$idColumnName=?", selection = "$idColumnName=?",
selectionArgs = arrayOf(k.keyAsString()), selectionArgs = arrayOf(k.keyAsString()),
limit = resultPagination.limitClause() limit = resultPagination.limitClause()
@ -169,10 +175,17 @@ class OneToManyAndroidRepo<Key, Value>(
pagination: Pagination, pagination: Pagination,
reversed: Boolean reversed: Boolean
): PaginationResult<Key> = count().let { count -> ): 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 } val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
helper.blockingReadableTransaction { helper.blockingReadableTransaction {
select( selectDistinct(
tableName, tableName,
idColumnArray,
limit = resultPagination.limitClause() limit = resultPagination.limitClause()
).use { c -> ).use { c ->
mutableListOf<Key>().also { mutableListOf<Key>().also {
@ -196,8 +209,9 @@ class OneToManyAndroidRepo<Key, Value>(
): PaginationResult<Key> = count().let { count -> ): PaginationResult<Key> = count().let { count ->
val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination } val resultPagination = pagination.let { if (reversed) pagination.reverse(count) else pagination }
helper.blockingReadableTransaction { helper.blockingReadableTransaction {
select( selectDistinct(
tableName, tableName,
idColumnArray,
selection = "$valueColumnName=?", selection = "$valueColumnName=?",
selectionArgs = arrayOf(v.valueAsString()), selectionArgs = arrayOf(v.valueAsString()),
limit = resultPagination.limitClause() limit = resultPagination.limitClause()

View File

@ -86,6 +86,12 @@ class MapWriteOneToManyKeyValueRepo<Key, Value>(
override suspend fun clear(k: Key) { override suspend fun clear(k: Key) {
map.remove(k) ?.also { _onDataCleared.emit(k) } 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>( class MapOneToManyKeyValueRepo<Key, Value>(

View File

@ -67,6 +67,15 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
Unit.serializer(), 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( override suspend fun set(toSet: Map<Key, List<Value>>) = unifiedRequester.unipost(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
@ -75,4 +84,4 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
BodyPair(keyValueMapSerializer, toSet), BodyPair(keyValueMapSerializer, toSet),
Unit.serializer(), Unit.serializer(),
) )
} }

View File

@ -14,4 +14,5 @@ const val onDataClearedRoute = "onDataCleared"
const val addRoute = "add" const val addRoute = "add"
const val removeRoute = "remove" const val removeRoute = "remove"
const val clearRoute = "clear" 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) { post(setRoute) {
unifiedRouter.apply { unifiedRouter.apply {
val obj = uniload(keyValueMapSerializer) val obj = uniload(keyValueMapSerializer)