forked from omni/OmniCards
refactor + feat: updated UI and added cards search logic
This commit is contained in:
@@ -12,6 +12,9 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Save
|
||||||
|
import androidx.compose.material.icons.outlined.Restore
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -135,6 +138,7 @@ fun BackupPage(innerPadding: PaddingValues, getDbFun: () -> DbHelper) {
|
|||||||
Page(stringResource(R.string.backup), innerPadding) {
|
Page(stringResource(R.string.backup), innerPadding) {
|
||||||
AdaptiveButton(
|
AdaptiveButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Icons.Outlined.Save,
|
||||||
onClick = {
|
onClick = {
|
||||||
createBackupLauncher.launch("omnicards-backup.json")
|
createBackupLauncher.launch("omnicards-backup.json")
|
||||||
}
|
}
|
||||||
@@ -143,6 +147,7 @@ fun BackupPage(innerPadding: PaddingValues, getDbFun: () -> DbHelper) {
|
|||||||
}
|
}
|
||||||
AdaptiveButton(
|
AdaptiveButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Icons.Outlined.Restore,
|
||||||
onClick = {
|
onClick = {
|
||||||
restoreFromBackupLauncher.launch("application/json")
|
restoreFromBackupLauncher.launch("application/json")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ import androidx.compose.material3.OutlinedTextField
|
|||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
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.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
@@ -88,7 +93,6 @@ fun CardEditable(
|
|||||||
var isCodeTypeDropdownExpanded by rememberSaveable { mutableStateOf(false) }
|
var isCodeTypeDropdownExpanded by rememberSaveable { mutableStateOf(false) }
|
||||||
var isColorEnabled by rememberSaveable { mutableStateOf(color != null) }
|
var isColorEnabled by rememberSaveable { mutableStateOf(color != null) }
|
||||||
var currentColor by rememberSaveable { mutableStateOf(color) }
|
var currentColor by rememberSaveable { mutableStateOf(color) }
|
||||||
var currentIcon by rememberSaveable { mutableStateOf(icon) }
|
|
||||||
|
|
||||||
val fieldModifier = Modifier.fillMaxWidth()
|
val fieldModifier = Modifier.fillMaxWidth()
|
||||||
|
|
||||||
@@ -151,32 +155,6 @@ fun CardEditable(
|
|||||||
label = { Text(stringResource(R.string.card_value)) }
|
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(
|
Box(
|
||||||
modifier = fieldModifier,
|
modifier = fieldModifier,
|
||||||
) {
|
) {
|
||||||
@@ -211,12 +189,41 @@ fun CardEditable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(
|
Row(
|
||||||
modifier = fieldModifier,
|
modifier = fieldModifier,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
AdaptiveButton(
|
AdaptiveButton(
|
||||||
modifier = Modifier.fillMaxWidth().weight(1.0f),
|
modifier = Modifier.fillMaxWidth().weight(1.0f),
|
||||||
|
icon = Icons.Outlined.Palette,
|
||||||
enabled = isColorEnabled,
|
enabled = isColorEnabled,
|
||||||
onClick = {
|
onClick = {
|
||||||
val intent = Intent(context, ChooseColorActivity::class.java)
|
val intent = Intent(context, ChooseColorActivity::class.java)
|
||||||
@@ -298,6 +305,7 @@ fun AddCard(innerPadding: PaddingValues, getDbFun: () -> DbHelper) {
|
|||||||
|
|
||||||
AdaptiveButton(
|
AdaptiveButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Icons.Outlined.Save,
|
||||||
onClick = {
|
onClick = {
|
||||||
cardName = cardName.trim()
|
cardName = cardName.trim()
|
||||||
|
|
||||||
@@ -350,6 +358,7 @@ fun EditCard(cardInfo: CardInfo, innerPadding: PaddingValues, getDbFun: () -> Db
|
|||||||
|
|
||||||
AdaptiveButton(
|
AdaptiveButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Icons.Outlined.Save,
|
||||||
onClick = {
|
onClick = {
|
||||||
cardName = cardName.trim()
|
cardName = cardName.trim()
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
@@ -60,6 +62,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -73,12 +76,13 @@ import kotlinx.coroutines.launch
|
|||||||
fun Page(
|
fun Page(
|
||||||
name: String,
|
name: String,
|
||||||
innerPadding: PaddingValues,
|
innerPadding: PaddingValues,
|
||||||
|
topBarAdditionalElements: @Composable () -> Unit = {},
|
||||||
floatingActionButton: @Composable (() -> Unit) = {},
|
floatingActionButton: @Composable (() -> Unit) = {},
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopBar(name, innerPadding)
|
TopBar(name, innerPadding, topBarAdditionalElements)
|
||||||
},
|
},
|
||||||
floatingActionButton = floatingActionButton
|
floatingActionButton = floatingActionButton
|
||||||
) { padding ->
|
) { padding ->
|
||||||
@@ -154,7 +158,11 @@ fun ExpandableFab(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TopBar(text: String, innerPadding: PaddingValues) {
|
fun TopBar(
|
||||||
|
text: String,
|
||||||
|
innerPadding: PaddingValues,
|
||||||
|
topBarAdditionalElements: @Composable () -> Unit = {}
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -162,7 +170,7 @@ fun TopBar(text: String, innerPadding: PaddingValues) {
|
|||||||
.padding(top = innerPadding.calculateTopPadding())
|
.padding(top = innerPadding.calculateTopPadding())
|
||||||
.padding(vertical = 12.dp, horizontal = 12.dp),
|
.padding(vertical = 12.dp, horizontal = 12.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text,
|
text,
|
||||||
@@ -170,6 +178,8 @@ fun TopBar(text: String, innerPadding: PaddingValues) {
|
|||||||
fontSize = 24.sp,
|
fontSize = 24.sp,
|
||||||
color = MaterialTheme.colorScheme.onPrimaryContainer
|
color = MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
topBarAdditionalElements()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +212,7 @@ fun CardButton(cardInfo: CardInfo, onDeleteCard: (Int) -> Unit) {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
shape = RoundedCornerShape(12.dp),
|
shape = RoundedCornerShape(12.dp),
|
||||||
color = cardColor.copy(0.425f),
|
color = MaterialTheme.colorScheme.primaryContainer.copy(0.625f),
|
||||||
tonalElevation = 2.dp,
|
tonalElevation = 2.dp,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
@@ -296,25 +306,46 @@ fun AdaptiveButton(
|
|||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
|
icon: ImageVector? = null,
|
||||||
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
|
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
|
||||||
border: BorderStroke? = null,
|
border: BorderStroke? = null,
|
||||||
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
||||||
interactionSource: MutableInteractionSource? = null,
|
interactionSource: MutableInteractionSource? = null,
|
||||||
|
isSecondary: Boolean = false,
|
||||||
content: @Composable RowScope.() -> Unit
|
content: @Composable RowScope.() -> Unit
|
||||||
) {
|
) {
|
||||||
|
val colors = if (isSecondary)
|
||||||
|
ButtonDefaults.buttonColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.secondaryContainer,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
|
||||||
|
)
|
||||||
|
else
|
||||||
|
ButtonDefaults.buttonColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
)
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
shape = RoundedCornerShape(12.dp),
|
shape = RoundedCornerShape(12.dp),
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = colors,
|
||||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
|
||||||
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
|
|
||||||
),
|
|
||||||
elevation = elevation,
|
elevation = elevation,
|
||||||
border = border,
|
border = border,
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
content = content
|
content = {
|
||||||
|
if (icon != null) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(18.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
content()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,22 +5,39 @@ import android.widget.Toast
|
|||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.expandVertically
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.scaleIn
|
||||||
|
import androidx.compose.animation.scaleOut
|
||||||
|
import androidx.compose.animation.shrinkVertically
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Add
|
import androidx.compose.material.icons.outlined.Add
|
||||||
import androidx.compose.material.icons.outlined.Sync
|
import androidx.compose.material.icons.outlined.Sync
|
||||||
import androidx.compose.material.icons.outlined.Backup
|
import androidx.compose.material.icons.outlined.Backup
|
||||||
import androidx.compose.material.icons.outlined.Code
|
import androidx.compose.material.icons.outlined.Code
|
||||||
|
import androidx.compose.material.icons.outlined.Search
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -72,12 +89,25 @@ fun MainPage(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
|
|
||||||
|
var searchQuery by rememberSaveable { mutableStateOf("") }
|
||||||
|
var isSearchFieldShowed by rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
Page(
|
Page(
|
||||||
stringResource(R.string.app_name),
|
stringResource(R.string.app_name),
|
||||||
innerPadding,
|
innerPadding,
|
||||||
|
topBarAdditionalElements = {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Search,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
isSearchFieldShowed = !isSearchFieldShowed
|
||||||
|
searchQuery = ""
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
ExpandableFab(
|
ExpandableFab(
|
||||||
items = listOf(
|
items = listOf(
|
||||||
@@ -100,17 +130,64 @@ fun MainPage(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
var queryCleaned = searchQuery.lowercase()
|
||||||
|
|
||||||
|
for ((from, to) in SEARCH_REPLACE_SYMBOLS) {
|
||||||
|
queryCleaned = queryCleaned.replace(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
val searchResults = cards.filter { cardInfo ->
|
||||||
|
if (queryCleaned.isEmpty()) {
|
||||||
|
return@filter true
|
||||||
|
}
|
||||||
|
|
||||||
|
var cardNameCleaned = cardInfo.name.lowercase()
|
||||||
|
|
||||||
|
for ((from, to) in SEARCH_REPLACE_SYMBOLS) {
|
||||||
|
cardNameCleaned = cardNameCleaned.replace(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardNameCleaned.contains(queryCleaned)) {
|
||||||
|
return@filter true
|
||||||
|
}
|
||||||
|
|
||||||
|
return@filter false
|
||||||
|
}
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
|
item {
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = isSearchFieldShowed,
|
||||||
|
enter = fadeIn() + expandVertically(),
|
||||||
|
exit = fadeOut() + shrinkVertically()
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = searchQuery,
|
||||||
|
onValueChange = {
|
||||||
|
searchQuery = it
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
label = { Text(stringResource(R.string.search)) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cards.isEmpty()) {
|
if (cards.isEmpty()) {
|
||||||
item {
|
item {
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.add_card_to_get_started)
|
stringResource(R.string.add_card_to_get_started)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else if (searchResults.isEmpty()) {
|
||||||
|
item {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.cards_not_found)
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (card in cards) {
|
for (card in searchResults) {
|
||||||
item {
|
item {
|
||||||
CardButton(card, onDeleteCard)
|
CardButton(card, onDeleteCard)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,32 @@ fun SelectIconPage(innerPadding: PaddingValues) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var queryCleaned = searchQuery.lowercase()
|
||||||
|
|
||||||
|
for ((from, to) in SEARCH_REPLACE_SYMBOLS) {
|
||||||
|
queryCleaned = queryCleaned.replace(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
val searchResults = iconsData!!.filter { iconData ->
|
||||||
|
if (queryCleaned.isEmpty()) {
|
||||||
|
return@filter true
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name in iconData.names.values) {
|
||||||
|
var nameCleaned = name.lowercase()
|
||||||
|
|
||||||
|
for ((from, to) in SEARCH_REPLACE_SYMBOLS) {
|
||||||
|
nameCleaned = nameCleaned.replace(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameCleaned.contains(queryCleaned)) {
|
||||||
|
return@filter true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return@filter false
|
||||||
|
}
|
||||||
|
|
||||||
Page(context.getString(R.string.choosing_icon), innerPadding) {
|
Page(context.getString(R.string.choosing_icon), innerPadding) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = searchQuery,
|
value = searchQuery,
|
||||||
@@ -138,67 +164,69 @@ fun SelectIconPage(innerPadding: PaddingValues) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val searchResults = iconsData!!.filter { iconData ->
|
|
||||||
var queryCleaned = searchQuery.lowercase()
|
|
||||||
|
|
||||||
if (queryCleaned.isEmpty()) {
|
|
||||||
return@filter true
|
|
||||||
}
|
|
||||||
|
|
||||||
for (name in iconData.names.values) {
|
|
||||||
var nameCleaned = name.lowercase()
|
|
||||||
|
|
||||||
for ((from, to) in SEARCH_REPLACE_SYMBOLS) {
|
|
||||||
nameCleaned = nameCleaned.replace(from, to)
|
|
||||||
queryCleaned = queryCleaned.replace(from, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nameCleaned.contains(queryCleaned)) {
|
|
||||||
return@filter true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return@filter false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchResults.isEmpty()) {
|
if (searchResults.isEmpty()) {
|
||||||
item {
|
item {
|
||||||
Text(stringResource(R.string.icons_not_found))
|
Text(stringResource(R.string.icons_not_found))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (iconData in searchResults) {
|
for (chunk in searchResults.chunked(2)) {
|
||||||
item {
|
item {
|
||||||
val loadedIcon = loadedIcons[iconData.iconId]
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
AdaptiveButton(
|
|
||||||
modifier = Modifier.fillMaxWidth().height(64.dp),
|
|
||||||
contentPadding = PaddingValues(0.dp),
|
|
||||||
onClick = {
|
|
||||||
if (loadedIcon == null && iconData.iconId != null) {
|
|
||||||
Toast.makeText(context, context.getString(R.string.wait_for_icon_load), Toast.LENGTH_SHORT).show()
|
|
||||||
} else {
|
|
||||||
val intent = Intent()
|
|
||||||
|
|
||||||
if (loadedIcon != null) {
|
|
||||||
intent.putExtra("icon", imageBitmapToBase64(loadedIcon))
|
|
||||||
}
|
|
||||||
|
|
||||||
activityContext!!.setResult(Activity.RESULT_OK, intent)
|
|
||||||
activityContext.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
Row(
|
for (iconData in chunk) {
|
||||||
modifier = Modifier
|
val loadedIcon = loadedIcons[iconData.iconId]
|
||||||
.fillMaxSize()
|
|
||||||
.background(Color.Transparent)
|
|
||||||
.padding(horizontal = 8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
|
||||||
CardIcon(loadedIcon, MaterialTheme.colorScheme.primary, loadedIcon == null && iconData.iconId != null)
|
|
||||||
|
|
||||||
Text(selectItemNameViaLanguage(iconData.names, language))
|
AdaptiveButton(
|
||||||
|
modifier = Modifier.weight(1f).height(64.dp),
|
||||||
|
contentPadding = PaddingValues(0.dp),
|
||||||
|
onClick = {
|
||||||
|
if (loadedIcon == null && iconData.iconId != null) {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
context.getString(R.string.wait_for_icon_load),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
} else {
|
||||||
|
val intent = Intent()
|
||||||
|
|
||||||
|
if (loadedIcon != null) {
|
||||||
|
intent.putExtra(
|
||||||
|
"icon",
|
||||||
|
imageBitmapToBase64(loadedIcon)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
activityContext!!.setResult(
|
||||||
|
Activity.RESULT_OK,
|
||||||
|
intent
|
||||||
|
)
|
||||||
|
activityContext.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(Color.Transparent)
|
||||||
|
.padding(horizontal = 8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
CardIcon(
|
||||||
|
loadedIcon,
|
||||||
|
MaterialTheme.colorScheme.primary,
|
||||||
|
loadedIcon == null && iconData.iconId != null
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
selectItemNameViaLanguage(
|
||||||
|
iconData.names,
|
||||||
|
language
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,9 +129,13 @@ fun SelectTemplatePage(innerPadding: PaddingValues) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val searchResults = currentTemplates.filter { template ->
|
var queryCleaned = searchQuery.lowercase()
|
||||||
var queryCleaned = searchQuery.lowercase()
|
|
||||||
|
|
||||||
|
for ((from, to) in SEARCH_REPLACE_SYMBOLS) {
|
||||||
|
queryCleaned = queryCleaned.replace(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
val searchResults = currentTemplates.filter { template ->
|
||||||
if (queryCleaned.isEmpty()) {
|
if (queryCleaned.isEmpty()) {
|
||||||
return@filter true
|
return@filter true
|
||||||
}
|
}
|
||||||
@@ -141,7 +145,6 @@ fun SelectTemplatePage(innerPadding: PaddingValues) {
|
|||||||
|
|
||||||
for ((from, to) in SEARCH_REPLACE_SYMBOLS) {
|
for ((from, to) in SEARCH_REPLACE_SYMBOLS) {
|
||||||
nameCleaned = nameCleaned.replace(from, to)
|
nameCleaned = nameCleaned.replace(from, to)
|
||||||
queryCleaned = queryCleaned.replace(from, to)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nameCleaned.contains(queryCleaned)) {
|
if (nameCleaned.contains(queryCleaned)) {
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -20,6 +22,8 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -95,10 +99,10 @@ fun ShowCardPage(innerPadding: PaddingValues, cardInfo: CardInfo) {
|
|||||||
contentDescription = cardInfo.codeValue,
|
contentDescription = cardInfo.codeValue,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(bottom = 8.dp)
|
.padding(bottom = 8.dp)
|
||||||
.fillMaxWidth()
|
.clip(RoundedCornerShape(12.dp)),
|
||||||
.weight(1f, fill = false),
|
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
cardInfo.codeValue,
|
cardInfo.codeValue,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
<string name="error_in_data">Ошибка в данных. Пожалуйста, заполните все необходимые (*) поля</string>
|
<string name="error_in_data">Ошибка в данных. Пожалуйста, заполните все необходимые (*) поля</string>
|
||||||
<string name="templates_not_found">Шаблоны не найдены</string>
|
<string name="templates_not_found">Шаблоны не найдены</string>
|
||||||
<string name="search">Поиск</string>
|
<string name="search">Поиск</string>
|
||||||
|
<string name="cards_not_found">Карты не найдены</string>
|
||||||
<string name="choosing_icon">Выбор иконки</string>
|
<string name="choosing_icon">Выбор иконки</string>
|
||||||
<string name="icons_not_found">Иконки не найдены</string>
|
<string name="icons_not_found">Иконки не найдены</string>
|
||||||
<string name="do_select_icon">Выбрать иконку</string>
|
<string name="do_select_icon">Выбрать иконку</string>
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
<string name="error_in_data">Error in data. Please, fill all required (*) fields</string>
|
<string name="error_in_data">Error in data. Please, fill all required (*) fields</string>
|
||||||
<string name="templates_not_found">Templates not found</string>
|
<string name="templates_not_found">Templates not found</string>
|
||||||
<string name="search">Search</string>
|
<string name="search">Search</string>
|
||||||
|
<string name="cards_not_found">Cards not found</string>
|
||||||
<string name="choosing_icon">Choosing icon</string>
|
<string name="choosing_icon">Choosing icon</string>
|
||||||
<string name="icons_not_found">Icons not found</string>
|
<string name="icons_not_found">Icons not found</string>
|
||||||
<string name="do_select_icon">Select icon</string>
|
<string name="do_select_icon">Select icon</string>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ fun CardButton(cardInfo: CardInfo) {
|
|||||||
Button(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth().height(64.dp),
|
modifier = Modifier.fillMaxWidth().height(64.dp),
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
containerColor = cardColor.copy(0.425f)
|
containerColor = MaterialTheme.colorScheme.primaryContainer.copy(0.625f)
|
||||||
),
|
),
|
||||||
shape = RoundedCornerShape(12.dp),
|
shape = RoundedCornerShape(12.dp),
|
||||||
contentPadding = PaddingValues(0.dp),
|
contentPadding = PaddingValues(0.dp),
|
||||||
|
|||||||
Reference in New Issue
Block a user