11package com.addev.listaspam
22
3+ import android.content.Context
4+ import android.net.Uri
35import android.os.Bundle
6+ import android.widget.Button
7+ import android.widget.Toast
8+ import androidx.activity.result.contract.ActivityResultContracts
49import androidx.appcompat.app.AppCompatActivity
510import androidx.preference.PreferenceFragmentCompat
11+ import org.json.JSONArray
12+ import org.json.JSONException
13+ import org.json.JSONObject
14+ import java.io.File
615
716class SettingsActivity : AppCompatActivity () {
17+ private val exportFileLauncher = registerForActivityResult(ActivityResultContracts .CreateDocument (" application/json" )) { uri: Uri ? ->
18+ uri?.let {
19+ if (exportAllSharedPreferences(it)) {
20+ Toast .makeText(this , " Preferencias exportadas con éxito" , Toast .LENGTH_SHORT ).show()
21+ } else {
22+ Toast .makeText(this , " Error al exportar preferencias" , Toast .LENGTH_SHORT ).show()
23+ }
24+ }
25+ }
26+
27+ private val importFileLauncher = registerForActivityResult(ActivityResultContracts .OpenDocument ()) { uri: Uri ? ->
28+ uri?.let {
29+ if (importAllSharedPreferences(it)) {
30+ Toast .makeText(this , " Preferencias importadas con éxito" , Toast .LENGTH_SHORT ).show()
31+ } else {
32+ Toast .makeText(this , " Error al importar preferencias" , Toast .LENGTH_SHORT ).show()
33+ }
34+ }
35+ }
36+
837 override fun onCreate (savedInstanceState : Bundle ? ) {
938 super .onCreate(savedInstanceState)
1039 setContentView(R .layout.activity_settings)
@@ -13,6 +42,17 @@ class SettingsActivity : AppCompatActivity() {
1342 .beginTransaction()
1443 .replace(R .id.settings_container, SettingsFragment ())
1544 .commit()
45+
46+ val exportButton: Button = findViewById(R .id.btn_export)
47+ val importButton: Button = findViewById(R .id.btn_import)
48+
49+ exportButton.setOnClickListener {
50+ exportFileLauncher.launch(" backup_prefs.json" )
51+ }
52+
53+ importButton.setOnClickListener {
54+ importFileLauncher.launch(arrayOf(" application/json" ))
55+ }
1656 }
1757
1858 // Fragmento para cargar las preferencias
@@ -21,4 +61,117 @@ class SettingsActivity : AppCompatActivity() {
2161 setPreferencesFromResource(R .xml.preferences, rootKey)
2262 }
2363 }
64+
65+ private fun exportAllSharedPreferences (uri : Uri ): Boolean {
66+ return try {
67+ val prefsDir = File (applicationInfo.dataDir, " shared_prefs" )
68+ val files = prefsDir.listFiles()
69+ val jsonObject = JSONObject ()
70+
71+ files?.forEach { file ->
72+ val prefName = file.nameWithoutExtension
73+ val sharedPreferences = getSharedPreferences(prefName, Context .MODE_PRIVATE )
74+ val allEntries: Map <String , * > = sharedPreferences.all
75+
76+ val prefJsonObject = JSONObject ()
77+ for ((key, value) in allEntries) {
78+ when (value) {
79+ is Set <* > -> {
80+ val jsonArray = JSONArray (value)
81+ prefJsonObject.put(key, jsonArray)
82+ }
83+ else -> prefJsonObject.put(key, value)
84+ }
85+ }
86+
87+ jsonObject.put(prefName, prefJsonObject)
88+ }
89+
90+ contentResolver.openOutputStream(uri)?.use { outputStream ->
91+ outputStream.write(jsonObject.toString().toByteArray())
92+ }
93+ true
94+ } catch (e: Exception ) {
95+ e.printStackTrace()
96+ false
97+ }
98+ }
99+
100+ private fun importAllSharedPreferences (uri : Uri ): Boolean {
101+ return try {
102+ contentResolver.openInputStream(uri)?.use { inputStream ->
103+ val jsonString = inputStream.bufferedReader().use { it.readText() }
104+ val jsonObject = JSONObject (jsonString)
105+
106+ // Validar el archivo JSON antes de importar
107+ if (! isValidSharedPreferencesJson(jsonObject)) {
108+ Toast .makeText(this , " El archivo JSON no es válido" , Toast .LENGTH_SHORT ).show()
109+ return false
110+ }
111+
112+ for (prefName in jsonObject.keys()) {
113+ val sharedPreferences = getSharedPreferences(prefName, Context .MODE_PRIVATE )
114+ val editor = sharedPreferences.edit()
115+
116+ val prefJsonObject = jsonObject.getJSONObject(prefName)
117+ for (key in prefJsonObject.keys()) {
118+ val value = prefJsonObject.get(key)
119+ when (value) {
120+ is JSONArray -> {
121+ val set = mutableSetOf<String >()
122+ for (i in 0 until value.length()) {
123+ set.add(value.getString(i))
124+ }
125+ editor.putStringSet(key, set)
126+ }
127+ is Int -> editor.putInt(key, value)
128+ is Long -> editor.putLong(key, value)
129+ is Float -> editor.putFloat(key, value)
130+ is Boolean -> editor.putBoolean(key, value)
131+ is String -> editor.putString(key, value)
132+ else -> throw IllegalArgumentException (" Tipo no soportado" )
133+ }
134+ }
135+ editor.apply ()
136+ }
137+ }
138+ true
139+ } catch (e: Exception ) {
140+ e.printStackTrace()
141+ false
142+ }
143+ }
144+
145+ private fun isValidSharedPreferencesJson (jsonObject : JSONObject ): Boolean {
146+ return try {
147+ for (prefName in jsonObject.keys()) {
148+ val prefJsonObject = jsonObject.getJSONObject(prefName)
149+
150+ // Verificar cada valor en las SharedPreferences
151+ for (key in prefJsonObject.keys()) {
152+ val value = prefJsonObject.get(key)
153+ when (value) {
154+ is JSONArray -> {
155+ // Verificar que el JSONArray contiene solo Strings
156+ for (i in 0 until value.length()) {
157+ if (value.get(i) !is String ) {
158+ return false
159+ }
160+ }
161+ }
162+ is Int , is Long , is Float , is Boolean , is String -> {
163+ // Tipos válidos, no hacer nada
164+ }
165+ else -> {
166+ return false
167+ }
168+ }
169+ }
170+ }
171+ true
172+ } catch (e: JSONException ) {
173+ e.printStackTrace()
174+ false
175+ }
176+ }
24177}
0 commit comments