Custom labels
This commit is contained in:
parent
29a06dfc4f
commit
7b86677fc2
@ -130,7 +130,7 @@ internal class AppShortcutRepositoryImpl(
|
|||||||
it,
|
it,
|
||||||
label
|
label
|
||||||
)
|
)
|
||||||
}.sorted()
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,7 @@ internal class ContactRepositoryImpl(
|
|||||||
for ((id, rawIds) in contactMap) {
|
for ((id, rawIds) in contactMap) {
|
||||||
Contact.contactById(context, id, rawIds)?.let { results.add(it) }
|
Contact.contactById(context, id, rawIds)?.let { results.add(it) }
|
||||||
}
|
}
|
||||||
results.sortedBy { it }
|
results
|
||||||
}
|
}
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,8 @@ sealed interface CustomAttribute {
|
|||||||
if (entity == null) return null
|
if (entity == null) return null
|
||||||
return when (entity.type) {
|
return when (entity.type) {
|
||||||
CustomAttributeType.Label.value -> CustomLabel(
|
CustomAttributeType.Label.value -> CustomLabel(
|
||||||
label = entity.value
|
label = entity.value,
|
||||||
|
key = entity.key
|
||||||
)
|
)
|
||||||
CustomAttributeType.Tag.value -> CustomTag(
|
CustomAttributeType.Tag.value -> CustomTag(
|
||||||
tagName = entity.value
|
tagName = entity.value
|
||||||
@ -31,6 +32,7 @@ sealed interface CustomAttribute {
|
|||||||
|
|
||||||
|
|
||||||
class CustomLabel(
|
class CustomLabel(
|
||||||
|
val key: String,
|
||||||
val label: String,
|
val label: String,
|
||||||
) : CustomAttribute {
|
) : CustomAttribute {
|
||||||
override fun toDatabaseEntity(key: String): CustomAttributeEntity {
|
override fun toDatabaseEntity(key: String): CustomAttributeEntity {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package de.mm20.launcher2.customattrs
|
package de.mm20.launcher2.customattrs
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||||
import de.mm20.launcher2.database.AppDatabase
|
import de.mm20.launcher2.database.AppDatabase
|
||||||
import de.mm20.launcher2.database.entities.CustomAttributeEntity
|
import de.mm20.launcher2.database.entities.CustomAttributeEntity
|
||||||
import de.mm20.launcher2.database.entities.WebsearchEntity
|
|
||||||
import de.mm20.launcher2.ktx.jsonObjectOf
|
import de.mm20.launcher2.ktx.jsonObjectOf
|
||||||
import de.mm20.launcher2.search.data.Searchable
|
import de.mm20.launcher2.search.data.Searchable
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@ -17,6 +17,10 @@ interface CustomAttributesRepository {
|
|||||||
fun getCustomIcon(searchable: Searchable): Flow<CustomIcon?>
|
fun getCustomIcon(searchable: Searchable): Flow<CustomIcon?>
|
||||||
fun setCustomIcon(searchable: Searchable, icon: CustomIcon?)
|
fun setCustomIcon(searchable: Searchable, icon: CustomIcon?)
|
||||||
|
|
||||||
|
fun getCustomLabels(items: List<Searchable>): Flow<List<CustomLabel>>
|
||||||
|
fun setCustomLabel(searchable: Searchable, label: String)
|
||||||
|
fun clearCustomLabel(searchable: Searchable)
|
||||||
|
|
||||||
suspend fun export(toDir: File)
|
suspend fun export(toDir: File)
|
||||||
suspend fun import(fromDir: File)
|
suspend fun import(fromDir: File)
|
||||||
}
|
}
|
||||||
@ -44,6 +48,36 @@ internal class CustomAttributesRepositoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getCustomLabels(items: List<Searchable>): Flow<List<CustomLabel>> {
|
||||||
|
val dao = appDatabase.customAttrsDao()
|
||||||
|
return dao.getCustomAttributes(items.map { it.key }, CustomAttributeType.Label.value)
|
||||||
|
.map { list ->
|
||||||
|
list.mapNotNull { CustomAttribute.fromDatabaseEntity(it) as? CustomLabel }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setCustomLabel(searchable: Searchable, label: String) {
|
||||||
|
val dao = appDatabase.customAttrsDao()
|
||||||
|
scope.launch {
|
||||||
|
appDatabase.runInTransaction {
|
||||||
|
dao.clearCustomAttribute(searchable.key, CustomAttributeType.Label.value)
|
||||||
|
dao.setCustomAttribute(
|
||||||
|
CustomLabel(
|
||||||
|
key = searchable.key,
|
||||||
|
label = label,
|
||||||
|
).toDatabaseEntity(searchable.key)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearCustomLabel(searchable: Searchable) {
|
||||||
|
val dao = appDatabase.customAttrsDao()
|
||||||
|
scope.launch {
|
||||||
|
dao.clearCustomAttribute(searchable.key, CustomAttributeType.Label.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun export(toDir: File) = withContext(Dispatchers.IO) {
|
override suspend fun export(toDir: File) = withContext(Dispatchers.IO) {
|
||||||
val dao = appDatabase.backupDao()
|
val dao = appDatabase.backupDao()
|
||||||
var page = 0
|
var page = 0
|
||||||
@ -72,7 +106,9 @@ internal class CustomAttributesRepositoryImpl(
|
|||||||
val dao = appDatabase.backupDao()
|
val dao = appDatabase.backupDao()
|
||||||
dao.wipeCustomAttributes()
|
dao.wipeCustomAttributes()
|
||||||
|
|
||||||
val files = fromDir.listFiles { _, name -> name.startsWith("customizations.") } ?: return@withContext
|
val files =
|
||||||
|
fromDir.listFiles { _, name -> name.startsWith("customizations.") }
|
||||||
|
?: return@withContext
|
||||||
|
|
||||||
for (file in files) {
|
for (file in files) {
|
||||||
val customAttrs = mutableListOf<CustomAttributeEntity>()
|
val customAttrs = mutableListOf<CustomAttributeEntity>()
|
||||||
|
|||||||
@ -16,4 +16,7 @@ interface CustomAttrsDao {
|
|||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
fun setCustomAttribute(entity: CustomAttributeEntity)
|
fun setCustomAttribute(entity: CustomAttributeEntity)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM CustomAttributes WHERE type = :type AND key IN (:keys)")
|
||||||
|
fun getCustomAttributes(keys: List<String>, type: String) : Flow<List<CustomAttributeEntity>>
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ internal class GDriveFileProvider(
|
|||||||
viewUri = it.viewUri,
|
viewUri = it.viewUri,
|
||||||
metaData = getMetadata(it.metadata)
|
metaData = getMetadata(it.metadata)
|
||||||
)
|
)
|
||||||
}.sorted()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMetadata(file: DriveFileMeta): List<Pair<Int, String>> {
|
private fun getMetadata(file: DriveFileMeta): List<Pair<Int, String>> {
|
||||||
|
|||||||
@ -61,6 +61,6 @@ internal class LocalFileProvider(
|
|||||||
results.add(file)
|
results.add(file)
|
||||||
}
|
}
|
||||||
cursor.close()
|
cursor.close()
|
||||||
return@withContext results.sortedBy { it }
|
return@withContext results
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ internal class OneDriveFileProvider(
|
|||||||
webUrl = driveItem.webUrl
|
webUrl = driveItem.webUrl
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return files.sorted()
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMetaData(driveItem: DriveItem): List<Pair<Int, String>> {
|
private fun getMetaData(driveItem: DriveItem): List<Pair<Int, String>> {
|
||||||
|
|||||||
@ -16,6 +16,8 @@ abstract class Searchable : Comparable<Searchable> {
|
|||||||
abstract val key: String
|
abstract val key: String
|
||||||
abstract val label: String
|
abstract val label: String
|
||||||
|
|
||||||
|
var labelOverride: String? = null
|
||||||
|
|
||||||
open fun serialize(): String = ""
|
open fun serialize(): String = ""
|
||||||
|
|
||||||
open fun getLaunchIntent(context: Context): Intent? = null
|
open fun getLaunchIntent(context: Context): Intent? = null
|
||||||
@ -43,8 +45,10 @@ abstract class Searchable : Comparable<Searchable> {
|
|||||||
abstract fun getPlaceholderIcon(context: Context): StaticLauncherIcon
|
abstract fun getPlaceholderIcon(context: Context): StaticLauncherIcon
|
||||||
|
|
||||||
override fun compareTo(other: Searchable): Int {
|
override fun compareTo(other: Searchable): Int {
|
||||||
|
val label1 = labelOverride ?: label
|
||||||
|
val label2 = other.labelOverride ?: other.label
|
||||||
return Collator.getInstance().apply { strength = Collator.SECONDARY }
|
return Collator.getInstance().apply { strength = Collator.SECONDARY }
|
||||||
.compare(label.romanize(), other.label.romanize())
|
.compare(label1.romanize(), label2.romanize())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import de.mm20.launcher2.appshortcuts.AppShortcutRepository
|
|||||||
import de.mm20.launcher2.calculator.CalculatorRepository
|
import de.mm20.launcher2.calculator.CalculatorRepository
|
||||||
import de.mm20.launcher2.calendar.CalendarRepository
|
import de.mm20.launcher2.calendar.CalendarRepository
|
||||||
import de.mm20.launcher2.contacts.ContactRepository
|
import de.mm20.launcher2.contacts.ContactRepository
|
||||||
|
import de.mm20.launcher2.customattrs.CustomAttributesRepository
|
||||||
import de.mm20.launcher2.favorites.FavoritesRepository
|
import de.mm20.launcher2.favorites.FavoritesRepository
|
||||||
import de.mm20.launcher2.files.FileRepository
|
import de.mm20.launcher2.files.FileRepository
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
@ -31,6 +32,7 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
private val favoritesRepository: FavoritesRepository by inject()
|
private val favoritesRepository: FavoritesRepository by inject()
|
||||||
private val widgetRepository: WidgetRepository by inject()
|
private val widgetRepository: WidgetRepository by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
|
private val customAttributesRepository: CustomAttributesRepository by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
|
||||||
private val calendarRepository: CalendarRepository by inject()
|
private val calendarRepository: CalendarRepository by inject()
|
||||||
@ -81,12 +83,15 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
widgetRepository.isCalendarWidgetEnabled().collectLatest { excludeCalendar ->
|
widgetRepository.isCalendarWidgetEnabled().collectLatest { excludeCalendar ->
|
||||||
dataStore.data.map { it.grid.columnCount }.collectLatest { columns ->
|
dataStore.data.map { it.grid.columnCount }.collectLatest { columns ->
|
||||||
favoritesRepository.getFavorites(
|
favoritesRepository
|
||||||
columns = columns,
|
.getFavorites(
|
||||||
excludeCalendarEvents = excludeCalendar
|
columns = columns,
|
||||||
).collectLatest {
|
excludeCalendarEvents = excludeCalendar
|
||||||
favorites.value = it
|
)
|
||||||
}
|
.withCustomLabels()
|
||||||
|
.collectLatest {
|
||||||
|
favorites.value = it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,44 +108,53 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
searchJob?.cancel()
|
searchJob?.cancel()
|
||||||
} catch (e: CancellationException) {
|
} catch (_: CancellationException) {
|
||||||
}
|
}
|
||||||
hideFavorites.postValue(query.isNotEmpty())
|
hideFavorites.postValue(query.isNotEmpty())
|
||||||
searchJob = viewModelScope.launch {
|
searchJob = viewModelScope.launch {
|
||||||
isSearching.postValue(true)
|
isSearching.postValue(true)
|
||||||
val jobs = mutableListOf<Deferred<Any>>()
|
val jobs = mutableListOf<Deferred<Any>>()
|
||||||
jobs += async(Dispatchers.Default) {
|
jobs += async(Dispatchers.Default) {
|
||||||
appRepository.search(query).collectLatest { apps ->
|
appRepository
|
||||||
hiddenItemKeys.collectLatest { hiddenKeys ->
|
.search(query)
|
||||||
val results = apps.partition { !hiddenKeys.contains(it.key) }
|
.withCustomLabels()
|
||||||
appResults.postValue(results.first)
|
.collectLatest { apps ->
|
||||||
hiddenItems.update {
|
hiddenItemKeys.collectLatest { hiddenKeys ->
|
||||||
it.copy(apps = results.second)
|
val results = apps.partition { !hiddenKeys.contains(it.key) }
|
||||||
|
appResults.postValue(results.first)
|
||||||
|
hiddenItems.update {
|
||||||
|
it.copy(apps = results.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
jobs += async(Dispatchers.Default) {
|
jobs += async(Dispatchers.Default) {
|
||||||
contactRepository.search(query).collectLatest { contacts ->
|
contactRepository
|
||||||
hiddenItemKeys.collectLatest { hiddenKeys ->
|
.search(query)
|
||||||
val results = contacts.partition { !hiddenKeys.contains(it.key) }
|
.withCustomLabels()
|
||||||
contactResults.postValue(results.first)
|
.collectLatest { contacts ->
|
||||||
hiddenItems.update {
|
hiddenItemKeys.collectLatest { hiddenKeys ->
|
||||||
it.copy(contacts = results.second)
|
val results = contacts.partition { !hiddenKeys.contains(it.key) }
|
||||||
|
contactResults.postValue(results.first)
|
||||||
|
hiddenItems.update {
|
||||||
|
it.copy(contacts = results.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
jobs += async(Dispatchers.Default) {
|
jobs += async(Dispatchers.Default) {
|
||||||
calendarRepository.search(query).collectLatest { events ->
|
calendarRepository
|
||||||
hiddenItemKeys.collectLatest { hiddenKeys ->
|
.search(query)
|
||||||
val results = events.partition { !hiddenKeys.contains(it.key) }
|
.withCustomLabels()
|
||||||
calendarResults.postValue(results.first)
|
.collectLatest { events ->
|
||||||
hiddenItems.update {
|
hiddenItemKeys.collectLatest { hiddenKeys ->
|
||||||
it.copy(calendarEvents = results.second)
|
val results = events.partition { !hiddenKeys.contains(it.key) }
|
||||||
|
calendarResults.postValue(results.first)
|
||||||
|
hiddenItems.update {
|
||||||
|
it.copy(calendarEvents = results.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
jobs += async(Dispatchers.Default) {
|
jobs += async(Dispatchers.Default) {
|
||||||
wikipediaRepository.search(query).collectLatest {
|
wikipediaRepository.search(query).collectLatest {
|
||||||
@ -163,15 +177,18 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async(Dispatchers.Default) {
|
jobs += async(Dispatchers.Default) {
|
||||||
fileRepository.search(query).collectLatest { files ->
|
fileRepository
|
||||||
hiddenItemKeys.collectLatest { hiddenKeys ->
|
.search(query)
|
||||||
val results = files.partition { !hiddenKeys.contains(it.key) }
|
.withCustomLabels()
|
||||||
fileResults.postValue(results.first)
|
.collectLatest { files ->
|
||||||
hiddenItems.update {
|
hiddenItemKeys.collectLatest { hiddenKeys ->
|
||||||
it.copy(files = results.second)
|
val results = files.partition { !hiddenKeys.contains(it.key) }
|
||||||
|
fileResults.postValue(results.first)
|
||||||
|
hiddenItems.update {
|
||||||
|
it.copy(files = results.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
jobs += async(Dispatchers.Default) {
|
jobs += async(Dispatchers.Default) {
|
||||||
websearchRepository.search(query).collectLatest {
|
websearchRepository.search(query).collectLatest {
|
||||||
@ -179,11 +196,14 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async(Dispatchers.Default) {
|
jobs += async(Dispatchers.Default) {
|
||||||
appShortcutRepository.search(query).collectLatest { shortcuts ->
|
appShortcutRepository
|
||||||
hiddenItemKeys.collectLatest { hidden ->
|
.search(query)
|
||||||
appShortcutResults.postValue(shortcuts.filter { !hidden.contains(it.key) })
|
.withCustomLabels()
|
||||||
|
.collectLatest { shortcuts ->
|
||||||
|
hiddenItemKeys.collectLatest { hidden ->
|
||||||
|
appShortcutResults.postValue(shortcuts.filter { !hidden.contains(it.key) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
launch(Dispatchers.Default) {
|
launch(Dispatchers.Default) {
|
||||||
hiddenItems.collectLatest {
|
hiddenItems.collectLatest {
|
||||||
@ -272,6 +292,22 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject custom labels and sort by the actual label
|
||||||
|
*/
|
||||||
|
private fun <T : Searchable> Flow<List<T>>.withCustomLabels(): Flow<List<T>> = channelFlow {
|
||||||
|
this@withCustomLabels.collectLatest { items ->
|
||||||
|
val labelsFlow = customAttributesRepository.getCustomLabels(items)
|
||||||
|
labelsFlow.collectLatest { labels ->
|
||||||
|
for (item in items) {
|
||||||
|
val customLabel = labels.find { it.key == item.key }
|
||||||
|
item.labelOverride = customLabel?.label
|
||||||
|
}
|
||||||
|
send(items.sorted())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class HiddenItemResults(
|
private data class HiddenItemResults(
|
||||||
|
|||||||
@ -62,7 +62,7 @@ fun AppItem(
|
|||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
) {
|
) {
|
||||||
Text(text = app.label, style = MaterialTheme.typography.titleMedium)
|
Text(text = app.labelOverride ?: app.label, style = MaterialTheme.typography.titleMedium)
|
||||||
app.version?.let {
|
app.version?.let {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.app_info_version, it),
|
text = stringResource(R.string.app_info_version, it),
|
||||||
|
|||||||
@ -80,7 +80,7 @@ fun CalendarItem(
|
|||||||
if (showDetails) MaterialTheme.typography.titleMedium
|
if (showDetails) MaterialTheme.typography.titleMedium
|
||||||
else MaterialTheme.typography.titleSmall
|
else MaterialTheme.typography.titleSmall
|
||||||
)
|
)
|
||||||
Text(text = calendar.label, style = textStyle)
|
Text(text = calendar.labelOverride ?: calendar.label, style = textStyle)
|
||||||
AnimatedVisibility(!showDetails) {
|
AnimatedVisibility(!showDetails) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.padding(top = 2.dp),
|
modifier = Modifier.padding(top = 2.dp),
|
||||||
|
|||||||
@ -97,23 +97,29 @@ fun CustomizeSearchableSheet(
|
|||||||
viewModel.openIconPicker()
|
viewModel.openIconPicker()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var customLabelValue by remember {
|
||||||
|
mutableStateOf(searchable.labelOverride ?: "")
|
||||||
|
}
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(top = 24.dp)
|
.padding(top = 24.dp),
|
||||||
.clickable {
|
value = customLabelValue,
|
||||||
Toast
|
onValueChange = {
|
||||||
.makeText(context, "Soon™", Toast.LENGTH_SHORT)
|
customLabelValue = it
|
||||||
.show()
|
},
|
||||||
},
|
|
||||||
enabled = false,
|
|
||||||
value = searchable.label,
|
|
||||||
onValueChange = {},
|
|
||||||
placeholder = {
|
placeholder = {
|
||||||
Text(searchable.label)
|
Text(searchable.label)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DisposableEffect(searchable.key) {
|
||||||
|
onDispose {
|
||||||
|
viewModel.setCustomLabel(customLabelValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val iconSize = 48.dp
|
val iconSize = 48.dp
|
||||||
|
|||||||
@ -2,7 +2,9 @@ package de.mm20.launcher2.ui.launcher.search.common.customattrs
|
|||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.liveData
|
import androidx.lifecycle.liveData
|
||||||
|
import de.mm20.launcher2.customattrs.CustomAttributesRepository
|
||||||
import de.mm20.launcher2.customattrs.CustomIcon
|
import de.mm20.launcher2.customattrs.CustomIcon
|
||||||
|
import de.mm20.launcher2.customattrs.customAttrsModule
|
||||||
import de.mm20.launcher2.icons.CustomIconWithPreview
|
import de.mm20.launcher2.icons.CustomIconWithPreview
|
||||||
import de.mm20.launcher2.icons.IconRepository
|
import de.mm20.launcher2.icons.IconRepository
|
||||||
import de.mm20.launcher2.icons.LauncherIcon
|
import de.mm20.launcher2.icons.LauncherIcon
|
||||||
@ -17,6 +19,7 @@ class CustomizeSearchableSheetVM(
|
|||||||
private val searchable: Searchable
|
private val searchable: Searchable
|
||||||
) : KoinComponent {
|
) : KoinComponent {
|
||||||
private val iconRepository: IconRepository by inject()
|
private val iconRepository: IconRepository by inject()
|
||||||
|
private val customAttributesRepository: CustomAttributesRepository by inject()
|
||||||
|
|
||||||
val isIconPickerOpen = MutableLiveData(false)
|
val isIconPickerOpen = MutableLiveData(false)
|
||||||
|
|
||||||
@ -65,4 +68,12 @@ class CustomizeSearchableSheetVM(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setCustomLabel(label: String) {
|
||||||
|
if (label.isBlank()) {
|
||||||
|
customAttributesRepository.clearCustomLabel(searchable)
|
||||||
|
} else {
|
||||||
|
customAttributesRepository.setCustomLabel(searchable, label)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ fun GridItem(modifier: Modifier = Modifier, item: Searchable, showLabels: Boolea
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(top = 8.dp),
|
.padding(top = 8.dp),
|
||||||
text = item.label,
|
text = item.labelOverride ?: item.label,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
|
|||||||
@ -80,7 +80,7 @@ fun ContactItem(
|
|||||||
else MaterialTheme.typography.titleSmall
|
else MaterialTheme.typography.titleSmall
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = contact.label,
|
text = contact.labelOverride ?: contact.label,
|
||||||
style = textStyle,
|
style = textStyle,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
|
|||||||
@ -72,7 +72,7 @@ fun FileItem(
|
|||||||
else MaterialTheme.typography.titleSmall
|
else MaterialTheme.typography.titleSmall
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = file.label,
|
text = file.labelOverride ?: file.label,
|
||||||
style = textStyle,
|
style = textStyle,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
|
|||||||
@ -65,7 +65,7 @@ fun AppShortcutItem(
|
|||||||
) {
|
) {
|
||||||
val titleStyle by animateTextStyleAsState(if (showDetails) MaterialTheme.typography.titleMedium else MaterialTheme.typography.titleSmall)
|
val titleStyle by animateTextStyleAsState(if (showDetails) MaterialTheme.typography.titleMedium else MaterialTheme.typography.titleSmall)
|
||||||
Text(
|
Text(
|
||||||
text = shortcut.label,
|
text = shortcut.labelOverride ?: shortcut.label,
|
||||||
style = titleStyle,
|
style = titleStyle,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user