Fix tagged item in pinned tags not being refreshed

This commit is contained in:
MM20 2024-06-15 23:04:40 +02:00
parent 13ae92eafe
commit 56578b238d
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
5 changed files with 51 additions and 28 deletions

View File

@ -168,7 +168,7 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
longPressAppKey, longPressAppKey,
doubleTapAppKey, doubleTapAppKey,
homeButtonAppKey, homeButtonAppKey,
).let { searchableRepository.getByKeys(it) } ).let { searchableRepository.getByKeys(it).first() }
GestureState( GestureState(
swipeLeftAction = swipeLeftAction, swipeLeftAction = swipeLeftAction,

View File

@ -16,6 +16,8 @@ import de.mm20.launcher2.searchable.SavableSearchableRepository
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -78,9 +80,11 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
} }
val swipeLeftApp: Flow<SavableSearchable?> = swipeLeft val swipeLeftApp: Flow<SavableSearchable?> = swipeLeft
.map { .flatMapLatest {
if (it !is GestureAction.Launch || it.key == null) null if (it !is GestureAction.Launch || it.key == null) flowOf(null)
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull() else searchableRepository.getByKeys(listOf(it.key!!)).map {
it.firstOrNull()
}
} }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
@ -90,9 +94,11 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
} }
val swipeRightApp: Flow<SavableSearchable?> = swipeRight val swipeRightApp: Flow<SavableSearchable?> = swipeRight
.map { .flatMapLatest {
if (it !is GestureAction.Launch || it.key == null) null if (it !is GestureAction.Launch || it.key == null) flowOf(null)
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull() else searchableRepository.getByKeys(listOf(it.key!!)).map {
it.firstOrNull()
}
} }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
@ -102,9 +108,11 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
} }
val swipeDownApp: Flow<SavableSearchable?> = swipeDown val swipeDownApp: Flow<SavableSearchable?> = swipeDown
.map { .flatMapLatest {
if (it !is GestureAction.Launch || it.key == null) null if (it !is GestureAction.Launch || it.key == null) flowOf(null)
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull() else searchableRepository.getByKeys(listOf(it.key!!)).map {
it.firstOrNull()
}
} }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
@ -114,9 +122,11 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
} }
val longPressApp: Flow<SavableSearchable?> = longPress val longPressApp: Flow<SavableSearchable?> = longPress
.map { .flatMapLatest {
if (it !is GestureAction.Launch || it.key == null) null if (it !is GestureAction.Launch || it.key == null) flowOf(null)
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull() else searchableRepository.getByKeys(listOf(it.key!!)).map {
it.firstOrNull()
}
} }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
@ -126,9 +136,11 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
} }
val doubleTapApp: Flow<SavableSearchable?> = doubleTap val doubleTapApp: Flow<SavableSearchable?> = doubleTap
.map { .flatMapLatest {
if (it !is GestureAction.Launch || it.key == null) null if (it !is GestureAction.Launch || it.key == null) flowOf(null)
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull() else searchableRepository.getByKeys(listOf(it.key!!)).map {
it.firstOrNull()
}
} }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)
@ -138,9 +150,11 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
} }
val homeButtonApp: Flow<SavableSearchable?> = homeButton val homeButtonApp: Flow<SavableSearchable?> = homeButton
.map { .flatMapLatest {
if (it !is GestureAction.Launch || it.key == null) null if (it !is GestureAction.Launch || it.key == null) flowOf(null)
else searchableRepository.getByKeys(listOf(it.key!!)).firstOrNull() else searchableRepository.getByKeys(listOf(it.key!!)).map {
it.firstOrNull()
}
} }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(stopTimeoutMillis = 10000), null)

View File

@ -13,6 +13,7 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import org.json.JSONArray import org.json.JSONArray
@ -137,7 +138,7 @@ internal class CustomAttributesRepositoryImpl(
override fun getItemsForTag(tag: String): Flow<List<SavableSearchable>> { override fun getItemsForTag(tag: String): Flow<List<SavableSearchable>> {
val dao = appDatabase.customAttrsDao() val dao = appDatabase.customAttrsDao()
return dao.getItemsWithTag(tag).map { return dao.getItemsWithTag(tag).flatMapLatest {
searchableRepository.getByKeys(it) searchableRepository.getByKeys(it)
} }
} }
@ -181,8 +182,10 @@ internal class CustomAttributesRepositoryImpl(
} }
} }
val dao = appDatabase.customAttrsDao() val dao = appDatabase.customAttrsDao()
return dao.search("%$query%").map { return dao.search("%$query%").flatMapLatest {
searchableRepository.getByKeys(it).toImmutableList() searchableRepository.getByKeys(it).map {
it.toImmutableList()
}
} }
} }

View File

@ -141,7 +141,7 @@ interface SearchableDao {
): Flow<List<String>> ): Flow<List<String>>
@Query("SELECT * FROM Searchable WHERE `key` IN (:keys)") @Query("SELECT * FROM Searchable WHERE `key` IN (:keys)")
suspend fun getByKeys(keys: List<String>): List<SavedSearchableEntity> fun getByKeys(keys: List<String>): Flow<List<SavedSearchableEntity>>
@Query("SELECT * FROM Searchable WHERE `key` = :key") @Query("SELECT * FROM Searchable WHERE `key` = :key")
fun getByKey(key: String): Flow<SavedSearchableEntity?> fun getByKey(key: String): Flow<SavedSearchableEntity?>

View File

@ -16,9 +16,11 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.json.JSONArray import org.json.JSONArray
@ -105,7 +107,7 @@ interface SavableSearchableRepository: Backupable {
* Get items with the given keys from the favorites database. * Get items with the given keys from the favorites database.
* Items that don't exist in the database will not be returned. * Items that don't exist in the database will not be returned.
*/ */
suspend fun getByKeys(keys: List<String>): List<SavableSearchable> fun getByKeys(keys: List<String>): Flow<List<SavableSearchable>>
/** /**
* Remove database entries that are invalid. This includes * Remove database entries that are invalid. This includes
@ -376,16 +378,20 @@ internal class SavableSearchableRepositoryImpl(
} }
} }
override suspend fun getByKeys(keys: List<String>): List<SavableSearchable> { override fun getByKeys(keys: List<String>): Flow<List<SavableSearchable>> {
val dao = database.searchableDao() val dao = database.searchableDao()
if (keys.size > 999) { if (keys.size > 999) {
return keys.chunked(999).flatMap { return combine(keys.chunked(999).map {
dao.getByKeys(it) dao.getByKeys(it)
.mapNotNull { fromDatabaseEntity(it).searchable } .map {
it.mapNotNull { fromDatabaseEntity(it).searchable }
}
}) { results ->
results.flatMap { it }
} }
} }
return dao.getByKeys(keys) return dao.getByKeys(keys)
.mapNotNull { fromDatabaseEntity(it).searchable } .map { it.mapNotNull { fromDatabaseEntity(it).searchable } }
} }
override suspend fun backup(toDir: File) = withContext(Dispatchers.IO) { override suspend fun backup(toDir: File) = withContext(Dispatchers.IO) {