Reduce memory usage

This commit is contained in:
Koitharu
2020-10-18 20:11:08 +03:00
parent 56e145420c
commit a8c22de601
21 changed files with 109 additions and 60 deletions

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.core.db.entity
import androidx.room.Embedded
import androidx.room.Junction
import androidx.room.Relation
import org.koitharu.kotatsu.utils.ext.mapToSet
data class MangaWithTags(
@Embedded val manga: MangaEntity,
@@ -14,7 +15,7 @@ data class MangaWithTags(
val tags: List<TagEntity>
) {
fun toManga() = manga.toManga(tags.map {
fun toManga() = manga.toManga(tags.mapToSet {
it.toMangaTag()
}.toSet())
})
}

View File

@@ -4,6 +4,7 @@ import androidx.room.Embedded
import androidx.room.Junction
import androidx.room.Relation
import org.koitharu.kotatsu.core.model.TrackingLogItem
import org.koitharu.kotatsu.utils.ext.mapToSet
import java.util.*
data class TrackLogWithManga(
@@ -24,7 +25,7 @@ data class TrackLogWithManga(
fun toTrackingLogItem() = TrackingLogItem(
id = trackLog.id,
chapters = trackLog.chapters.split('\n').filterNot { x -> x.isEmpty() },
manga = manga.toManga(tags.map { x -> x.toMangaTag() }.toSet()),
manga = manga.toManga(tags.mapToSet { x -> x.toMangaTag() }),
createdAt = Date(trackLog.createdAt)
)
}

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.arraySetOf
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
@@ -13,7 +14,11 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
protected abstract val defaultDomain: String
override val sortOrders = setOf(SortOrder.NEWEST, SortOrder.POPULARITY, SortOrder.ALPHABETICAL)
override val sortOrders = arraySetOf(
SortOrder.NEWEST,
SortOrder.POPULARITY,
SortOrder.ALPHABETICAL
)
override suspend fun getList(
offset: Int,
@@ -51,13 +56,13 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
coverUrl = row.selectFirst("div.manga_images")?.selectFirst("img")
?.attr("src")?.withDomain(domain).orEmpty(),
tags = safe {
row.selectFirst("div.genre")?.select("a")?.map {
row.selectFirst("div.genre")?.select("a")?.mapToSet {
MangaTag(
title = it.text(),
key = it.attr("href").substringAfterLast('/').urlEncoded(),
source = source
)
}?.toSet()
}
}.orEmpty(),
source = source
)
@@ -118,17 +123,17 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
val doc = loaderContext.httpGet("https://$domain/catalog").parseHtml()
val root = doc.body().selectFirst("div.main_fon").getElementById("side")
.select("ul").last()
return root.select("li.sidetag").map { li ->
return root.select("li.sidetag").mapToSet { li ->
val a = li.children().last()
MangaTag(
title = a.text().capitalize(),
key = a.attr("href").substringAfterLast('/'),
source = source
)
}.toSet()
}
}
override fun onCreatePreferences() = setOf(R.string.key_parser_domain)
override fun onCreatePreferences() = arraySetOf(R.string.key_parser_domain)
private fun getSortKey(sortOrder: SortOrder?) =
when (sortOrder ?: sortOrders.minByOrNull { it.ordinal }) {

View File

@@ -1,20 +1,18 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.arraySetOf
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.map
import org.koitharu.kotatsu.utils.ext.mapIndexed
import org.koitharu.kotatsu.utils.ext.parseHtml
import org.koitharu.kotatsu.utils.ext.parseJson
import org.koitharu.kotatsu.utils.ext.*
class DesuMeRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepository(loaderContext) {
override val source = MangaSource.DESUME
override val sortOrders = setOf(
override val sortOrders = arraySetOf(
SortOrder.UPDATED,
SortOrder.POPULARITY,
SortOrder.NEWEST,
@@ -76,13 +74,13 @@ class DesuMeRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepositor
val json = loaderContext.httpGet(url).parseJson().getJSONObject("response")
?: throw ParseException("Invalid response")
return manga.copy(
tags = json.getJSONArray("genres").map {
tags = json.getJSONArray("genres").mapToSet {
MangaTag(
key = it.getString("text"),
title = it.getString("russian"),
source = manga.source
)
}.toSet(),
},
description = json.getString("description"),
chapters = json.getJSONObject("chapters").getJSONArray("list").mapIndexed { i, it ->
val chid = it.getLong("id")
@@ -113,16 +111,16 @@ class DesuMeRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepositor
val domain = conf.getDomain(DOMAIN)
val doc = loaderContext.httpGet("https://$domain/manga/").parseHtml()
val root = doc.body().getElementById("animeFilter").selectFirst(".catalog-genres")
return root.select("li").map {
return root.select("li").mapToSet {
MangaTag(
source = source,
key = it.selectFirst("input").attr("data-genre"),
title = it.selectFirst("label").text()
)
}.toSet()
}
}
override fun onCreatePreferences() = setOf(R.string.key_parser_domain)
override fun onCreatePreferences() = arraySetOf(R.string.key_parser_domain)
private fun getSortKey(sortOrder: SortOrder?) =
when (sortOrder) {

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.arraySetOf
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
@@ -12,7 +13,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
protected abstract val defaultDomain: String
override val sortOrders = setOf(
override val sortOrders = arraySetOf(
SortOrder.UPDATED, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.RATING
//FIXME SortOrder.ALPHABETICAL
@@ -70,13 +71,13 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
author = tileInfo?.selectFirst("a.person-link")?.text(),
tags = safe {
tileInfo?.select("a.element-link")
?.map {
?.mapToSet {
MangaTag(
title = it.text(),
key = it.attr("href").substringAfterLast('/'),
source = source
)
}?.toSet()
}
}.orEmpty(),
state = when {
node.selectFirst("div.tags")
@@ -153,16 +154,16 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
val doc = loaderContext.httpGet("https://$domain/list/genres/sort_name").parseHtml()
val root = doc.body().getElementById("mangaBox").selectFirst("div.leftContent")
.selectFirst("table.table")
return root.select("a.element-link").map { a ->
return root.select("a.element-link").mapToSet { a ->
MangaTag(
title = a.text().capitalize(),
key = a.attr("href").substringAfterLast('/'),
source = source
)
}.toSet()
}
}
override fun onCreatePreferences() = setOf(R.string.key_parser_domain)
override fun onCreatePreferences() = arraySetOf(R.string.key_parser_domain)
private fun getSortKey(sortOrder: SortOrder?) =
when (sortOrder ?: sortOrders.minByOrNull { it.ordinal }) {

View File

@@ -4,6 +4,7 @@ import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.longHashCode
import org.koitharu.kotatsu.utils.ext.mapToSet
import org.koitharu.kotatsu.utils.ext.parseHtml
import org.koitharu.kotatsu.utils.ext.withDomain
@@ -37,14 +38,14 @@ class HenChanRepository(loaderContext: MangaLoaderContext) : ChanRepository(load
return manga.copy(
description = root.getElementById("description")?.html()?.substringBeforeLast("<div"),
largeCoverUrl = root.getElementById("cover")?.attr("src")?.withDomain(domain),
tags = root.selectFirst("div.sidetags")?.select("li.sidetag")?.map {
tags = root.selectFirst("div.sidetags")?.select("li.sidetag")?.mapToSet {
val a = it.children().last()
MangaTag(
title = a.text(),
key = a.attr("href").substringAfterLast('/'),
source = source
)
}?.toSet() ?: manga.tags,
} ?: manga.tags,
chapters = listOf(
MangaChapter(
id = readLink.longHashCode(),

View File

@@ -1,5 +1,7 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.ArraySet
import androidx.collection.arraySetOf
import org.json.JSONArray
import org.json.JSONObject
import org.koitharu.kotatsu.R
@@ -16,7 +18,7 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
override val source = MangaSource.MANGALIB
override val sortOrders = setOf(
override val sortOrders = arraySetOf(
SortOrder.RATING,
SortOrder.ALPHABETICAL,
SortOrder.POPULARITY,
@@ -68,7 +70,7 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
}
}
override fun onCreatePreferences() = setOf(R.string.key_parser_domain)
override fun onCreatePreferences() = arraySetOf(R.string.key_parser_domain)
override suspend fun getDetails(manga: Manga): Manga {
val doc = loaderContext.httpGet(manga.url + "?section=info").parseHtml()
@@ -126,13 +128,13 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
author = info.getElementsMatchingOwnText("Автор").firstOrNull()
?.nextElementSibling()?.text() ?: manga.author,
tags = info.getElementsMatchingOwnText("Жанры")?.firstOrNull()
?.nextElementSibling()?.select("a")?.mapNotNull { a ->
?.nextElementSibling()?.select("a")?.mapToSet { a ->
MangaTag(
title = a.text().capitalize(),
key = a.attr("href").substringAfterLast('='),
source = source
)
}?.toSet() ?: manga.tags,
} ?: manga.tags,
description = info.getElementsMatchingOwnText("Описание")?.firstOrNull()
?.nextElementSibling()?.html(),
chapters = chapters
@@ -183,7 +185,7 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
if (raw.startsWith("window.__DATA")) {
val json = JSONObject(raw.substringAfter('=').substringBeforeLast(';'))
val genres = json.getJSONObject("filters").getJSONArray("genres")
val result = HashSet<MangaTag>(genres.length())
val result = ArraySet<MangaTag>(genres.length())
for (x in genres) {
result += MangaTag(
source = source,

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.arraySetOf
import org.intellij.lang.annotations.Language
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.ParseException
@@ -13,7 +14,7 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposi
override val source = MangaSource.MANGATOWN
override val sortOrders = setOf(
override val sortOrders = arraySetOf(
SortOrder.ALPHABETICAL,
SortOrder.RATING,
SortOrder.POPULARITY,
@@ -71,13 +72,13 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposi
"completed" -> MangaState.FINISHED
else -> null
},
tags = li.selectFirst("p.keyWord")?.select("a")?.mapNotNull tags@{ x ->
tags = li.selectFirst("p.keyWord")?.select("a")?.mapNotNullToSet tags@{ x ->
MangaTag(
title = x.attr("title"),
key = x.attr("href").parseTagKey() ?: return@tags null,
source = MangaSource.MANGATOWN
)
}?.toSet().orEmpty(),
}.orEmpty(),
url = href
)
}
@@ -150,22 +151,22 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposi
.getElementsContainingOwnText("Genres")
.first()
.nextElementSibling()
return root.select("li").mapNotNull { li ->
val a = li.selectFirst("a") ?: return@mapNotNull null
return root.select("li").mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
val key = a.attr("href").parseTagKey()
if (key.isNullOrEmpty()) {
return@mapNotNull null
return@mapNotNullToSet null
}
MangaTag(
source = MangaSource.MANGATOWN,
key = key,
title = a.text()
)
}.toSet()
}
}
override fun onCreatePreferences() = setOf(R.string.key_parser_domain, R.string.key_parser_ssl)
override fun onCreatePreferences() = arraySetOf(R.string.key_parser_domain, R.string.key_parser_ssl)
private fun String.parseTagKey() = split('/').findLast { TAG_REGEX matches it }

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.arraySetOf
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
@@ -12,7 +13,7 @@ class NudeMoonRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposit
override val source = MangaSource.NUDEMOON
override val sortOrders = setOf(SortOrder.NEWEST, SortOrder.POPULARITY, SortOrder.RATING)
override val sortOrders = arraySetOf(SortOrder.NEWEST, SortOrder.POPULARITY, SortOrder.RATING)
init {
loaderContext.insertCookies(
@@ -133,7 +134,7 @@ class NudeMoonRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposit
}
}
override fun onCreatePreferences() = setOf(R.string.key_parser_domain)
override fun onCreatePreferences() = arraySetOf(R.string.key_parser_domain)
private fun getSortKey(sortOrder: SortOrder?) =
when (sortOrder ?: sortOrders.minByOrNull { it.ordinal }) {

View File

@@ -5,6 +5,7 @@ import android.content.SharedPreferences
import android.content.res.Resources
import android.provider.Settings
import androidx.appcompat.app.AppCompatDelegate
import androidx.collection.arraySetOf
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import org.koitharu.kotatsu.R
@@ -44,7 +45,7 @@ class AppSettings private constructor(resources: Resources, private val prefs: S
val readerPageSwitch by StringSetPreferenceDelegate(
resources.getString(R.string.key_reader_switchers),
setOf(PAGE_SWITCH_TAPS)
arraySetOf(PAGE_SWITCH_TAPS)
)
var isTrafficWarningEnabled by BoolPreferenceDelegate(
@@ -89,7 +90,7 @@ class AppSettings private constructor(resources: Resources, private val prefs: S
val trackSources by StringSetPreferenceDelegate(
resources.getString(R.string.key_track_sources),
setOf(TRACK_FAVOURITES, TRACK_HISTORY)
arraySetOf(TRACK_FAVOURITES, TRACK_HISTORY)
)
var appPassword by NullableStringPreferenceDelegate(

View File

@@ -11,27 +11,28 @@ import org.koitharu.kotatsu.core.db.entity.MangaEntity
import org.koitharu.kotatsu.core.db.entity.TagEntity
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.utils.ext.mapToSet
class FavouritesRepository(private val db: MangaDatabase) {
suspend fun getAllManga(): List<Manga> {
val entities = db.favouritesDao.findAll()
return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) }
return entities.map { it.manga.toManga(it.tags.mapToSet(TagEntity::toMangaTag)) }
}
suspend fun getAllManga(offset: Int): List<Manga> {
val entities = db.favouritesDao.findAll(offset, 20)
return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) }
return entities.map { it.manga.toManga(it.tags.mapToSet(TagEntity::toMangaTag)) }
}
suspend fun getManga(categoryId: Long): List<Manga> {
val entities = db.favouritesDao.findAll(categoryId)
return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) }
return entities.map { it.manga.toManga(it.tags.mapToSet(TagEntity::toMangaTag)) }
}
suspend fun getManga(categoryId: Long, offset: Int): List<Manga> {
val entities = db.favouritesDao.findAll(categoryId, offset, 20)
return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) }
return entities.map { it.manga.toManga(it.tags.mapToSet(TagEntity::toMangaTag)) }
}
suspend fun getAllCategories(): List<FavouriteCategory> {

View File

@@ -13,6 +13,7 @@ import org.koitharu.kotatsu.core.db.entity.TagEntity
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.domain.tracking.TrackingRepository
import org.koitharu.kotatsu.utils.ext.mapToSet
class HistoryRepository(private val db: MangaDatabase) : KoinComponent {
@@ -20,7 +21,7 @@ class HistoryRepository(private val db: MangaDatabase) : KoinComponent {
suspend fun getList(offset: Int, limit: Int = 20): List<Manga> {
val entities = db.historyDao.findAll(offset, limit)
return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) }
return entities.map { it.manga.toManga(it.tags.mapToSet(TagEntity::toMangaTag)) }
}
suspend fun addOrUpdate(manga: Manga, chapterId: Long, page: Int, scroll: Int) {

View File

@@ -8,7 +8,7 @@ import org.koitharu.kotatsu.core.model.MangaChapter
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.MangaTag
import org.koitharu.kotatsu.utils.ext.getStringOrNull
import org.koitharu.kotatsu.utils.ext.map
import org.koitharu.kotatsu.utils.ext.mapToSet
import org.koitharu.kotatsu.utils.ext.safe
class MangaIndex(source: String?) {
@@ -51,13 +51,13 @@ class MangaIndex(source: String?) {
rating = json.getDouble("rating").toFloat(),
coverUrl = json.getString("cover"),
description = json.getStringOrNull("description"),
tags = json.getJSONArray("tags").map { x ->
tags = json.getJSONArray("tags").mapToSet { x ->
MangaTag(
title = x.getString("title"),
key = x.getString("key"),
source = source
)
}.toSet(),
},
chapters = getChapters(json.getJSONObject("chapters"), source)
)
}

View File

@@ -56,7 +56,7 @@ class DownloadService : BaseService() {
when (intent?.action) {
ACTION_DOWNLOAD_START -> {
val manga = intent.getParcelableExtra<Manga>(EXTRA_MANGA)
val chapters = intent.getLongArrayExtra(EXTRA_CHAPTERS_IDS)?.toSet()
val chapters = intent.getLongArrayExtra(EXTRA_CHAPTERS_IDS)?.toArraySet()
if (manga != null) {
jobs[startId] = downloadManga(manga, chapters, startId)
Toast.makeText(this, R.string.manga_downloading_, Toast.LENGTH_SHORT).show()

View File

@@ -7,6 +7,7 @@ import org.koin.core.component.get
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
import org.koitharu.kotatsu.ui.base.BasePresenter
import org.koitharu.kotatsu.utils.ext.mapToSet
@InjectViewState
class FavouriteCategoriesPresenter : BasePresenter<FavouriteCategoriesView>() {
@@ -29,7 +30,7 @@ class FavouriteCategoriesPresenter : BasePresenter<FavouriteCategoriesView>() {
fun loadMangaCategories(manga: Manga) {
launchJob {
val categories = repository.getCategories(manga.id)
viewState.onCheckedCategoriesChanged(categories.map { it.id.toInt() }.toSet())
viewState.onCheckedCategoriesChanged(categories.mapToSet { it.id.toInt() })
}
}

View File

@@ -11,6 +11,7 @@ import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.utils.ext.mapToSet
import org.koitharu.kotatsu.utils.ext.safe
class SourcesAdapter(private val onItemClickListener: OnRecyclerItemClickListener<MangaSource>) :
@@ -44,7 +45,7 @@ class SourcesAdapter(private val onItemClickListener: OnRecyclerItemClickListene
} else {
hiddenItems.add(holder.requireData())
}
settings.hiddenSources = hiddenItems.map { x -> x.name }.toSet()
settings.hiddenSources = hiddenItems.mapToSet { x -> x.name }
}
holder.imageView_config.setOnClickListener { v ->
onItemClickListener.onItemClick(holder.requireData(), holder.bindingAdapterPosition, v)

View File

@@ -30,7 +30,28 @@ fun <T> List<T>.medianOrNull(): T? = when {
inline fun <T, R> Collection<T>.mapToSet(transform: (T) -> R): Set<R> {
val destination = ArraySet<R>(size)
for (item in this)
for (item in this) {
destination.add(transform(item))
}
return destination
}
inline fun <T, R> Collection<T>.mapNotNullToSet(transform: (T) -> R?): Set<R> {
val destination = ArraySet<R>(size)
for (item in this) {
destination.add(transform(item) ?: continue)
}
return destination
}
fun LongArray.toArraySet(): Set<Long> {
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> ArraySet<Long>(size).also { set ->
for (item in this) {
set.add(item)
}
}
}
}

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.utils.ext
import android.os.Bundle
import androidx.fragment.app.Fragment
fun <T : Fragment> T.withArgs(size: Int, block: Bundle.() -> Unit): T {
inline fun <T : Fragment> T.withArgs(size: Int, block: Bundle.() -> Unit): T {
val b = Bundle(size)
b.block()
this.arguments = b

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.utils.ext
import androidx.collection.ArraySet
import org.json.JSONArray
import org.json.JSONObject
@@ -36,4 +37,14 @@ private class JSONIterator(private val array: JSONArray) : Iterator<JSONObject>
override fun next(): JSONObject = array.getJSONObject(index++)
}
fun <T> JSONArray.mapToSet(block: (JSONObject) -> T): Set<T> {
val len = length()
val result = ArraySet<T>(len)
for (i in 0 until len) {
val jo = getJSONObject(i)
result.add(block(jo))
}
return result
}

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.utils.ext
import android.net.Uri
import androidx.collection.arraySetOf
import java.math.BigInteger
import java.net.URLEncoder
import java.security.MessageDigest
@@ -71,7 +72,7 @@ fun String.transliterate(skipMissing: Boolean): String {
}
fun String.toFileNameSafe() = this.transliterate(false)
.replace(Regex("[^a-z0-9_\\-]", setOf(RegexOption.IGNORE_CASE)), " ")
.replace(Regex("[^a-z0-9_\\-]", arraySetOf(RegexOption.IGNORE_CASE)), " ")
.replace(Regex("\\s+"), "_")
fun String.ellipsize(maxLength: Int) = if (this.length > maxLength) {

View File

@@ -143,7 +143,7 @@ fun View.measureWidth(): Int {
} else vw
}
fun ViewPager2.doOnPageChanged(callback: (Int) -> Unit) {
inline fun ViewPager2.doOnPageChanged(crossinline callback: (Int) -> Unit) {
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
@@ -153,7 +153,7 @@ fun ViewPager2.doOnPageChanged(callback: (Int) -> Unit) {
})
}
fun RecyclerView.doOnCurrentItemChanged(callback: (Int) -> Unit) {
inline fun RecyclerView.doOnCurrentItemChanged(crossinline callback: (Int) -> Unit) {
addOnScrollListener(object : RecyclerView.OnScrollListener() {
private var lastItem = -1