mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-25 11:22:20 +00:00
move file pickers to separate composable
This commit is contained in:
parent
4efc33dba4
commit
05fc53c96f
5 changed files with 76 additions and 52 deletions
61
app/src/main/java/helium314/keyboard/settings/FilePicker.kt
Normal file
61
app/src/main/java/helium314/keyboard/settings/FilePicker.kt
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package helium314.keyboard.settings
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.provider.OpenableColumns
|
||||||
|
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||||
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
|
import androidx.activity.result.ActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import helium314.keyboard.latin.R
|
||||||
|
import helium314.keyboard.latin.utils.LayoutUtilsCustom
|
||||||
|
import helium314.keyboard.latin.utils.getActivity
|
||||||
|
import helium314.keyboard.settings.dialogs.InfoDialog
|
||||||
|
|
||||||
|
val layoutIntent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||||
|
.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("text/*", "application/octet-stream", "application/json"))
|
||||||
|
.setType("*/*")
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun filePicker(onUri: (Uri) -> Unit) =
|
||||||
|
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
|
||||||
|
val uri = it.data?.data ?: return@rememberLauncherForActivityResult
|
||||||
|
onUri(uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun layoutFilePicker(
|
||||||
|
onSuccess: (content: String, name: String?) -> Unit
|
||||||
|
): ManagedActivityResultLauncher<Intent, ActivityResult> {
|
||||||
|
val ctx = LocalContext.current
|
||||||
|
var errorDialog by remember { mutableStateOf(false) }
|
||||||
|
val loadFilePicker = filePicker { uri ->
|
||||||
|
val cr = ctx.getActivity()?.contentResolver ?: return@filePicker
|
||||||
|
val name = cr.query(uri, null, null, null, null)?.use { c ->
|
||||||
|
if (!c.moveToFirst()) return@use null
|
||||||
|
val index = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||||
|
if (index < 0) null
|
||||||
|
else c.getString(index)
|
||||||
|
}
|
||||||
|
cr.openInputStream(uri)?.use {
|
||||||
|
val content = it.reader().readText()
|
||||||
|
errorDialog = !LayoutUtilsCustom.checkLayout(content, ctx)
|
||||||
|
if (!errorDialog)
|
||||||
|
onSuccess(content, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errorDialog)
|
||||||
|
InfoDialog(stringResource(R.string.file_read_error)) { errorDialog = false }
|
||||||
|
return loadFilePicker
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
// 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.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
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
|
||||||
|
@ -52,6 +49,7 @@ import helium314.keyboard.latin.utils.prefs
|
||||||
import helium314.keyboard.settings.Setting
|
import helium314.keyboard.settings.Setting
|
||||||
import helium314.keyboard.settings.SettingsActivity
|
import helium314.keyboard.settings.SettingsActivity
|
||||||
import helium314.keyboard.settings.SettingsDestination
|
import helium314.keyboard.settings.SettingsDestination
|
||||||
|
import helium314.keyboard.settings.filePicker
|
||||||
import helium314.keyboard.settings.keyboardNeedsReload
|
import helium314.keyboard.settings.keyboardNeedsReload
|
||||||
import helium314.keyboard.settings.screens.SaveThoseColors
|
import helium314.keyboard.settings.screens.SaveThoseColors
|
||||||
import kotlinx.serialization.SerializationException
|
import kotlinx.serialization.SerializationException
|
||||||
|
@ -119,9 +117,7 @@ fun ColorThemePickerDialog(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
var errorDialog by remember { mutableStateOf(false) }
|
var errorDialog by remember { mutableStateOf(false) }
|
||||||
val loadFilePicker = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
val loadFilePicker = filePicker { uri ->
|
||||||
if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
|
|
||||||
val uri = it.data?.data ?: return@rememberLauncherForActivityResult
|
|
||||||
ctx.getActivity()?.contentResolver?.openInputStream(uri)?.use {
|
ctx.getActivity()?.contentResolver?.openInputStream(uri)?.use {
|
||||||
errorDialog = !loadColorString(it.reader().readText(), prefs)
|
errorDialog = !loadColorString(it.reader().readText(), prefs)
|
||||||
if (!errorDialog)
|
if (!errorDialog)
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
// 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.Intent
|
|
||||||
import android.provider.OpenableColumns
|
|
||||||
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
|
||||||
|
@ -51,8 +46,12 @@ import helium314.keyboard.latin.utils.prefs
|
||||||
import helium314.keyboard.settings.Setting
|
import helium314.keyboard.settings.Setting
|
||||||
import helium314.keyboard.settings.SettingsActivity
|
import helium314.keyboard.settings.SettingsActivity
|
||||||
import helium314.keyboard.settings.keyboardNeedsReload
|
import helium314.keyboard.settings.keyboardNeedsReload
|
||||||
|
import helium314.keyboard.settings.layoutFilePicker
|
||||||
|
import helium314.keyboard.settings.layoutIntent
|
||||||
|
|
||||||
// modified copy of ColorPickerDialog, later check whether stuff can be re-used
|
// modified copy of ColorPickerDialog, later check whether stuff can be re-used
|
||||||
|
// todo:
|
||||||
|
// call SubtypeSettings.onRenameLayout on rename!
|
||||||
@Composable
|
@Composable
|
||||||
fun LayoutPickerDialog(
|
fun LayoutPickerDialog(
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
|
@ -67,7 +66,6 @@ fun LayoutPickerDialog(
|
||||||
|
|
||||||
val currentLayout = Settings.readDefaultLayoutName(layoutType, prefs)
|
val currentLayout = Settings.readDefaultLayoutName(layoutType, prefs)
|
||||||
val internalLayouts = LayoutUtils.getAvailableLayouts(layoutType, ctx)
|
val internalLayouts = LayoutUtils.getAvailableLayouts(layoutType, ctx)
|
||||||
// todo: getCustomLayoutFiles does not work nicely for main layout, but currently this dialog is not used for them
|
|
||||||
val customLayouts = LayoutUtilsCustom.getLayoutFiles(layoutType, ctx).map { it.name }.sorted()
|
val customLayouts = LayoutUtilsCustom.getLayoutFiles(layoutType, ctx).map { it.name }.sorted()
|
||||||
val layouts = internalLayouts + customLayouts + ""
|
val layouts = internalLayouts + customLayouts + ""
|
||||||
|
|
||||||
|
@ -78,22 +76,8 @@ fun LayoutPickerDialog(
|
||||||
}
|
}
|
||||||
var errorDialog by rememberSaveable { mutableStateOf(false) }
|
var errorDialog by rememberSaveable { mutableStateOf(false) }
|
||||||
var newLayoutDialog: Pair<String, String?>? by rememberSaveable { mutableStateOf(null) }
|
var newLayoutDialog: Pair<String, String?>? by rememberSaveable { mutableStateOf(null) }
|
||||||
val loadFilePicker = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
val picker = layoutFilePicker { content, name ->
|
||||||
if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
|
newLayoutDialog = (name ?: layoutType.default) to content
|
||||||
val uri = it.data?.data ?: return@rememberLauncherForActivityResult
|
|
||||||
val cr = ctx.getActivity()?.contentResolver ?: return@rememberLauncherForActivityResult
|
|
||||||
val name = cr.query(uri, null, null, null, null)?.use { c ->
|
|
||||||
if (!c.moveToFirst()) return@use null
|
|
||||||
val index = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
|
||||||
if (index < 0) null
|
|
||||||
else c.getString(index)
|
|
||||||
}
|
|
||||||
cr.openInputStream(uri)?.use {
|
|
||||||
val content = it.reader().readText()
|
|
||||||
errorDialog = !LayoutUtilsCustom.checkLayout(content, ctx)
|
|
||||||
if (!errorDialog)
|
|
||||||
newLayoutDialog = (name ?: layoutType.default) to content
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ThreeButtonAlertDialog(
|
ThreeButtonAlertDialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
|
@ -101,12 +85,7 @@ fun LayoutPickerDialog(
|
||||||
onConfirmed = { },
|
onConfirmed = { },
|
||||||
confirmButtonText = null,
|
confirmButtonText = null,
|
||||||
neutralButtonText = stringResource(R.string.button_load_custom),
|
neutralButtonText = stringResource(R.string.button_load_custom),
|
||||||
onNeutral = {
|
onNeutral = { picker.launch(layoutIntent) },
|
||||||
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) },
|
|
||||||
title = { Text(setting.title) },
|
title = { Text(setting.title) },
|
||||||
text = {
|
text = {
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
package helium314.keyboard.settings.preferences
|
package helium314.keyboard.settings.preferences
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
@ -27,7 +24,6 @@ import helium314.keyboard.latin.R
|
||||||
import helium314.keyboard.latin.checkVersionUpgrade
|
import helium314.keyboard.latin.checkVersionUpgrade
|
||||||
import helium314.keyboard.latin.common.FileUtils
|
import helium314.keyboard.latin.common.FileUtils
|
||||||
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
|
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
|
||||||
import helium314.keyboard.latin.settings.Defaults
|
|
||||||
import helium314.keyboard.latin.settings.Settings
|
import helium314.keyboard.latin.settings.Settings
|
||||||
import helium314.keyboard.latin.settings.USER_DICTIONARY_SUFFIX
|
import helium314.keyboard.latin.settings.USER_DICTIONARY_SUFFIX
|
||||||
import helium314.keyboard.latin.utils.DeviceProtectedUtils
|
import helium314.keyboard.latin.utils.DeviceProtectedUtils
|
||||||
|
@ -35,7 +31,6 @@ import helium314.keyboard.latin.utils.ExecutorUtils
|
||||||
import helium314.keyboard.latin.utils.LayoutUtilsCustom
|
import helium314.keyboard.latin.utils.LayoutUtilsCustom
|
||||||
import helium314.keyboard.latin.utils.Log
|
import helium314.keyboard.latin.utils.Log
|
||||||
import helium314.keyboard.latin.utils.SubtypeSettings
|
import helium314.keyboard.latin.utils.SubtypeSettings
|
||||||
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
|
|
||||||
import helium314.keyboard.latin.utils.getActivity
|
import helium314.keyboard.latin.utils.getActivity
|
||||||
import helium314.keyboard.latin.utils.prefs
|
import helium314.keyboard.latin.utils.prefs
|
||||||
import helium314.keyboard.latin.utils.protectedPrefs
|
import helium314.keyboard.latin.utils.protectedPrefs
|
||||||
|
@ -43,6 +38,7 @@ import helium314.keyboard.settings.Setting
|
||||||
import helium314.keyboard.settings.SettingsActivity
|
import helium314.keyboard.settings.SettingsActivity
|
||||||
import helium314.keyboard.settings.dialogs.ConfirmationDialog
|
import helium314.keyboard.settings.dialogs.ConfirmationDialog
|
||||||
import helium314.keyboard.settings.dialogs.InfoDialog
|
import helium314.keyboard.settings.dialogs.InfoDialog
|
||||||
|
import helium314.keyboard.settings.filePicker
|
||||||
import helium314.keyboard.settings.keyboardNeedsReload
|
import helium314.keyboard.settings.keyboardNeedsReload
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -67,12 +63,10 @@ fun BackupRestorePreference(setting: Setting) {
|
||||||
"custom_background_image.*".toRegex(),
|
"custom_background_image.*".toRegex(),
|
||||||
"custom_font".toRegex(),
|
"custom_font".toRegex(),
|
||||||
) }
|
) }
|
||||||
val backupLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
val backupLauncher = filePicker { uri ->
|
||||||
if (result.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
|
|
||||||
val uri = result.data?.data ?: return@rememberLauncherForActivityResult
|
|
||||||
// zip all files matching the backup patterns
|
// zip all files matching the backup patterns
|
||||||
// essentially this is the typed words information, and user-added dictionaries
|
// essentially this is the typed words information, and user-added dictionaries
|
||||||
val filesDir = ctx.filesDir ?: return@rememberLauncherForActivityResult
|
val filesDir = ctx.filesDir ?: return@filePicker
|
||||||
val filesPath = filesDir.path + File.separator
|
val filesPath = filesDir.path + File.separator
|
||||||
val files = mutableListOf<File>()
|
val files = mutableListOf<File>()
|
||||||
filesDir.walk().forEach { file ->
|
filesDir.walk().forEach { file ->
|
||||||
|
@ -125,9 +119,7 @@ fun BackupRestorePreference(setting: Setting) {
|
||||||
}
|
}
|
||||||
wait.await()
|
wait.await()
|
||||||
}
|
}
|
||||||
val restoreLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
val restoreLauncher = filePicker { uri ->
|
||||||
if (result.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
|
|
||||||
val uri = result.data?.data ?: return@rememberLauncherForActivityResult
|
|
||||||
val wait = CountDownLatch(1)
|
val wait = CountDownLatch(1)
|
||||||
ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute {
|
ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
package helium314.keyboard.settings.preferences
|
package helium314.keyboard.settings.preferences
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
@ -23,6 +20,7 @@ import helium314.keyboard.latin.utils.JniUtils
|
||||||
import helium314.keyboard.latin.utils.protectedPrefs
|
import helium314.keyboard.latin.utils.protectedPrefs
|
||||||
import helium314.keyboard.settings.Setting
|
import helium314.keyboard.settings.Setting
|
||||||
import helium314.keyboard.settings.dialogs.ConfirmationDialog
|
import helium314.keyboard.settings.dialogs.ConfirmationDialog
|
||||||
|
import helium314.keyboard.settings.filePicker
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
@ -43,9 +41,7 @@ fun LoadGestureLibPreference(setting: Setting) {
|
||||||
Runtime.getRuntime().exit(0) // exit will restart the app, so library will be loaded
|
Runtime.getRuntime().exit(0) // exit will restart the app, so library will be loaded
|
||||||
}
|
}
|
||||||
var tempFilePath: String? by rememberSaveable { mutableStateOf(null) }
|
var tempFilePath: String? by rememberSaveable { mutableStateOf(null) }
|
||||||
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
val launcher = filePicker { uri ->
|
||||||
if (result.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
|
|
||||||
val uri = result.data?.data ?: return@rememberLauncherForActivityResult
|
|
||||||
val tmpfile = File(ctx.filesDir.absolutePath + File.separator + "tmplib")
|
val tmpfile = File(ctx.filesDir.absolutePath + File.separator + "tmplib")
|
||||||
try {
|
try {
|
||||||
val otherTemporaryFile = File(ctx.filesDir.absolutePath + File.separator + "tmpfile")
|
val otherTemporaryFile = File(ctx.filesDir.absolutePath + File.separator + "tmpfile")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue