package ru.omni_devel.cards import android.app.Activity import android.content.Intent 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.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.google.zxing.BarcodeFormat import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanOptions import ru.omni_devel.cards.ui.theme.OmniCardsTheme class EditCardActivity : ComponentActivity() { private lateinit var db: DbHelper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() db = DbHelper(this, null) val cardId = intent.getIntExtra("cardId", -1) val cardInfo = db.getCard(cardId) setContent { OmniCardsTheme { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> EditCardPage(cardInfo, innerPadding, getDbFun = { return@EditCardPage db }) } } } } } @Composable fun CardEditable( cardName: String, onCardNameChange: (String) -> Unit, codeValue: String, onCodeValueChange: (String) -> Unit, codeType: BarcodeFormat, onCodeTypeChange: (BarcodeFormat) -> Unit, color: String?, onColorChange: (String?) -> Unit ) { val context = LocalContext.current var isCodeTypeDropdownExpanded by rememberSaveable { mutableStateOf(false) } var isColorEnabled by rememberSaveable { mutableStateOf(color != null) } var currentColor by rememberSaveable { mutableStateOf(color) } val fieldModifier = Modifier.fillMaxWidth() val scanLauncher = rememberLauncherForActivityResult( contract = ScanContract() ) { result -> if (result.contents != null) { onCodeValueChange(result.contents) result.formatName?.let { formatName -> try { onCodeTypeChange(BarcodeFormat.valueOf(formatName)) } catch (_: IllegalArgumentException) {} } } } val editColorLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult() ) { result -> if (result.resultCode == Activity.RESULT_OK) { val color = result.data?.getStringExtra("color") currentColor = color onColorChange(color) } } val selectTemplateLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult() ) { result -> if (result.resultCode == Activity.RESULT_OK) { val codeValue = result.data?.getStringExtra("codeValue") ?: "" onCodeValueChange(codeValue) } } OutlinedTextField( value = cardName, onValueChange = onCardNameChange, modifier = fieldModifier, label = { Text(stringResource(R.string.card_name)) } ) OutlinedTextField( value = codeValue, onValueChange = onCodeValueChange, modifier = fieldModifier, label = { Text(stringResource(R.string.card_value)) } ) AdaptiveButton( modifier = Modifier.fillMaxWidth(), onClick = { scanLauncher.launch( ScanOptions().apply { setPrompt(context.getString(R.string.scan_your_card)) setBeepEnabled(true) setOrientationLocked(true) } ) } ) { Text(stringResource(R.string.do_scan_card)) } AdaptiveButton( modifier = Modifier.fillMaxWidth(), onClick = { val intent = Intent(context, SelectTemplateActivity::class.java) selectTemplateLauncher.launch(intent) } ) { Text(stringResource(R.string.card_from_template)) } Box( modifier = fieldModifier, ) { OutlinedTextField( value = codeType.name, onValueChange = {}, modifier = fieldModifier, label = { Text(stringResource(R.string.card_code_type)) }, readOnly = true, ) Box( modifier = fieldModifier .matchParentSize() .clickable { isCodeTypeDropdownExpanded = !isCodeTypeDropdownExpanded } ) DropdownMenu( expanded = isCodeTypeDropdownExpanded, onDismissRequest = { isCodeTypeDropdownExpanded = false }, modifier = fieldModifier ) { BarcodeFormat.entries.forEach { format -> DropdownMenuItem( text = { Text(format.name) }, onClick = { onCodeTypeChange(format) isCodeTypeDropdownExpanded = false } ) } } } Row( modifier = fieldModifier, horizontalArrangement = Arrangement.spacedBy(8.dp) ) { AdaptiveButton( modifier = Modifier.fillMaxWidth().weight(1.0f), enabled = isColorEnabled, onClick = { val intent = Intent(context, ChooseColorActivity::class.java) intent.putExtra("currentColor", currentColor) editColorLauncher.launch(intent) } ) { Text(stringResource(R.string.do_choose_color)) } Switch( checked = isColorEnabled, onCheckedChange = { isColorEnabled = it if (!isColorEnabled) { onColorChange(null) } } ) } } @Composable fun AddCard(innerPadding: PaddingValues, getDbFun: () -> DbHelper) { var cardName by rememberSaveable { mutableStateOf("") } var codeValue by rememberSaveable { mutableStateOf("") } var codeType by rememberSaveable { mutableStateOf(BarcodeFormat.QR_CODE) } var color by rememberSaveable { mutableStateOf(null) } val context = LocalActivity.current Page( stringResource(R.string.new_card_title), innerPadding ) { Column( modifier = Modifier.verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(8.dp) ) { CardEditable( cardName = cardName, onCardNameChange = { cardName = it }, codeValue = codeValue, onCodeValueChange = { codeValue = it }, codeType = codeType, onCodeTypeChange = { codeType = it }, color = color, onColorChange = { color = it } ) AdaptiveButton( modifier = Modifier.fillMaxWidth(), onClick = { cardName = cardName.trim() val err = checkCardData(cardName, codeValue) if (err == null) { getDbFun().addCard(cardName, codeValue, codeType, color) context!!.finish() } else { Toast.makeText(context, context!!.getString(err), Toast.LENGTH_SHORT).show() } } ) { Text(stringResource(R.string.do_save)) } } } } @Composable fun EditCard(cardInfo: CardInfo, innerPadding: PaddingValues, getDbFun: () -> DbHelper) { var cardName by rememberSaveable { mutableStateOf(cardInfo.name) } var codeValue by rememberSaveable { mutableStateOf(cardInfo.codeValue) } var codeType by rememberSaveable { mutableStateOf(cardInfo.codeType) } var color by rememberSaveable { mutableStateOf(cardInfo.color) } val context = LocalActivity.current Page( stringResource(R.string.editing_card_title, cardInfo.id), innerPadding ) { Column( modifier = Modifier.verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(8.dp) ) { CardEditable( cardName = cardName, onCardNameChange = { cardName = it }, codeValue = codeValue, onCodeValueChange = { codeValue = it }, codeType = codeType, onCodeTypeChange = { codeType = it }, color = color, onColorChange = { color = it } ) AdaptiveButton( modifier = Modifier.fillMaxWidth(), onClick = { cardName = cardName.trim() val err = checkCardData(cardName, codeValue) if (err == null) { getDbFun().editCard(cardInfo.id, cardName, codeValue, codeType, color) context!!.finish() } else { Toast.makeText(context, context!!.getString(err), Toast.LENGTH_SHORT).show() } } ) { Text(stringResource(R.string.do_save)) } } } } @Composable fun EditCardPage(cardInfo: CardInfo?, innerPadding: PaddingValues, getDbFun: () -> DbHelper) { if (cardInfo == null) { AddCard(innerPadding, getDbFun) } else { EditCard(cardInfo, innerPadding, getDbFun) } }