mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-06-10 00:27:45 +00:00
add option to load colors
This commit is contained in:
parent
6d9763d079
commit
e105f39752
3 changed files with 95 additions and 13 deletions
|
@ -378,6 +378,22 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) {
|
||||||
return colorMap
|
return colorMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getUnusedThemeName(initialName: String, prefs: SharedPreferences): String {
|
||||||
|
val existingNames = prefs.all.keys.mapNotNull {
|
||||||
|
when {
|
||||||
|
it.startsWith(Settings.PREF_USER_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_COLORS_PREFIX)
|
||||||
|
it.startsWith(Settings.PREF_USER_ALL_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_ALL_COLORS_PREFIX)
|
||||||
|
it.startsWith(Settings.PREF_USER_MORE_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_MORE_COLORS_PREFIX)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}.toSortedSet()
|
||||||
|
if (initialName !in existingNames) return initialName
|
||||||
|
var i = 1
|
||||||
|
while ("$initialName$i" in existingNames)
|
||||||
|
i++
|
||||||
|
return "$initialName$i"
|
||||||
|
}
|
||||||
|
|
||||||
// returns false if not renamed due to invalid name or collision
|
// returns false if not renamed due to invalid name or collision
|
||||||
fun renameUserColors(from: String, to: String, prefs: SharedPreferences): Boolean {
|
fun renameUserColors(from: String, to: String, prefs: SharedPreferences): Boolean {
|
||||||
if (to.isBlank()) return false // don't want that
|
if (to.isBlank()) return false // don't want that
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
package helium314.keyboard.settings.dialogs
|
package helium314.keyboard.settings.dialogs
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
@ -31,16 +38,23 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import helium314.keyboard.keyboard.ColorSetting
|
||||||
import helium314.keyboard.keyboard.KeyboardTheme
|
import helium314.keyboard.keyboard.KeyboardTheme
|
||||||
import helium314.keyboard.latin.R
|
import helium314.keyboard.latin.R
|
||||||
|
import helium314.keyboard.latin.common.ColorType
|
||||||
import helium314.keyboard.latin.settings.Settings
|
import helium314.keyboard.latin.settings.Settings
|
||||||
|
import helium314.keyboard.latin.utils.decodeBase36
|
||||||
|
import helium314.keyboard.latin.utils.getActivity
|
||||||
import helium314.keyboard.latin.utils.getStringResourceOrName
|
import helium314.keyboard.latin.utils.getStringResourceOrName
|
||||||
import helium314.keyboard.latin.utils.prefs
|
import helium314.keyboard.latin.utils.prefs
|
||||||
import helium314.keyboard.settings.Setting
|
import helium314.keyboard.settings.Setting
|
||||||
import helium314.keyboard.settings.SettingsDestination
|
import helium314.keyboard.settings.SettingsDestination
|
||||||
import helium314.keyboard.settings.keyboardNeedsReload
|
import helium314.keyboard.settings.keyboardNeedsReload
|
||||||
|
import helium314.keyboard.settings.screens.SaveThoseColors
|
||||||
|
import kotlinx.serialization.SerializationException
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import java.util.EnumMap
|
||||||
|
|
||||||
// specialized variant of ListPickerDialog
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ColorThemePickerDialog(
|
fun ColorThemePickerDialog(
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
|
@ -71,16 +85,14 @@ fun ColorThemePickerDialog(
|
||||||
val index = colors.indexOf(selectedColor)
|
val index = colors.indexOf(selectedColor)
|
||||||
if (index != -1) state.scrollToItem(index, -state.layoutInfo.viewportSize.height / 3)
|
if (index != -1) state.scrollToItem(index, -state.layoutInfo.viewportSize.height / 3)
|
||||||
}
|
}
|
||||||
|
var showLoadDialog by remember { mutableStateOf(false) }
|
||||||
ThreeButtonAlertDialog(
|
ThreeButtonAlertDialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
cancelButtonText = stringResource(R.string.dialog_close),
|
cancelButtonText = stringResource(R.string.dialog_close),
|
||||||
onConfirmed = { },
|
onConfirmed = { },
|
||||||
confirmButtonText = null,
|
confirmButtonText = null,
|
||||||
// neutralButtonText = stringResource(R.string.load),
|
neutralButtonText = stringResource(R.string.load),
|
||||||
onNeutral = {
|
onNeutral = { showLoadDialog = true },
|
||||||
// todo: launcher to select file
|
|
||||||
// when importing make sure name is not in use
|
|
||||||
},
|
|
||||||
title = { Text(setting.title) },
|
title = { Text(setting.title) },
|
||||||
text = {
|
text = {
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
|
@ -173,6 +185,66 @@ fun ColorThemePickerDialog(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
if (showLoadDialog) {
|
||||||
|
var errorDialog by remember { mutableStateOf(false) }
|
||||||
|
val loadFilePicker = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
|
||||||
|
val uri = it.data?.data ?: return@rememberLauncherForActivityResult
|
||||||
|
ctx.getActivity()?.contentResolver?.openInputStream(uri)?.use {
|
||||||
|
errorDialog = loadColorString(it.reader().readText(), prefs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConfirmationDialog(
|
||||||
|
onDismissRequest = { showLoadDialog = false },
|
||||||
|
onConfirmed = {
|
||||||
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||||
|
.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("text/*", "application/octet-stream", "application/json"))
|
||||||
|
.setType("*/*")
|
||||||
|
loadFilePicker.launch(intent)
|
||||||
|
},
|
||||||
|
confirmButtonText = stringResource(R.string.button_load_custom),
|
||||||
|
onNeutral = {
|
||||||
|
val cm = ctx.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
val clip = cm.primaryClip?.takeIf { it.itemCount > 0 } ?: return@ConfirmationDialog
|
||||||
|
val text = clip.getItemAt(0).text
|
||||||
|
errorDialog = loadColorString(text.toString(), prefs)
|
||||||
|
},
|
||||||
|
neutralButtonText = "load from clipboard" // todo: this is too long, maybe better if "load file" is changed to "load"?
|
||||||
|
)
|
||||||
|
if (errorDialog)
|
||||||
|
InfoDialog("error") { showLoadDialog = false } // also error dialog to false?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadColorString(colorString: String, prefs: SharedPreferences): Boolean {
|
||||||
|
try {
|
||||||
|
val that = Json.decodeFromString<SaveThoseColors>(colorString)
|
||||||
|
val themeName = KeyboardTheme.getUnusedThemeName(that.name ?: "imported colors", prefs)
|
||||||
|
val colors = that.colors.map { ColorSetting(it.key, it.value.second, it.value.first) }
|
||||||
|
KeyboardTheme.writeUserColors(prefs, themeName, colors)
|
||||||
|
KeyboardTheme.writeUserMoreColors(prefs, themeName, that.moreColors)
|
||||||
|
} catch (e: SerializationException) {
|
||||||
|
try {
|
||||||
|
val allColorsStringMap = Json.decodeFromString<Map<String, Int>>(colorString)
|
||||||
|
val allColors = EnumMap<ColorType, Int>(ColorType::class.java)
|
||||||
|
var themeName = "imported colors"
|
||||||
|
allColorsStringMap.forEach {
|
||||||
|
try {
|
||||||
|
allColors[ColorType.valueOf(it.key)] = it.value
|
||||||
|
} catch (_: IllegalArgumentException) {
|
||||||
|
themeName = decodeBase36(it.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
themeName = KeyboardTheme.getUnusedThemeName(themeName, prefs)
|
||||||
|
KeyboardTheme.writeUserAllColors(prefs, themeName, allColors)
|
||||||
|
KeyboardTheme.writeUserMoreColors(prefs, themeName, 2)
|
||||||
|
} catch (e: SerializationException) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyboardNeedsReload = true
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
|
|
|
@ -73,12 +73,6 @@ fun ColorsScreen(
|
||||||
isNight: Boolean,
|
isNight: Boolean,
|
||||||
onClickBack: () -> Unit
|
onClickBack: () -> Unit
|
||||||
) {
|
) {
|
||||||
// todo:
|
|
||||||
// allow save (load should be in theme selector, maybe here too)
|
|
||||||
// import/export should now also store theme name
|
|
||||||
// handle name collisions on load by simply appending a number
|
|
||||||
// make sure import of old colors works
|
|
||||||
|
|
||||||
val ctx = LocalContext.current
|
val ctx = LocalContext.current
|
||||||
|
|
||||||
// is there really no better way of only setting forceOpposite while the screen is shown (and not paused)?
|
// is there really no better way of only setting forceOpposite while the screen is shown (and not paused)?
|
||||||
|
@ -163,7 +157,7 @@ fun ColorsScreen(
|
||||||
stringResource(R.string.save) to {
|
stringResource(R.string.save) to {
|
||||||
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
|
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
|
||||||
.addCategory(Intent.CATEGORY_OPENABLE)
|
.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
.putExtra(Intent.EXTRA_TITLE,"theme.json")
|
.putExtra(Intent.EXTRA_TITLE,"${newThemeName.text}.json")
|
||||||
.setType("application/json")
|
.setType("application/json")
|
||||||
saveLauncher.launch(intent)
|
saveLauncher.launch(intent)
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue