Add search-only visibility level to items

This commit is contained in:
MM20
2024-06-17 22:59:12 +02:00
parent 1251924553
commit c7ea840fc5
28 changed files with 571 additions and 485 deletions
@@ -0,0 +1,8 @@
package de.mm20.launcher2.searchable
enum class PinnedLevel {
NotPinned,
FrequentlyUsed,
AutomaticallySorted,
ManuallySorted,
}
@@ -20,7 +20,6 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONArray
@@ -32,7 +31,7 @@ import org.koin.core.error.NoBeanDefFoundException
import org.koin.core.qualifier.named
import java.io.File
interface SavableSearchableRepository: Backupable {
interface SavableSearchableRepository : Backupable {
fun insert(
searchable: SavableSearchable,
@@ -40,7 +39,7 @@ interface SavableSearchableRepository: Backupable {
fun upsert(
searchable: SavableSearchable,
hidden: Boolean? = null,
visibility: VisibilityLevel? = null,
pinned: Boolean? = null,
launchCount: Int? = null,
weight: Double? = null,
@@ -48,7 +47,7 @@ interface SavableSearchableRepository: Backupable {
fun update(
searchable: SavableSearchable,
hidden: Boolean? = null,
visibility: VisibilityLevel? = null,
pinned: Boolean? = null,
launchCount: Int? = null,
weight: Double? = null,
@@ -61,29 +60,35 @@ interface SavableSearchableRepository: Backupable {
searchable: SavableSearchable,
)
/**
* @param minVisibility the minimum visibility of the searchables to return. A visible is
* considered to be "lower" when it makes an item less visible.
* @param maxVisibility the maximum visibility of the searchables to return. A visible is
* considered to be "higher" when it makes an item more visible.
*/
fun get(
includeTypes: List<String>? = null,
excludeTypes: List<String>? = null,
manuallySorted: Boolean = false,
automaticallySorted: Boolean = false,
frequentlyUsed: Boolean = false,
hidden: Boolean = false,
minPinnedLevel: PinnedLevel = PinnedLevel.NotPinned,
maxPinnedLevel: PinnedLevel = PinnedLevel.ManuallySorted,
minVisibility: VisibilityLevel = VisibilityLevel.Hidden,
maxVisibility: VisibilityLevel = VisibilityLevel.Default,
limit: Int = 100,
): Flow<List<SavableSearchable>>
fun getKeys(
includeTypes: List<String>? = null,
excludeTypes: List<String>? = null,
manuallySorted: Boolean = false,
automaticallySorted: Boolean = false,
frequentlyUsed: Boolean = false,
hidden: Boolean = false,
minPinnedLevel: PinnedLevel = PinnedLevel.NotPinned,
maxPinnedLevel: PinnedLevel = PinnedLevel.ManuallySorted,
minVisibility: VisibilityLevel = VisibilityLevel.Hidden,
maxVisibility: VisibilityLevel = VisibilityLevel.Default,
limit: Int = 100,
): Flow<List<String>>
fun isPinned(searchable: SavableSearchable): Flow<Boolean>
fun isHidden(searchable: SavableSearchable): Flow<Boolean>
fun getVisibility(searchable: SavableSearchable): Flow<VisibilityLevel>
fun updateFavorites(
manuallySorted: List<SavableSearchable>,
automaticallySorted: List<SavableSearchable>,
@@ -132,7 +137,7 @@ internal class SavableSearchableRepositoryImpl(
key = searchable.key,
type = searchable.domain,
serializedSearchable = searchable.serialize() ?: return@launch,
hidden = false,
visibility = VisibilityLevel.Default.value,
launchCount = 0,
weight = 0.0,
pinPosition = 0,
@@ -144,7 +149,7 @@ internal class SavableSearchableRepositoryImpl(
override fun upsert(
searchable: SavableSearchable,
hidden: Boolean?,
visibility: VisibilityLevel?,
pinned: Boolean?,
launchCount: Int?,
weight: Double?
@@ -156,7 +161,7 @@ internal class SavableSearchableRepositoryImpl(
SavedSearchableEntity(
key = searchable.key,
type = searchable.domain,
hidden = hidden ?: entity?.hidden ?: false,
visibility = visibility?.value ?: entity?.visibility ?: 0,
pinPosition = pinned?.let { if (it) 1 else 0 } ?: entity?.pinPosition ?: 0,
launchCount = launchCount ?: entity?.launchCount ?: 0,
weight = weight ?: entity?.weight ?: 0.0,
@@ -168,7 +173,7 @@ internal class SavableSearchableRepositoryImpl(
override fun update(
searchable: SavableSearchable,
hidden: Boolean?,
visibility: VisibilityLevel?,
pinned: Boolean?,
launchCount: Int?,
weight: Double?
@@ -180,7 +185,7 @@ internal class SavableSearchableRepositoryImpl(
SavedSearchableEntity(
key = searchable.key,
type = searchable.domain,
hidden = hidden ?: entity?.hidden ?: false,
visibility = visibility?.value ?: entity?.visibility ?: 0,
pinPosition = pinned?.let { if (it) 1 else 0 } ?: entity?.pinPosition ?: 0,
launchCount = launchCount ?: entity?.launchCount ?: 0,
weight = weight ?: entity?.weight ?: 0.0,
@@ -198,7 +203,8 @@ internal class SavableSearchableRepositoryImpl(
WeightFactor.High -> WEIGHT_FACTOR_HIGH
else -> WEIGHT_FACTOR_MEDIUM
}
val item = SavedSearchable(searchable.key, searchable, 0, 0, false, 0.0)
val item =
SavedSearchable(searchable.key, searchable, 0, 0, VisibilityLevel.Default, 0.0)
item.toDatabaseEntity()?.let {
database.searchableDao()
.touch(it, weightFactor)
@@ -209,37 +215,43 @@ internal class SavableSearchableRepositoryImpl(
override fun get(
includeTypes: List<String>?,
excludeTypes: List<String>?,
manuallySorted: Boolean,
automaticallySorted: Boolean,
frequentlyUsed: Boolean,
hidden: Boolean,
minPinnedLevel: PinnedLevel,
maxPinnedLevel: PinnedLevel,
minVisibility: VisibilityLevel,
maxVisibility: VisibilityLevel,
limit: Int
): Flow<List<SavableSearchable>> {
val dao = database.searchableDao()
val entities = when {
includeTypes == null && excludeTypes == null -> dao.get(
manuallySorted = manuallySorted,
automaticallySorted = automaticallySorted,
frequentlyUsed = frequentlyUsed,
hidden = hidden,
manuallySorted = PinnedLevel.ManuallySorted in minPinnedLevel..maxPinnedLevel,
automaticallySorted = PinnedLevel.AutomaticallySorted in minPinnedLevel..maxPinnedLevel,
frequentlyUsed = PinnedLevel.FrequentlyUsed in minPinnedLevel..maxPinnedLevel,
unused = PinnedLevel.NotPinned in minPinnedLevel..maxPinnedLevel,
minVisibility = minVisibility.value,
maxVisibility = maxVisibility.value,
limit = limit
)
includeTypes == null -> dao.getExcludeTypes(
excludeTypes = excludeTypes,
manuallySorted = manuallySorted,
automaticallySorted = automaticallySorted,
frequentlyUsed = frequentlyUsed,
hidden = hidden,
manuallySorted = PinnedLevel.ManuallySorted in minPinnedLevel..maxPinnedLevel,
automaticallySorted = PinnedLevel.AutomaticallySorted in minPinnedLevel..maxPinnedLevel,
frequentlyUsed = PinnedLevel.FrequentlyUsed in minPinnedLevel..maxPinnedLevel,
unused = PinnedLevel.NotPinned in minPinnedLevel..maxPinnedLevel,
minVisibility = minVisibility.value,
maxVisibility = maxVisibility.value,
limit = limit
)
excludeTypes == null -> dao.getIncludeTypes(
includeTypes = includeTypes,
manuallySorted = manuallySorted,
automaticallySorted = automaticallySorted,
frequentlyUsed = frequentlyUsed,
hidden = hidden,
manuallySorted = PinnedLevel.ManuallySorted in minPinnedLevel..maxPinnedLevel,
automaticallySorted = PinnedLevel.AutomaticallySorted in minPinnedLevel..maxPinnedLevel,
frequentlyUsed = PinnedLevel.FrequentlyUsed in minPinnedLevel..maxPinnedLevel,
unused = PinnedLevel.NotPinned in minPinnedLevel..maxPinnedLevel,
minVisibility = minVisibility.value,
maxVisibility = maxVisibility.value,
limit = limit
)
@@ -254,37 +266,43 @@ internal class SavableSearchableRepositoryImpl(
override fun getKeys(
includeTypes: List<String>?,
excludeTypes: List<String>?,
manuallySorted: Boolean,
automaticallySorted: Boolean,
frequentlyUsed: Boolean,
hidden: Boolean,
minPinnedLevel: PinnedLevel,
maxPinnedLevel: PinnedLevel,
minVisibility: VisibilityLevel,
maxVisibility: VisibilityLevel,
limit: Int
): Flow<List<String>> {
val dao = database.searchableDao()
return when {
includeTypes == null && excludeTypes == null -> dao.getKeys(
manuallySorted = manuallySorted,
automaticallySorted = automaticallySorted,
frequentlyUsed = frequentlyUsed,
hidden = hidden,
manuallySorted = PinnedLevel.ManuallySorted in minPinnedLevel..maxPinnedLevel,
automaticallySorted = PinnedLevel.AutomaticallySorted in minPinnedLevel..maxPinnedLevel,
frequentlyUsed = PinnedLevel.FrequentlyUsed in minPinnedLevel..maxPinnedLevel,
unused = PinnedLevel.NotPinned in minPinnedLevel..maxPinnedLevel,
minVisibility = minVisibility.value,
maxVisibility = maxVisibility.value,
limit = limit
)
includeTypes == null -> dao.getKeysExcludeTypes(
excludeTypes = excludeTypes,
manuallySorted = manuallySorted,
automaticallySorted = automaticallySorted,
frequentlyUsed = frequentlyUsed,
hidden = hidden,
manuallySorted = PinnedLevel.ManuallySorted in minPinnedLevel..maxPinnedLevel,
automaticallySorted = PinnedLevel.AutomaticallySorted in minPinnedLevel..maxPinnedLevel,
frequentlyUsed = PinnedLevel.FrequentlyUsed in minPinnedLevel..maxPinnedLevel,
unused = PinnedLevel.NotPinned in minPinnedLevel..maxPinnedLevel,
minVisibility = minVisibility.value,
maxVisibility = maxVisibility.value,
limit = limit
)
excludeTypes == null -> dao.getKeysIncludeTypes(
includeTypes = includeTypes,
manuallySorted = manuallySorted,
automaticallySorted = automaticallySorted,
frequentlyUsed = frequentlyUsed,
hidden = hidden,
manuallySorted = PinnedLevel.ManuallySorted in minPinnedLevel..maxPinnedLevel,
automaticallySorted = PinnedLevel.AutomaticallySorted in minPinnedLevel..maxPinnedLevel,
frequentlyUsed = PinnedLevel.FrequentlyUsed in minPinnedLevel..maxPinnedLevel,
unused = PinnedLevel.NotPinned in minPinnedLevel..maxPinnedLevel,
minVisibility = minVisibility.value,
maxVisibility = maxVisibility.value,
limit = limit
)
@@ -296,8 +314,10 @@ internal class SavableSearchableRepositoryImpl(
return database.searchableDao().isPinned(searchable.key)
}
override fun isHidden(searchable: SavableSearchable): Flow<Boolean> {
return database.searchableDao().isHidden(searchable.key)
override fun getVisibility(searchable: SavableSearchable): Flow<VisibilityLevel> {
return database.searchableDao().getVisibility(searchable.key).map {
VisibilityLevel.fromInt(it)
}
}
override fun delete(searchable: SavableSearchable) {
@@ -367,7 +387,7 @@ internal class SavableSearchableRepositoryImpl(
searchable = searchable,
launchCount = entity.launchCount,
pinPosition = entity.pinPosition,
hidden = entity.hidden,
visibility = VisibilityLevel.fromInt(entity.visibility),
weight = entity.weight
)
}
@@ -405,7 +425,7 @@ internal class SavableSearchableRepositoryImpl(
jsonObjectOf(
"key" to fav.key,
"type" to fav.type,
"hidden" to fav.hidden,
"visibility" to fav.visibility,
"launchCount" to fav.launchCount,
"pinPosition" to fav.pinPosition,
"searchable" to fav.serializedSearchable,
@@ -441,7 +461,7 @@ internal class SavableSearchableRepositoryImpl(
type = json.optString("type").takeIf { it.isNotEmpty() } ?: continue,
serializedSearchable = json.getString("searchable"),
launchCount = json.getInt("launchCount"),
hidden = json.getBoolean("hidden"),
visibility = json.optInt("visibility", 0),
pinPosition = json.getInt("pinPosition"),
weight = json.optDouble("weight").takeIf { !it.isNaN() } ?: 0.0
)
@@ -11,7 +11,7 @@ data class SavedSearchable(
val searchable: SavableSearchable?,
var launchCount: Int,
var pinPosition: Int,
var hidden: Boolean,
var visibility: VisibilityLevel,
var weight: Double
) {
fun toDatabaseEntity(): SavedSearchableEntity? {
@@ -21,7 +21,7 @@ data class SavedSearchable(
key = key,
type = searchable.domain,
serializedSearchable = data,
hidden = hidden,
visibility = visibility.value,
pinPosition = pinPosition,
launchCount = launchCount,
weight = weight
@@ -0,0 +1,32 @@
package de.mm20.launcher2.searchable
enum class VisibilityLevel(val value: Int) {
/**
* Default visibility:
* - apps are shown in app drawer
* - calendar events are shown in calendar widget
* - everything else is shown in search results
* - items can appear in frequently used section
*/
Default(0),
/**
* Search only visibility:
* - items are only shown in search results
* - items can appear in frequently used section
* - items are not shown in app drawer or calendar widget
*/
SearchOnly(1),
/**
* Hidden visibility:
* - items are not shown in search results
* - items are not shown in app drawer or calendar widget
* - items are not shown in frequently used section
*/
Hidden(2);
companion object {
internal fun fromInt(value: Int) = entries.firstOrNull() { it.value == value } ?: Default
}
}