refactor: Clean up UI components and improve JSON import/export
- Removed unused parameters and functions related to biometric protection and save/reset operations in AppShell.kt and AppDialogs.kt. - Simplified logging and toast messages in JsonImportExportDialog.kt. - Improved null safety and file output stream handling in JsonImportExportDialog.kt. - Updated AndroidManifest.xml with target API level and tools namespace.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
@@ -16,7 +17,8 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:theme="@style/Theme.Noteshop">
|
||||
android:theme="@style/Theme.Noteshop"
|
||||
tools:targetApi="33">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
|
||||
@@ -1084,8 +1084,8 @@ fun AppShell(
|
||||
onShowListDialogChange = { setShowListDialog(it) },
|
||||
listDetails = listDetails,
|
||||
onListDetailsChange = { shoppingListsViewModel.updateListDetails(it) },
|
||||
onSaveList = { scope.launch { shoppingListsViewModel.saveList() } },
|
||||
onResetListDetails = { shoppingListsViewModel.resetListDetails() },
|
||||
|
||||
|
||||
onSetListProtection = { password ->
|
||||
selectedListId?.let { listId ->
|
||||
shoppingListsViewModel.setProtection(listId, password)
|
||||
@@ -1095,32 +1095,20 @@ fun AppShell(
|
||||
setShowSetListPasswordDialog(false)
|
||||
},
|
||||
|
||||
onSetListProtectionBiometric = { id ->
|
||||
shoppingListsViewModel.setProtectionBiometric(id)
|
||||
setCurrentScreen(Screen.ShoppingLists)
|
||||
},
|
||||
|
||||
txtImportLauncher = txtImportLauncher,
|
||||
showNoteDialog = showNoteDialog,
|
||||
onShowNoteDialogChange = { setShowNoteDialog(it) },
|
||||
noteDetails = noteDetails,
|
||||
onNoteDetailsChange = { notesViewModel.updateNoteDetails(it) },
|
||||
onSaveNote = { scope.launch { notesViewModel.saveNote() } },
|
||||
onResetNoteDetails = { notesViewModel.resetNoteDetails() },
|
||||
onSetNoteProtectionBiometric = { id ->
|
||||
notesViewModel.setProtectionBiometric(id)
|
||||
setCurrentScreen(Screen.Notes)
|
||||
},
|
||||
|
||||
|
||||
noteImportLauncher = noteImportLauncher,
|
||||
showRecipeDialog = showRecipeDialog,
|
||||
onShowRecipeDialogChange = { setShowRecipeDialog(it) },
|
||||
recipeDetails = recipeDetails,
|
||||
onRecipeDetailsChange = { recipesViewModel.updateRecipeDetails(it) },
|
||||
onSaveRecipe = { scope.launch { recipesViewModel.saveRecipe() } },
|
||||
onResetRecipeDetails = { recipesViewModel.resetRecipeDetails() },
|
||||
onSetRecipeProtectionBiometric = { id ->
|
||||
recipesViewModel.setProtectionBiometric(id)
|
||||
setCurrentScreen(Screen.Recipes)
|
||||
},
|
||||
|
||||
recipeImportLauncher = recipeImportLauncher,
|
||||
recipesTitle = recipesTitle,
|
||||
showJsonDialog = showJsonDialog,
|
||||
@@ -1276,7 +1264,6 @@ fun AppShell(
|
||||
setItemToLockType(null)
|
||||
},
|
||||
canUseBiometrics = canUseBiometrics,
|
||||
itemToLockType = itemToLockType,
|
||||
showStartupPasswordDialog = showStartupPasswordDialog,
|
||||
onShowStartupPasswordDialogChange = { setShowStartupPasswordDialog(it) },
|
||||
onUnlockEncryption = { password ->
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.lxtools.noteshop.ui
|
||||
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -89,14 +90,14 @@ fun JsonImportExportDialog(
|
||||
scope.launch {
|
||||
context.contentResolver.openInputStream(it)?.use { inputStream ->
|
||||
val fileContent = inputStream.readBytes()
|
||||
var jsonString: String? = null
|
||||
var jsonString: String?
|
||||
|
||||
if (secretKey != null) {
|
||||
try {
|
||||
val decryptedBytes = fileEncryptor.decrypt(fileContent, secretKey!!)
|
||||
jsonString = decryptedBytes.toString(Charsets.UTF_8)
|
||||
} catch (e: javax.crypto.AEADBadTagException) {
|
||||
android.util.Log.w("JsonImportExportDialog", "Decryption failed, trying as unencrypted: ${e.message}")
|
||||
Log.w("JsonImportExportDialog", "Decryption failed, trying as unencrypted: ${e.message}")
|
||||
// Fallback to unencrypted if decryption fails
|
||||
jsonString = fileContent.toString(Charsets.UTF_8)
|
||||
}
|
||||
@@ -106,14 +107,14 @@ fun JsonImportExportDialog(
|
||||
}
|
||||
|
||||
try {
|
||||
notesViewModel.importNotesFromJson(jsonString!!)
|
||||
android.widget.Toast.makeText(context, R.string.json_import_successful, android.widget.Toast.LENGTH_SHORT).show()
|
||||
} catch (e: kotlinx.serialization.SerializationException) {
|
||||
android.util.Log.e("JsonImportExportDialog", "Error parsing notes JSON: ${e.message}")
|
||||
android.widget.Toast.makeText(context, context.getString(R.string.json_import_failed_invalid_format, e.message), android.widget.Toast.LENGTH_LONG).show()
|
||||
notesViewModel.importNotesFromJson(jsonString)
|
||||
Toast.makeText(context, R.string.json_import_successful, Toast.LENGTH_SHORT).show()
|
||||
} catch (e: SerializationException) {
|
||||
Log.e("JsonImportExportDialog", "Error parsing notes JSON: ${e.message}")
|
||||
Toast.makeText(context, context.getString(R.string.json_import_failed_invalid_format, e.message), Toast.LENGTH_LONG).show()
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("JsonImportExportDialog", "Error importing notes: ${e.message}")
|
||||
android.widget.Toast.makeText(context, context.getString(R.string.json_import_failed_generic, e.message), android.widget.Toast.LENGTH_LONG).show()
|
||||
Log.e("JsonImportExportDialog", "Error importing notes: ${e.message}")
|
||||
Toast.makeText(context, context.getString(R.string.json_import_failed_generic, e.message), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,12 +130,14 @@ fun JsonImportExportDialog(
|
||||
scope.launch {
|
||||
val allNotes = notesViewModel.uiState.value.noteList
|
||||
val content = notesViewModel.exportNotesToJson(allNotes)
|
||||
context.contentResolver.openOutputStream(it)?.use { outputStream ->
|
||||
secretKey?.let { key ->
|
||||
val encryptedContent = fileEncryptor.encrypt(content.toByteArray(), key)
|
||||
context.contentResolver.openOutputStream(it, "wt")?.use { outputStream ->
|
||||
if (secretKey != null) {
|
||||
val encryptedContent = fileEncryptor.encrypt(content.toByteArray(), secretKey!!)
|
||||
outputStream.write(encryptedContent)
|
||||
} else {
|
||||
outputStream.write(content.toByteArray(Charsets.UTF_8))
|
||||
}
|
||||
android.widget.Toast.makeText(context, R.string.json_export_successful, android.widget.Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(context, R.string.json_export_successful, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,12 +152,14 @@ fun JsonImportExportDialog(
|
||||
scope.launch {
|
||||
val allShoppingLists = shoppingListsViewModel.uiState.value.shoppingLists
|
||||
val content = shoppingListsViewModel.exportShoppingListsToJson(allShoppingLists)
|
||||
context.contentResolver.openOutputStream(it)?.use { outputStream ->
|
||||
secretKey?.let { key ->
|
||||
val encryptedContent = fileEncryptor.encrypt(content.toByteArray(), key)
|
||||
context.contentResolver.openOutputStream(it, "wt")?.use { outputStream ->
|
||||
if (secretKey != null) {
|
||||
val encryptedContent = fileEncryptor.encrypt(content.toByteArray(), secretKey!!)
|
||||
outputStream.write(encryptedContent)
|
||||
} else {
|
||||
outputStream.write(content.toByteArray(Charsets.UTF_8))
|
||||
}
|
||||
android.widget.Toast.makeText(context, R.string.json_export_successful, android.widget.Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(context, R.string.json_export_successful, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,14 +174,14 @@ fun JsonImportExportDialog(
|
||||
scope.launch {
|
||||
context.contentResolver.openInputStream(it)?.use { inputStream ->
|
||||
val fileContent = inputStream.readBytes()
|
||||
var jsonString: String? = null
|
||||
var jsonString: String?
|
||||
|
||||
if (secretKey != null) {
|
||||
try {
|
||||
val decryptedBytes = fileEncryptor.decrypt(fileContent, secretKey!!)
|
||||
jsonString = decryptedBytes.toString(Charsets.UTF_8)
|
||||
} catch (e: javax.crypto.AEADBadTagException) {
|
||||
android.util.Log.w("JsonImportExportDialog", "Decryption failed, trying as unencrypted: ${e.message}")
|
||||
Log.w("JsonImportExportDialog", "Decryption failed, trying as unencrypted: ${e.message}")
|
||||
// Fallback to unencrypted if decryption fails
|
||||
jsonString = fileContent.toString(Charsets.UTF_8)
|
||||
}
|
||||
@@ -186,14 +191,14 @@ fun JsonImportExportDialog(
|
||||
}
|
||||
|
||||
try {
|
||||
shoppingListsViewModel.importShoppingListsFromJson(jsonString!!)
|
||||
android.widget.Toast.makeText(context, R.string.json_import_successful, android.widget.Toast.LENGTH_SHORT).show()
|
||||
} catch (e: kotlinx.serialization.SerializationException) {
|
||||
android.util.Log.e("JsonImportExportDialog", "Error parsing shopping lists JSON: ${e.message}")
|
||||
android.widget.Toast.makeText(context, context.getString(R.string.json_import_failed_invalid_format, e.message), android.widget.Toast.LENGTH_LONG).show()
|
||||
shoppingListsViewModel.importShoppingListsFromJson(jsonString)
|
||||
Toast.makeText(context, R.string.json_import_successful, Toast.LENGTH_SHORT).show()
|
||||
} catch (e: SerializationException) {
|
||||
Log.e("JsonImportExportDialog", "Error parsing shopping lists JSON: ${e.message}")
|
||||
Toast.makeText(context, context.getString(R.string.json_import_failed_invalid_format, e.message), Toast.LENGTH_LONG).show()
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("JsonImportExportDialog", "Error importing shopping lists: ${e.message}")
|
||||
android.widget.Toast.makeText(context, context.getString(R.string.json_import_failed_generic, e.message), android.widget.Toast.LENGTH_LONG).show()
|
||||
Log.e("JsonImportExportDialog", "Error importing shopping lists: ${e.message}")
|
||||
Toast.makeText(context, context.getString(R.string.json_import_failed_generic, e.message), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,12 +214,14 @@ fun JsonImportExportDialog(
|
||||
scope.launch {
|
||||
val allRecipes = recipesViewModel.uiState.value.recipeList
|
||||
val content = recipesViewModel.exportRecipesToJson(allRecipes)
|
||||
context.contentResolver.openOutputStream(it)?.use { outputStream ->
|
||||
secretKey?.let { key ->
|
||||
val encryptedContent = fileEncryptor.encrypt(content.toByteArray(), key)
|
||||
context.contentResolver.openOutputStream(it, "wt")?.use { outputStream ->
|
||||
if (secretKey != null) {
|
||||
val encryptedContent = fileEncryptor.encrypt(content.toByteArray(), secretKey!!)
|
||||
outputStream.write(encryptedContent)
|
||||
} else {
|
||||
outputStream.write(content.toByteArray(Charsets.UTF_8))
|
||||
}
|
||||
android.widget.Toast.makeText(context, R.string.json_export_successful, android.widget.Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(context, R.string.json_export_successful, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,14 +236,14 @@ fun JsonImportExportDialog(
|
||||
scope.launch {
|
||||
context.contentResolver.openInputStream(it)?.use { inputStream ->
|
||||
val fileContent = inputStream.readBytes()
|
||||
var jsonString: String? = null
|
||||
var jsonString: String?
|
||||
|
||||
if (secretKey != null) {
|
||||
try {
|
||||
val decryptedBytes = fileEncryptor.decrypt(fileContent, secretKey!!)
|
||||
jsonString = decryptedBytes.toString(Charsets.UTF_8)
|
||||
} catch (e: javax.crypto.AEADBadTagException) {
|
||||
android.util.Log.w("JsonImportExportDialog", "Decryption failed, trying as unencrypted: ${e.message}")
|
||||
Log.w("JsonImportExportDialog", "Decryption failed, trying as unencrypted: ${e.message}")
|
||||
// Fallback to unencrypted if decryption fails
|
||||
jsonString = fileContent.toString(Charsets.UTF_8)
|
||||
}
|
||||
@@ -246,14 +253,14 @@ fun JsonImportExportDialog(
|
||||
}
|
||||
|
||||
try {
|
||||
recipesViewModel.importRecipesFromJson(jsonString!!)
|
||||
android.widget.Toast.makeText(context, R.string.json_import_successful, android.widget.Toast.LENGTH_SHORT).show()
|
||||
} catch (e: kotlinx.serialization.SerializationException) {
|
||||
android.util.Log.e("JsonImportExportDialog", "Error parsing recipes JSON: ${e.message}")
|
||||
android.widget.Toast.makeText(context, context.getString(R.string.json_import_failed_invalid_format, e.message), android.widget.Toast.LENGTH_LONG).show()
|
||||
recipesViewModel.importRecipesFromJson(jsonString)
|
||||
Toast.makeText(context, R.string.json_import_successful, Toast.LENGTH_SHORT).show()
|
||||
} catch (e: SerializationException) {
|
||||
Log.e("JsonImportExportDialog", "Error parsing recipes JSON: ${e.message}")
|
||||
Toast.makeText(context, context.getString(R.string.json_import_failed_invalid_format, e.message), Toast.LENGTH_LONG).show()
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("JsonImportExportDialog", "Error importing recipes: ${e.message}")
|
||||
android.widget.Toast.makeText(context, context.getString(R.string.json_import_failed_generic, e.message), android.widget.Toast.LENGTH_LONG).show()
|
||||
Log.e("JsonImportExportDialog", "Error importing recipes: ${e.message}")
|
||||
Toast.makeText(context, context.getString(R.string.json_import_failed_generic, e.message), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,4 +346,4 @@ fun JsonImportExportDialog(
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import de.lxtools.noteshop.ui.recipes.RecipesViewModel
|
||||
import de.lxtools.noteshop.ui.shopping.ShoppingListDetails
|
||||
import de.lxtools.noteshop.ui.shopping.ShoppingListInputDialog
|
||||
import de.lxtools.noteshop.ui.ChooseLockMethodDialog
|
||||
import de.lxtools.noteshop.ui.LockableItemType
|
||||
import de.lxtools.noteshop.ui.LockMethod
|
||||
import de.lxtools.noteshop.ui.shopping.ShoppingListsViewModel
|
||||
import de.lxtools.noteshop.ui.StartupPasswordDialog
|
||||
@@ -45,26 +44,26 @@ fun AppDialogs(
|
||||
onShowListDialogChange: (Boolean) -> Unit,
|
||||
listDetails: ShoppingListDetails,
|
||||
onListDetailsChange: (ShoppingListDetails) -> Unit,
|
||||
onSaveList: () -> Unit,
|
||||
onResetListDetails: () -> Unit,
|
||||
|
||||
|
||||
onSetListProtection: (String) -> Unit,
|
||||
onSetListProtectionBiometric: (Int) -> Unit,
|
||||
|
||||
txtImportLauncher: ActivityResultLauncher<Array<String>>,
|
||||
showNoteDialog: Boolean,
|
||||
onShowNoteDialogChange: (Boolean) -> Unit,
|
||||
noteDetails: NoteDetails,
|
||||
onNoteDetailsChange: (NoteDetails) -> Unit,
|
||||
onSaveNote: () -> Unit,
|
||||
onResetNoteDetails: () -> Unit,
|
||||
onSetNoteProtectionBiometric: (Int) -> Unit,
|
||||
|
||||
|
||||
|
||||
noteImportLauncher: ActivityResultLauncher<Array<String>>,
|
||||
showRecipeDialog: Boolean,
|
||||
onShowRecipeDialogChange: (Boolean) -> Unit,
|
||||
recipeDetails: RecipeDetails,
|
||||
onRecipeDetailsChange: (RecipeDetails) -> Unit,
|
||||
onSaveRecipe: () -> Unit,
|
||||
onResetRecipeDetails: () -> Unit,
|
||||
onSetRecipeProtectionBiometric: (Int) -> Unit,
|
||||
|
||||
|
||||
|
||||
recipeImportLauncher: ActivityResultLauncher<Array<String>>,
|
||||
recipesTitle: String,
|
||||
showJsonDialog: Boolean,
|
||||
@@ -102,7 +101,6 @@ fun AppDialogs(
|
||||
onShowChooseLockMethodDialogChange: (Boolean) -> Unit,
|
||||
onConfirmLockMethod: (LockMethod) -> Unit,
|
||||
canUseBiometrics: Boolean,
|
||||
itemToLockType: de.lxtools.noteshop.ui.LockableItemType?,
|
||||
showStartupPasswordDialog: Boolean,
|
||||
onShowStartupPasswordDialogChange: (Boolean) -> Unit,
|
||||
onUnlockEncryption: (String) -> Unit,
|
||||
|
||||
Reference in New Issue
Block a user