Files
OmniCards/mobile/src/main/java/ru/omni_devel/cards/Elements.kt
T

316 lines
11 KiB
Kotlin

package ru.omni_devel.cards
import android.content.Intent
import androidx.activity.compose.BackHandler
import androidx.activity.compose.LocalActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
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.RowScope
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.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ButtonElevation
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.QrCode
import androidx.compose.material.icons.outlined.DensityMedium
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.NavigationDrawerItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.graphics.toColorInt
import kotlinx.coroutines.launch
@Composable
fun Page(
name: String,
innerPadding: PaddingValues,
floatingActionButton: @Composable (() -> Unit) = {},
content: @Composable () -> Unit
) {
Scaffold(
floatingActionButton = floatingActionButton
) { padding ->
Box(
modifier = Modifier
.padding(padding)
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.padding(horizontal = 16.dp)
.padding(top = 16.dp)
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
content()
}
}
}
}
@Composable
fun ExpandableFab(
items: List<NavigationPageData>
) {
val activityContext = LocalActivity.current
var isExpanded by remember { mutableStateOf(false) }
val rotation by animateFloatAsState(if (isExpanded) 45f else 0f)
Column(
horizontalAlignment = Alignment.End,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items.forEach { page ->
AnimatedVisibility(
visible = isExpanded,
enter = fadeIn() + scaleIn(),
exit = fadeOut() + scaleOut()
) {
ExtendedFloatingActionButton(
text = { Text(page.name) },
icon = { Icon(page.icon, contentDescription = null) },
onClick = {
isExpanded = false
if (page.pageClass != null) {
val intent = Intent(activityContext, page.pageClass)
activityContext!!.startActivity(intent)
} else if (page.onClick != null) {
page.onClick()
}
}
)
}
}
FloatingActionButton(
onClick = { isExpanded = !isExpanded }
) {
Icon(
modifier = Modifier.graphicsLayer { rotationZ = rotation },
imageVector = Icons.Outlined.Add,
contentDescription = null
)
}
}
}
@Composable
fun TopBar(text: String, innerPadding: PaddingValues, openMenuButton: (@Composable () -> Unit)? = null) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.primaryContainer)
.padding(top = innerPadding.calculateTopPadding())
.padding(vertical = 12.dp, horizontal = 12.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
if (openMenuButton != null) {
openMenuButton()
}
Text(
text,
modifier = Modifier,
fontSize = 24.sp,
color = MaterialTheme.colorScheme.onPrimaryContainer
)
}
}
@Composable
fun CardButton(cardInfo: CardInfo, onDeleteCard: (Int) -> Unit) {
val context = LocalContext.current
var menuExpanded by remember { mutableStateOf(false) }
val cardColor = if (cardInfo.color == null)
MaterialTheme.colorScheme.primaryContainer
else
Color(cardInfo.color.toColorInt())
Box(modifier = Modifier.fillMaxWidth()) {
Surface(
modifier = Modifier
.fillMaxWidth()
.height(64.dp)
.pointerInput(Unit) {
detectTapGestures(
onTap = {
val intent = Intent(context, ShowCardActivity::class.java)
intent.putExtra("cardId", cardInfo.id)
context.startActivity(intent)
},
onLongPress = {
menuExpanded = true
}
)
},
shape = RoundedCornerShape(12.dp),
color = cardColor.copy(0.425f),
tonalElevation = 2.dp,
) {
Row(
modifier = Modifier
.fillMaxSize()
.background(Color.Transparent)
.padding(horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
CardIcon(
if (cardInfo.icon == null) null else base64ToImageBitmap(cardInfo.icon),
cardColor = cardColor
)
Text(
cardInfo.name,
fontSize = 16.sp,
color = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Start
)
}
}
DropdownMenu(
expanded = menuExpanded,
onDismissRequest = { menuExpanded = false }
) {
DropdownMenuItem(
text = { Text(stringResource(R.string.do_edit_card)) },
onClick = {
menuExpanded = false
val intent = Intent(context, EditCardActivity::class.java)
intent.putExtra("cardId", cardInfo.id)
context.startActivity(intent)
}
)
DropdownMenuItem(
text = { Text(stringResource(R.string.do_delete_card)) },
onClick = {
menuExpanded = false
onDeleteCard(cardInfo.id)
}
)
}
}
}
@Composable
fun CardIcon(icon: ImageBitmap?, cardColor: Color, isLoading: Boolean = false) {
Row(
modifier = Modifier
.background(
cardColor.copy(0.525f),
RoundedCornerShape(12.dp)
)
.padding(8.dp)
.size(32.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.size(24.dp),
color = MaterialTheme.colorScheme.primary
)
} else if (icon == null) {
Icon(
modifier = Modifier.size(24.dp),
imageVector = Icons.Outlined.QrCode,
tint = MaterialTheme.colorScheme.onPrimaryContainer,
contentDescription = null
)
} else {
Image(
bitmap = icon,
contentDescription = null,
modifier = Modifier.size(32.dp)
)
}
}
}
@Composable
fun AdaptiveButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
content: @Composable RowScope.() -> Unit
) {
Button(
onClick = onClick,
modifier = modifier,
enabled = enabled,
shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
),
elevation = elevation,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content
)
}