Allow configuring extension languages

This commit is contained in:
Syer10
2021-06-16 20:23:59 -04:00
parent 6c10770ea6
commit bc7cd12d3a
3 changed files with 77 additions and 9 deletions

View File

@@ -8,9 +8,10 @@ package ca.gosyer.data.extension
import ca.gosyer.common.prefs.Preference
import ca.gosyer.common.prefs.PreferenceStore
import java.util.Locale
class ExtensionPreferences(private val preferenceStore: PreferenceStore) {
fun languages(): Preference<Set<String>> {
return preferenceStore.getStringSet("enabled_langs", setOf("all", "en"))
return preferenceStore.getStringSet("enabled_langs", setOf("all", "en", Locale.getDefault().language))
}
}

View File

@@ -6,6 +6,7 @@
package ca.gosyer.ui.extensions
import androidx.compose.foundation.ScrollbarAdapter
import androidx.compose.foundation.VerticalScrollbar
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
@@ -21,15 +22,20 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollbarAdapter
import androidx.compose.material.Button
import androidx.compose.material.ContentAlpha
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Translate
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -41,12 +47,15 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import ca.gosyer.BuildConfig
import ca.gosyer.data.models.Extension
import ca.gosyer.ui.base.WindowDialog
import ca.gosyer.ui.base.components.ActionIcon
import ca.gosyer.ui.base.components.KtorImage
import ca.gosyer.ui.base.components.LoadingScreen
import ca.gosyer.ui.base.components.Toolbar
import ca.gosyer.ui.base.vm.viewModel
import ca.gosyer.util.compose.ThemedWindow
import ca.gosyer.util.compose.persistentLazyListState
import kotlinx.coroutines.flow.MutableStateFlow
import java.util.Locale
fun openExtensionsMenu() {
@@ -78,6 +87,18 @@ fun ExtensionsMenu() {
searchText = search,
search = {
vm.search(it)
},
actions = {
ActionIcon(
{
val enabledLangs = MutableStateFlow(vm.enabledLangs.value)
LanguageDialog(enabledLangs, vm.getSourceLanguages().toList()) {
vm.setEnabledLanguages(enabledLangs.value)
}
},
"Enabled languages",
Icons.Default.Translate
)
}
)
}
@@ -154,3 +175,34 @@ fun ExtensionItem(
}
}
}
fun LanguageDialog(enabledLangsFlow: MutableStateFlow<Set<String>>, availableLangs: List<String>, setLangs: () -> Unit) {
WindowDialog(BuildConfig.NAME, onPositiveButton = setLangs) {
val enabledLangs by enabledLangsFlow.collectAsState()
val state = rememberLazyListState()
Box {
LazyColumn(Modifier.fillMaxWidth(), state) {
items(availableLangs) { lang ->
Row {
val langName = remember(lang) {
Locale.forLanguageTag(lang)?.displayName ?: lang
}
Text(langName)
Switch(
lang in enabledLangs,
{
if (it) {
enabledLangsFlow.value += lang
} else {
enabledLangsFlow.value -= lang
}
}
)
}
}
item { Spacer(Modifier.height(70.dp)) }
}
VerticalScrollbar(ScrollbarAdapter(state), Modifier.align(Alignment.CenterEnd).padding(8.dp))
}
}
}

View File

@@ -15,6 +15,9 @@ import ca.gosyer.util.lang.throwIfCancellation
import ca.gosyer.util.system.CKLogger
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -24,6 +27,8 @@ class ExtensionsMenuViewModel @Inject constructor(
private val extensionPreferences: ExtensionPreferences
) : ViewModel() {
val serverUrl = serverPreferences.serverUrl().stateIn(scope)
private val _enabledLangs = extensionPreferences.languages().asStateFlow()
val enabledLangs = _enabledLangs.asStateFlow()
private lateinit var extensionList: List<Extension>
@@ -33,21 +38,22 @@ class ExtensionsMenuViewModel @Inject constructor(
private val _isLoading = MutableStateFlow(true)
val isLoading = _isLoading.asStateFlow()
var searchQuery = MutableStateFlow<String?>(null)
val searchQuery = MutableStateFlow<String?>(null)
init {
scope.launch {
getExtensions()
}
enabledLangs.drop(1).onEach {
search(searchQuery.value.orEmpty())
}.launchIn(scope)
}
private suspend fun getExtensions() {
try {
_isLoading.value = true
val enabledLangs = extensionPreferences.languages().get()
extensionList = extensionHandler.getExtensionList()
.filter { it.lang in enabledLangs }
.sortedWith(compareBy({ it.lang }, { it.pkgName }))
search(searchQuery.value.orEmpty())
} catch (e: Exception) {
e.throwIfCancellation()
@@ -93,8 +99,16 @@ class ExtensionsMenuViewModel @Inject constructor(
}
}
fun getSourceLanguages() = extensionList.map { it.lang }.toSet()
fun setEnabledLanguages(langs: Set<String>) {
info { langs }
_enabledLangs.value = langs
}
fun search(searchQuery: String) {
this.searchQuery.value = searchQuery.takeUnless { it.isBlank() }
val extensionList = extensionList.filter { it.lang in enabledLangs.value }
if (searchQuery.isBlank()) {
_extensions.value = extensionList.splitSort()
} else {
@@ -108,10 +122,11 @@ class ExtensionsMenuViewModel @Inject constructor(
}
private fun List<Extension>.splitSort(): List<Extension> {
val obsolete = filter { it.obsolete }.sortedWith(compareBy({ it.lang }, { it.pkgName }))
val updates = filter { it.hasUpdate }.sortedWith(compareBy({ it.lang }, { it.pkgName }))
val installed = filter { it.installed && !it.hasUpdate && !it.obsolete }.sortedWith(compareBy({ it.lang }, { it.pkgName }))
val available = filter { !it.installed }.sortedWith(compareBy({ it.lang }, { it.pkgName }))
val comparator = compareBy<Extension>({ it.lang }, { it.pkgName })
val obsolete = filter { it.obsolete }.sortedWith(comparator)
val updates = filter { it.hasUpdate }.sortedWith(comparator)
val installed = filter { it.installed && !it.hasUpdate && !it.obsolete }.sortedWith(comparator)
val available = filter { !it.installed }.sortedWith(comparator)
return obsolete + updates + installed + available
}