Improve icon picker, add icon search
This commit is contained in:
parent
050e8284e7
commit
a1e8c20b2b
@ -19,8 +19,8 @@ interface IconDao {
|
||||
@Query("SELECT * FROM Icons WHERE componentName = :componentName AND (type = 'app' OR type = 'calendar')")
|
||||
suspend fun getIconsFromAllPacks(componentName: String): List<IconEntity>
|
||||
|
||||
@Query("SELECT * FROM Icons WHERE iconPack = :iconPack AND (type = 'app' OR type = 'calendar') LIMIT :limit OFFSET :offset")
|
||||
suspend fun getIcons(iconPack: String, offset: Int, limit: Int): List<IconEntity>
|
||||
@Query("SELECT * FROM Icons WHERE (type = 'app' OR type = 'calendar') AND drawable LIKE :query ORDER BY iconPack, drawable LIMIT :limit")
|
||||
suspend fun searchIconPackIcons(query: String, limit: Int = 100): List<IconEntity>
|
||||
|
||||
@Query("DELETE FROM Icons WHERE iconPack = :iconPack")
|
||||
fun deleteIcons(iconPack: String)
|
||||
|
||||
@ -623,4 +623,8 @@
|
||||
<string name="restore_complete">The backup has been restored.</string>
|
||||
|
||||
<string name="icon_picker_title">Pick icon</string>
|
||||
<string name="icon_picker_default_icon">Default</string>
|
||||
<string name="icon_picker_suggestions">Suggestions</string>
|
||||
<string name="icon_picker_packs">Icon packs</string>
|
||||
<string name="icon_picker_search_icon">Search icon</string>
|
||||
</resources>
|
||||
@ -40,8 +40,6 @@ dependencies {
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.androidx.palette)
|
||||
|
||||
implementation(libs.androidx.paging.common)
|
||||
|
||||
implementation(libs.materialcomponents.core)
|
||||
|
||||
implementation(libs.bundles.androidx.lifecycle)
|
||||
|
||||
@ -15,6 +15,7 @@ import android.util.Log
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.customattrs.CustomIconPackIcon
|
||||
import de.mm20.launcher2.database.AppDatabase
|
||||
import de.mm20.launcher2.ktx.randomElementOrNull
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -185,18 +186,12 @@ class IconPackManager(
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getIcons(componentName: ComponentName): List<IconPackIcon> {
|
||||
suspend fun getAllIconPackIcons(componentName: ComponentName): List<IconPackIcon> {
|
||||
val iconDao = appDatabase.iconDao()
|
||||
return iconDao.getIconsFromAllPacks(componentName.flattenToString())
|
||||
.map { IconPackIcon(it) }
|
||||
}
|
||||
|
||||
suspend fun getIcons(iconPack: String, offset: Int, limit: Int): List<IconPackIcon> {
|
||||
val iconDao = appDatabase.iconDao()
|
||||
return iconDao.getIcons(iconPack, offset, limit)
|
||||
.map { IconPackIcon(it) }
|
||||
}
|
||||
|
||||
private suspend fun getIconBack(iconPack: String): String? {
|
||||
val iconDao = appDatabase.iconDao()
|
||||
val iconbacks = iconDao.getIconBacks(iconPack)
|
||||
@ -242,6 +237,13 @@ class IconPackManager(
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun searchIconPackIcon(query: String): List<IconPackIcon> {
|
||||
val iconDao = appDatabase.iconDao()
|
||||
return iconDao.searchIconPackIcons("%$query%").map {
|
||||
IconPackIcon(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
package de.mm20.launcher2.icons
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import de.mm20.launcher2.customattrs.CustomIconPackIcon
|
||||
import de.mm20.launcher2.icons.transformations.LauncherIconTransformation
|
||||
import de.mm20.launcher2.icons.transformations.apply
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal class IconPackPagingSource(
|
||||
private val iconPackManager: IconPackManager,
|
||||
private val iconPack: String,
|
||||
private val transformations: List<LauncherIconTransformation>
|
||||
) : PagingSource<Int, CustomIconWithPreview>() {
|
||||
override fun getRefreshKey(state: PagingState<Int, CustomIconWithPreview>): Int? {
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, CustomIconWithPreview> {
|
||||
val page = params.key ?: 0
|
||||
|
||||
val icons = withContext(Dispatchers.IO) {
|
||||
iconPackManager.getIcons(iconPack, page, page + params.loadSize)
|
||||
}
|
||||
|
||||
val customIcons = mutableListOf<CustomIconWithPreview>()
|
||||
withContext(Dispatchers.Default) {
|
||||
for (icon in icons) {
|
||||
val data = CustomIconPackIcon(iconPack, icon.componentName?.flattenToString() ?: continue)
|
||||
|
||||
val ic = iconPackManager.getIcon(
|
||||
iconPack,
|
||||
icon.componentName
|
||||
) ?: continue
|
||||
|
||||
customIcons.add(
|
||||
CustomIconWithPreview(
|
||||
preview = transformations.apply(ic),
|
||||
customIcon = data,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return LoadResult.Page(
|
||||
data = customIcons,
|
||||
prevKey = if (page > 0) page - 1 else null,
|
||||
nextKey = if (icons.size == params.loadSize) page + 1 else null
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,12 +6,11 @@ import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Color
|
||||
import android.util.LruCache
|
||||
import androidx.paging.PagingSource
|
||||
import de.mm20.launcher2.customattrs.*
|
||||
import de.mm20.launcher2.icons.providers.*
|
||||
import de.mm20.launcher2.icons.transformations.LauncherIconTransformation
|
||||
import de.mm20.launcher2.icons.transformations.LegacyToAdaptiveTransformation
|
||||
import de.mm20.launcher2.icons.transformations.apply
|
||||
import de.mm20.launcher2.icons.transformations.transform
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.search.data.LauncherApp
|
||||
import de.mm20.launcher2.search.data.Searchable
|
||||
@ -117,7 +116,7 @@ class IconRepository(
|
||||
icon = provs.getFirstIcon(searchable, size)
|
||||
|
||||
if (icon != null) {
|
||||
icon = transforms.apply(icon)
|
||||
icon = icon.transform(transforms)
|
||||
|
||||
cache.put(searchable.key + customIcon.hashCode(), icon)
|
||||
send(icon)
|
||||
@ -181,15 +180,6 @@ class IconRepository(
|
||||
|
||||
val defaultTransformations = transformations.first()
|
||||
|
||||
val defaultTransformedIcon = defaultTransformations.apply(rawIcon)
|
||||
|
||||
suggestions.add(
|
||||
CustomIconWithPreview(
|
||||
defaultTransformedIcon,
|
||||
null,
|
||||
)
|
||||
)
|
||||
|
||||
val customIcons = mutableListOf<CustomIcon>(UnmodifiedSystemDefaultIcon)
|
||||
|
||||
if (rawIcon is StaticLauncherIcon && rawIcon.backgroundLayer is TransparentLayer) {
|
||||
@ -230,7 +220,7 @@ class IconRepository(
|
||||
val icon = providers.getFirstIcon(searchable, size) ?: rawIcon
|
||||
|
||||
CustomIconWithPreview(
|
||||
preview = transformations.apply(icon),
|
||||
preview = icon.transform(transformations),
|
||||
customIcon = it,
|
||||
)
|
||||
|
||||
@ -240,7 +230,7 @@ class IconRepository(
|
||||
val providerOptions = mutableListOf<CustomIcon>()
|
||||
|
||||
if (searchable is LauncherApp) {
|
||||
val iconPackIcons = iconPackManager.getIcons(
|
||||
val iconPackIcons = iconPackManager.getAllIconPackIcons(
|
||||
searchable.launcherActivityInfo.componentName
|
||||
)
|
||||
|
||||
@ -262,7 +252,7 @@ class IconRepository(
|
||||
val icon = providers.getFirstIcon(searchable, size) ?: return@mapNotNull null
|
||||
|
||||
CustomIconWithPreview(
|
||||
preview = defaultTransformations.apply(icon),
|
||||
preview = icon.transform(defaultTransformations),
|
||||
customIcon = it,
|
||||
)
|
||||
|
||||
@ -273,8 +263,28 @@ class IconRepository(
|
||||
|
||||
}
|
||||
|
||||
suspend fun getAllIconsFromPack(iconPack: String): PagingSource<Int, CustomIconWithPreview> {
|
||||
return IconPackPagingSource(iconPackManager, iconPack, transformations.first())
|
||||
suspend fun getUncustomizedDefaultIcon(searchable: Searchable, size: Int): CustomIconWithPreview? {
|
||||
val icon = iconProviders.first().getFirstIcon(searchable, size)
|
||||
?.transform(transformations.first()) ?: return null
|
||||
return CustomIconWithPreview(
|
||||
customIcon = null,
|
||||
preview = icon
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun searchIconPackIcon(query: String): List<CustomIconWithPreview> {
|
||||
val transformations = this.transformations.first()
|
||||
return iconPackManager.searchIconPackIcon(query).mapNotNull {
|
||||
val componentName = it.componentName ?: return@mapNotNull null
|
||||
|
||||
CustomIconWithPreview(
|
||||
customIcon = CustomIconPackIcon(
|
||||
iconPackPackage = it.iconPack,
|
||||
iconComponentName = componentName.flattenToString(),
|
||||
),
|
||||
preview = iconPackManager.getIcon(it.iconPack, componentName)?.transform(transformations) ?: return@mapNotNull null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setCustomIcon(searchable: Searchable, icon: CustomIcon?) {
|
||||
|
||||
@ -8,17 +8,17 @@ internal interface LauncherIconTransformation {
|
||||
suspend fun transform(icon: StaticLauncherIcon): StaticLauncherIcon
|
||||
}
|
||||
|
||||
internal suspend fun Iterable<LauncherIconTransformation>.apply(icon: LauncherIcon): LauncherIcon {
|
||||
if (icon is StaticLauncherIcon) {
|
||||
var transformedIcon = icon
|
||||
for (transformation in this) {
|
||||
internal suspend fun LauncherIcon.transform(transformations: Iterable<LauncherIconTransformation>): LauncherIcon {
|
||||
if (this is StaticLauncherIcon) {
|
||||
var transformedIcon = this
|
||||
for (transformation in transformations) {
|
||||
transformedIcon = transformation.transform(transformedIcon as StaticLauncherIcon)
|
||||
}
|
||||
return transformedIcon
|
||||
}
|
||||
if (icon is TransformableDynamicLauncherIcon) {
|
||||
icon.setTransformations(this.toList())
|
||||
return icon
|
||||
if (this is TransformableDynamicLauncherIcon) {
|
||||
this.setTransformations(transformations.toList())
|
||||
return this
|
||||
}
|
||||
return icon
|
||||
return this
|
||||
}
|
||||
@ -238,14 +238,6 @@ dependencyResolutionManagement {
|
||||
.to("androidx.navigation", "navigation-compose")
|
||||
.version("2.5.0-rc02")
|
||||
|
||||
alias("androidx.paging.common")
|
||||
.to("androidx.paging", "paging-common-ktx")
|
||||
.version("3.2.0-alpha01")
|
||||
alias("androidx.paging.compose")
|
||||
.to("androidx.paging", "paging-compose")
|
||||
.version("1.0.0-alpha15")
|
||||
|
||||
|
||||
alias("materialcomponents.core")
|
||||
.to("com.google.android.material", "material")
|
||||
.version("1.6.0-beta01")
|
||||
|
||||
@ -64,7 +64,6 @@ dependencies {
|
||||
implementation(libs.androidx.compose.animationgraphics)
|
||||
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
implementation(libs.androidx.paging.compose)
|
||||
|
||||
implementation(libs.composecolorpicker)
|
||||
|
||||
|
||||
@ -2,41 +2,34 @@ package de.mm20.launcher2.ui.launcher.search.common.customattrs
|
||||
|
||||
import android.graphics.drawable.InsetDrawable
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyItemScope
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridScope
|
||||
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.paging.compose.itemsIndexed
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Clear
|
||||
import androidx.compose.material.icons.rounded.Search
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import de.mm20.launcher2.badges.Badge
|
||||
import de.mm20.launcher2.icons.CustomIconWithPreview
|
||||
import de.mm20.launcher2.search.data.Searchable
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
||||
import de.mm20.launcher2.ui.ktx.toPixels
|
||||
import de.mm20.launcher2.ui.locals.LocalGridColumns
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun CustomizeSearchableSheet(
|
||||
@ -111,69 +104,146 @@ fun CustomizeSearchableSheet(
|
||||
} else {
|
||||
val iconSize = 48.dp
|
||||
val iconSizePx = iconSize.toPixels()
|
||||
val suggestions by
|
||||
remember { viewModel.getIconSuggestions(iconSizePx.toInt()) }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val suggestions by remember { viewModel.getIconSuggestions(iconSizePx.toInt()) }
|
||||
.observeAsState(emptyList())
|
||||
|
||||
val iconPackIcons by remember {
|
||||
viewModel.getAllIconsFromAllIconPacks()
|
||||
}.observeAsState(emptyList())
|
||||
val defaultIcon by remember {
|
||||
viewModel.getDefaultIcon(iconSizePx.toInt())
|
||||
}.observeAsState()
|
||||
|
||||
val pagingItems = iconPackIcons.map {
|
||||
it.flow.collectAsLazyPagingItems()
|
||||
}
|
||||
var query by remember { mutableStateOf("") }
|
||||
val isSearching by viewModel.isSearchingIcons.observeAsState(initial = false)
|
||||
val iconResults by viewModel.iconSearchResults.observeAsState(emptyList())
|
||||
|
||||
LazyVerticalGrid(columns = GridCells.Fixed(LocalGridColumns.current)) {
|
||||
items(suggestions) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.padding(vertical = 8.dp)
|
||||
) {
|
||||
ShapedLauncherIcon(
|
||||
size = iconSize,
|
||||
icon = it.preview,
|
||||
onClick = {
|
||||
viewModel.pickIcon(it.customIcon)
|
||||
val columns = LocalGridColumns.current
|
||||
|
||||
LazyVerticalGrid(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
columns = GridCells.Fixed(columns)
|
||||
) {
|
||||
|
||||
item(span = { GridItemSpan(columns) }) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.padding(bottom = 16.dp),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Search,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (query.isNotEmpty()) {
|
||||
IconButton(onClick = {
|
||||
query = ""
|
||||
scope.launch {
|
||||
viewModel.searchIcon("")
|
||||
}
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Clear,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
value = query,
|
||||
onValueChange = {
|
||||
query = it
|
||||
scope.launch {
|
||||
viewModel.searchIcon(query)
|
||||
}
|
||||
},
|
||||
label = {
|
||||
Text(stringResource(R.string.icon_picker_search_icon))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (query.isEmpty()) {
|
||||
if (defaultIcon != null) {
|
||||
item(span = { GridItemSpan(columns) }) {
|
||||
Separator(stringResource(R.string.icon_picker_default_icon))
|
||||
}
|
||||
item {
|
||||
IconPreview(item = defaultIcon, iconSize = iconSize, onClick = {
|
||||
viewModel.pickIcon(null)
|
||||
})
|
||||
}
|
||||
}
|
||||
item(span = { GridItemSpan(columns) }) {
|
||||
Separator(stringResource(R.string.icon_picker_suggestions))
|
||||
}
|
||||
|
||||
items(suggestions) {
|
||||
IconPreview(
|
||||
it,
|
||||
iconSize,
|
||||
onClick = { viewModel.pickIcon(it.customIcon) }
|
||||
)
|
||||
}
|
||||
}
|
||||
for (pager in pagingItems) {
|
||||
itemsIndexed(pager) { index, item ->
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.padding(vertical = 8.dp)
|
||||
) {
|
||||
ShapedLauncherIcon(
|
||||
size = iconSize,
|
||||
icon = item?.preview,
|
||||
onClick = {
|
||||
viewModel.pickIcon(item?.customIcon)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
|
||||
item(span = { GridItemSpan(columns) }) {
|
||||
Separator(stringResource(R.string.icon_picker_packs))
|
||||
}
|
||||
|
||||
items(iconResults) {
|
||||
IconPreview(
|
||||
it,
|
||||
iconSize,
|
||||
onClick = { viewModel.pickIcon(it.customIcon) }
|
||||
)
|
||||
}
|
||||
|
||||
if (isSearching) {
|
||||
item(span = { GridItemSpan(columns) }) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.padding(12.dp)
|
||||
.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any> LazyGridScope.itemsIndexed(
|
||||
items: LazyPagingItems<T>,
|
||||
key: ((index: Int, item: T) -> Any)? = null,
|
||||
itemContent: @Composable LazyGridScope.(index: Int, value: T?) -> Unit
|
||||
@Composable
|
||||
fun IconPreview(
|
||||
item: CustomIconWithPreview?,
|
||||
iconSize: Dp,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
items(
|
||||
count = items.itemCount,
|
||||
key = if (key == null) null else { index ->
|
||||
val item = items.peek(index)
|
||||
if (item == null) {
|
||||
} else {
|
||||
key(index, item)
|
||||
}
|
||||
}
|
||||
) { index ->
|
||||
this@itemsIndexed.itemContent(index, items[index])
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.padding(vertical = 8.dp)
|
||||
) {
|
||||
ShapedLauncherIcon(
|
||||
size = iconSize,
|
||||
icon = item?.preview,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Separator(label: String) {
|
||||
Text(
|
||||
label,
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
modifier = Modifier
|
||||
.padding(top = 16.dp, bottom = 8.dp)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
@ -2,15 +2,16 @@ package de.mm20.launcher2.ui.launcher.search.common.customattrs
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.liveData
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import de.mm20.launcher2.customattrs.CustomIcon
|
||||
import de.mm20.launcher2.icons.CustomIconWithPreview
|
||||
import de.mm20.launcher2.icons.IconRepository
|
||||
import de.mm20.launcher2.icons.LauncherIcon
|
||||
import de.mm20.launcher2.search.data.Searchable
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
class CustomizeSearchableSheetVM(
|
||||
private val searchable: Searchable
|
||||
@ -40,19 +41,28 @@ class CustomizeSearchableSheetVM(
|
||||
closeIconPicker()
|
||||
}
|
||||
|
||||
fun getAllIconsFromAllIconPacks() = liveData {
|
||||
emit(emptyList())
|
||||
val iconPacks = iconRepository.getInstalledIconPacks()
|
||||
fun getDefaultIcon(size: Int) = liveData {
|
||||
emit(iconRepository.getUncustomizedDefaultIcon(searchable, size))
|
||||
}
|
||||
|
||||
emit(iconPacks.map {
|
||||
val source = iconRepository.getAllIconsFromPack(it.packageName)
|
||||
val iconSearchResults = MutableLiveData(emptyList<CustomIconWithPreview>())
|
||||
val isSearchingIcons = MutableLiveData(false)
|
||||
|
||||
Pager(
|
||||
PagingConfig(pageSize = 20, enablePlaceholders = false, maxSize = 200),
|
||||
) {
|
||||
source
|
||||
private var debounceSearchJob: Job? = null
|
||||
suspend fun searchIcon(query: String) {
|
||||
debounceSearchJob?.cancelAndJoin()
|
||||
if (query.isBlank()) {
|
||||
iconSearchResults.value = emptyList()
|
||||
isSearchingIcons.value = false
|
||||
return
|
||||
}
|
||||
withContext(coroutineContext) {
|
||||
debounceSearchJob = launch {
|
||||
delay(1000)
|
||||
isSearchingIcons.value = true
|
||||
iconSearchResults.value = iconRepository.searchIconPackIcon(query)
|
||||
isSearchingIcons.value = false
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user