forked from omni/OmniCards
397 lines
13 KiB
Kotlin
397 lines
13 KiB
Kotlin
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.background
|
|
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.layout.height
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.foundation.rememberScrollState
|
|
import androidx.compose.foundation.verticalScroll
|
|
import androidx.compose.material3.DropdownMenu
|
|
import androidx.compose.material3.DropdownMenuItem
|
|
import androidx.compose.material3.MaterialTheme
|
|
import androidx.compose.material3.OutlinedTextField
|
|
import androidx.compose.material3.Scaffold
|
|
import androidx.compose.material3.Switch
|
|
import androidx.compose.material3.Text
|
|
import androidx.compose.material.icons.Icons
|
|
import androidx.compose.material.icons.outlined.Palette
|
|
import androidx.compose.material.icons.outlined.QrCodeScanner
|
|
import androidx.compose.material.icons.outlined.TextFields
|
|
import androidx.compose.material.icons.outlined.Save
|
|
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.Alignment
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.graphics.Color
|
|
import androidx.compose.ui.platform.LocalContext
|
|
import androidx.compose.ui.res.stringResource
|
|
import androidx.compose.ui.unit.dp
|
|
import androidx.core.graphics.toColorInt
|
|
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,
|
|
icon: String?,
|
|
onIconChange: (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 cardColor = if (color == null)
|
|
MaterialTheme.colorScheme.primary
|
|
else
|
|
Color(color.toColorInt())
|
|
|
|
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")!!
|
|
val codeType = BarcodeFormat.valueOf(result.data?.getStringExtra("codeType")!!)
|
|
|
|
onCodeValueChange(codeValue)
|
|
onCodeTypeChange(codeType)
|
|
}
|
|
}
|
|
|
|
val selectIconLauncher = rememberLauncherForActivityResult(
|
|
contract = ActivityResultContracts.StartActivityForResult()
|
|
) { result ->
|
|
if (result.resultCode == Activity.RESULT_OK) {
|
|
val icon = result.data?.getStringExtra("icon")
|
|
|
|
onIconChange(icon)
|
|
}
|
|
}
|
|
|
|
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)) }
|
|
)
|
|
|
|
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
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
AdaptiveButton(
|
|
modifier = Modifier.fillMaxWidth(),
|
|
icon = Icons.Outlined.QrCodeScanner,
|
|
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(),
|
|
icon = Icons.Outlined.TextFields,
|
|
onClick = {
|
|
val intent = Intent(context, SelectTemplateActivity::class.java)
|
|
|
|
selectTemplateLauncher.launch(intent)
|
|
}
|
|
) {
|
|
Text(stringResource(R.string.card_from_template))
|
|
}
|
|
|
|
Row(
|
|
modifier = fieldModifier,
|
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
|
) {
|
|
AdaptiveButton(
|
|
modifier = Modifier.fillMaxWidth().weight(1.0f),
|
|
icon = Icons.Outlined.Palette,
|
|
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)
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
AdaptiveButton(
|
|
modifier = Modifier.fillMaxWidth().height(64.dp),
|
|
contentPadding = PaddingValues(horizontal = 0.dp),
|
|
onClick = {
|
|
val intent = Intent(context, SelectIconActivity::class.java)
|
|
|
|
selectIconLauncher.launch(intent)
|
|
}
|
|
) {
|
|
Row(
|
|
modifier = Modifier
|
|
.fillMaxSize()
|
|
.background(Color.Transparent)
|
|
.padding(horizontal = 8.dp),
|
|
verticalAlignment = Alignment.CenterVertically,
|
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
|
) {
|
|
CardIcon(if (icon == null) null else base64ToImageBitmap(icon), cardColor)
|
|
|
|
Text(stringResource(R.string.do_select_icon))
|
|
}
|
|
}
|
|
}
|
|
|
|
@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<String?>(null) }
|
|
var icon by rememberSaveable { mutableStateOf<String?>(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 },
|
|
icon = icon,
|
|
onIconChange = { icon = it }
|
|
)
|
|
|
|
AdaptiveButton(
|
|
modifier = Modifier.fillMaxWidth(),
|
|
icon = Icons.Outlined.Save,
|
|
onClick = {
|
|
cardName = cardName.trim()
|
|
|
|
val err = checkCardData(cardName, codeValue)
|
|
|
|
if (err == null) {
|
|
getDbFun().addCard(cardName, codeValue, codeType, color, icon)
|
|
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) }
|
|
var icon by rememberSaveable { mutableStateOf(cardInfo.icon) }
|
|
|
|
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 },
|
|
icon = icon,
|
|
onIconChange = { icon = it }
|
|
)
|
|
|
|
AdaptiveButton(
|
|
modifier = Modifier.fillMaxWidth(),
|
|
icon = Icons.Outlined.Save,
|
|
onClick = {
|
|
cardName = cardName.trim()
|
|
|
|
val err = checkCardData(cardName, codeValue)
|
|
|
|
if (err == null) {
|
|
getDbFun().editCard(cardInfo.id, cardName, codeValue, codeType, color, icon)
|
|
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)
|
|
}
|
|
}
|