mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-04-19 13:49:13 +00:00
add settings to backup
This commit is contained in:
parent
7ae0d0783d
commit
6968488e45
5 changed files with 74 additions and 7 deletions
|
@ -1,5 +1,6 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
android {
|
||||
compileSdk 34
|
||||
|
@ -78,6 +79,7 @@ dependencies {
|
|||
implementation 'androidx.preference:preference:1.2.1' // includes appcompat
|
||||
implementation 'androidx.recyclerview:recyclerview:1.3.1'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1" // why not working with 1.6.0?
|
||||
implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
|
|
@ -11,6 +11,7 @@ import android.content.SharedPreferences
|
|||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.Preference
|
||||
|
@ -23,9 +24,13 @@ import org.dslul.openboard.inputmethod.latin.SystemBroadcastReceiver
|
|||
import org.dslul.openboard.inputmethod.latin.common.FileUtils
|
||||
import org.dslul.openboard.inputmethod.latin.define.JniLibName
|
||||
import org.dslul.openboard.inputmethod.latin.settings.SeekBarDialogPreference.ValueProxy
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dslul.openboard.inputmethod.keyboard.KeyboardSwitcher
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.IOException
|
||||
import java.io.Writer
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
@ -43,6 +48,7 @@ import java.util.zip.ZipOutputStream
|
|||
* - Debug settings
|
||||
*/
|
||||
class AdvancedSettingsFragment : SubScreenFragment() {
|
||||
private val TAG = this::class.simpleName
|
||||
private var libfile: File? = null
|
||||
private val backupFilePatterns by lazy { listOf(
|
||||
"blacklists/.*\\.txt".toRegex(),
|
||||
|
@ -166,10 +172,6 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
if (backupFilePatterns.any { path.matches(it) })
|
||||
files.add(file)
|
||||
}
|
||||
if (files.isEmpty()) {
|
||||
infoDialog(requireContext(), R.string.backup_error)
|
||||
return
|
||||
}
|
||||
try {
|
||||
activity?.contentResolver?.openOutputStream(uri)?.use { os ->
|
||||
// write files to zip
|
||||
|
@ -181,11 +183,14 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
fileStream.close()
|
||||
zipStream.closeEntry()
|
||||
}
|
||||
zipStream.putNextEntry(ZipEntry(PREFS_FILE_NAME))
|
||||
zipStream.bufferedWriter().use { settingsToJsonStream(sharedPreferences.all, it) }
|
||||
zipStream.close()
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
// inform about every error
|
||||
infoDialog(requireContext(), R.string.backup_error)
|
||||
Log.w(TAG, "error during backup", t)
|
||||
infoDialog(requireContext(), requireContext().getString(R.string.backup_error, t.message))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,6 +204,10 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
if (backupFilePatterns.any { entry!!.name.matches(it) }) {
|
||||
val file = File(filesDir, entry.name)
|
||||
FileUtils.copyStreamToNewFile(zip, file)
|
||||
} else if (entry.name == PREFS_FILE_NAME) {
|
||||
val prefLines = String(zip.readBytes()).split("\n")
|
||||
sharedPreferences.edit().clear().apply()
|
||||
readJsonLinesToSettings(prefLines)
|
||||
}
|
||||
zip.closeEntry()
|
||||
entry = zip.nextEntry
|
||||
|
@ -207,8 +216,13 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
}
|
||||
val newDictBroadcast = Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION)
|
||||
activity?.sendBroadcast(newDictBroadcast)
|
||||
// reload current prefs screen
|
||||
preferenceScreen.removeAll()
|
||||
onCreate(null)
|
||||
KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext())
|
||||
} catch (t: Throwable) {
|
||||
// inform about every error
|
||||
Log.w(TAG, "error during restore", t)
|
||||
infoDialog(requireContext(), requireContext().getString(R.string.restore_error, t.message))
|
||||
}
|
||||
}
|
||||
|
@ -231,6 +245,50 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
})
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST") // it is checked... but whatever (except string set, because can't check for that))
|
||||
private fun settingsToJsonStream(settings: Map<String, Any?>, out: Writer) {
|
||||
val booleans = settings.filterValues { it is Boolean } as Map<String, Boolean>
|
||||
val ints = settings.filterValues { it is Int } as Map<String, Int>
|
||||
val longs = settings.filterValues { it is Long } as Map<String, Long>
|
||||
val floats = settings.filterValues { it is Float } as Map<String, Float>
|
||||
val strings = settings.filterValues { it is String } as Map<String, String>
|
||||
val stringSets = settings.filterValues { it is Set<*> } as Map<String, Set<String>>
|
||||
// now write
|
||||
out.appendLine("boolean settings")
|
||||
out.appendLine( Json.encodeToString(booleans))
|
||||
out.appendLine("int settings")
|
||||
out.appendLine( Json.encodeToString(ints))
|
||||
out.appendLine("long settings")
|
||||
out.appendLine( Json.encodeToString(longs))
|
||||
out.appendLine("float settings")
|
||||
out.appendLine( Json.encodeToString(floats))
|
||||
out.appendLine("string settings")
|
||||
out.appendLine( Json.encodeToString(strings))
|
||||
out.appendLine("string set settings")
|
||||
out.appendLine( Json.encodeToString(stringSets))
|
||||
}
|
||||
|
||||
private fun readJsonLinesToSettings(list: List<String>): Boolean {
|
||||
val i = list.iterator()
|
||||
val e = sharedPreferences.edit()
|
||||
try {
|
||||
while (i.hasNext()) {
|
||||
when (i.next()) {
|
||||
"boolean settings" -> Json.decodeFromString<Map<String, Boolean>>(i.next()).forEach { e.putBoolean(it.key, it.value) }
|
||||
"int settings" -> Json.decodeFromString<Map<String, Int>>(i.next()).forEach { e.putInt(it.key, it.value) }
|
||||
"long settings" -> Json.decodeFromString<Map<String, Long>>(i.next()).forEach { e.putLong(it.key, it.value) }
|
||||
"float settings" -> Json.decodeFromString<Map<String, Float>>(i.next()).forEach { e.putFloat(it.key, it.value) }
|
||||
"string settings" -> Json.decodeFromString<Map<String, String>>(i.next()).forEach { e.putString(it.key, it.value) }
|
||||
"string set settings" -> Json.decodeFromString<Map<String, Set<String>>>(i.next()).forEach { e.putStringSet(it.key, it.value) }
|
||||
}
|
||||
}
|
||||
e.apply()
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String?) {
|
||||
if (Settings.PREF_SHOW_SETUP_WIZARD_ICON == key) {
|
||||
SystemBroadcastReceiver.toggleAppIcon(requireContext())
|
||||
|
@ -239,3 +297,5 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val PREFS_FILE_NAME = "preferences.json"
|
||||
|
|
|
@ -181,7 +181,7 @@ Nouveau dictionnaire:
|
|||
<string name="space_language_slide_summary">Glissez sur la barre d\'espace vers le haut pour changer de langue</string>
|
||||
<string name="backup_restore_title">Sauvegarde et restauration</string>
|
||||
<string name="backup_restore_message">Sauvegarde ou chargement à partir d\'un fichier. Attention : la restauration écrasera les données existantes.</string>
|
||||
<string name="backup_error">Erreur lors de la sauvegarde</string>
|
||||
<string name="backup_error">Erreur lors de la sauvegarde : %s</string>
|
||||
<string name="restore_error">Erreur lors de la restauration de la sauvegarde : %s</string>
|
||||
<string name="button_backup">Sauvegarder</string>
|
||||
<string name="button_restore">Restaurer</string>
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
<!-- Message for backup and restore dialog -->
|
||||
<string name="backup_restore_message">Save or load from file. Warning: restore will overwrite existing data</string>
|
||||
<!-- Error message for backup -->
|
||||
<string name="backup_error">Backup error</string>
|
||||
<string name="backup_error">Backup error: %s</string>
|
||||
<!-- Error message for restore, %s is replaced by the error message -->
|
||||
<string name="restore_error">Error restoring the backup: %s</string>
|
||||
<!-- backup button -->
|
||||
|
|
|
@ -9,12 +9,17 @@ buildscript {
|
|||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.1.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.10' apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
|
|
Loading…
Add table
Reference in a new issue