package ru.omni_devel.cards import android.net.Uri import android.os.Bundle import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.LocalActivity import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.AlertDialog import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import kotlinx.serialization.json.Json import ru.omni_devel.cards.ui.theme.OmniCardsTheme import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue import androidx.compose.ui.res.stringResource class BackupActivity : ComponentActivity() { private lateinit var db: DbHelper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() db = DbHelper(this, null) setContent { OmniCardsTheme { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> BackupPage(innerPadding = innerPadding, getDbFun = { return@BackupPage db }) } } } } } @Composable fun BackupPage(innerPadding: PaddingValues, getDbFun: () -> DbHelper) { val context = LocalContext.current val activityContext = LocalActivity.current val showImportDialog = rememberSaveable { mutableStateOf(false) } var pendingUri by rememberSaveable { mutableStateOf(null) } val createBackupLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.CreateDocument("application/json") ) { uri -> uri?.let { try { val jsonData = Json.encodeToString(getDbFun().getCards()) context.contentResolver.openOutputStream(it)?.use { outputStream -> outputStream.write(jsonData.toByteArray()) Toast.makeText(context, context.getString(R.string.backup_successfully_saved), Toast.LENGTH_SHORT).show() activityContext!!.finish() } } catch (e: Exception) { Toast.makeText(context, context.getString(R.string.failed_to_save_backup, e), Toast.LENGTH_LONG).show() } } } val restoreFromBackupLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.GetContent() ) { uri -> uri?.let { pendingUri = it showImportDialog.value = true } } if (showImportDialog.value) { AlertDialog( title = { Text(stringResource(R.string.ask_do_restore)) }, text = { Text(stringResource(R.string.restore_caution)) }, confirmButton = { TextButton( onClick = { showImportDialog.value = false pendingUri?.let { uri -> try { context.contentResolver.openInputStream(uri)?.use { stream -> val json = stream.bufferedReader().use { it.readText() } val cards = Json.decodeFromString>(json) val db = getDbFun() db.clearDatabase() db.addCards(cards) Toast.makeText(context, context.getString(R.string.backup_successfully_restored), Toast.LENGTH_SHORT).show() activityContext!!.finish() } } catch (e: Exception) { Toast.makeText(context, context.getString(R.string.failed_to_restore_backup, e), Toast.LENGTH_LONG).show() } } } ) { Text(stringResource(R.string.yes)) } }, dismissButton = { TextButton( onClick = { showImportDialog.value = false } ) { Text(stringResource(R.string.no)) } }, onDismissRequest = { showImportDialog.value = false }, ) } Page(stringResource(R.string.backup), innerPadding) { FullWidthButton( onClick = { createBackupLauncher.launch("omnicards-backup.json") } ) { Text(stringResource(R.string.do_backup)) } FullWidthButton( onClick = { restoreFromBackupLauncher.launch("application/json") } ) { Text(stringResource(R.string.do_restore)) } } }