refactor: replaced bottom actions list with floating action button

This commit is contained in:
2026-06-23 11:53:30 +03:00
parent 3cf6b876f9
commit 13d6ba0b52
4 changed files with 103 additions and 93 deletions
@@ -3,6 +3,12 @@ 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
@@ -29,9 +35,12 @@ 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
@@ -50,6 +59,7 @@ 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
@@ -60,65 +70,14 @@ import androidx.core.graphics.toColorInt
import kotlinx.coroutines.launch
@Composable
fun Page(name: String, innerPadding: PaddingValues, pages: List<NavigationPageData>? = null, content: @Composable () -> Unit) {
val activityContext = LocalActivity.current
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
BackHandler(
enabled = pages != null && drawerState.isOpen
) {
scope.launch {
drawerState.close()
}
}
ModalNavigationDrawer(
drawerState = drawerState,
drawerContent = {
if (pages != null) {
ModalDrawerSheet(
modifier = Modifier.background(MaterialTheme.colorScheme.background).padding(8.dp)
) {
for (page in pages) {
NavigationDrawerItem(
label = { Text(page.name) },
selected = false,
onClick = {
scope.launch { drawerState.close() }
if (page.pageClass != null) {
val intent = Intent(activityContext, page.pageClass)
activityContext!!.startActivity(intent)
} else if (page.onClick != null) {
page.onClick()
}
}
)
}
}
}
}
) {
fun Page(
name: String,
innerPadding: PaddingValues,
floatingActionButton: @Composable (() -> Unit) = {},
content: @Composable () -> Unit
) {
Scaffold(
topBar = {
TopBar(name, innerPadding, if (pages != null) {
{
Icon(
modifier = Modifier.clickable() {
scope.launch {
drawerState.open()
}
},
imageVector = Icons.Outlined.DensityMedium,
contentDescription = null,
tint = MaterialTheme.colorScheme.onPrimaryContainer
)
}
} else null)
}
floatingActionButton = floatingActionButton
) { padding ->
Box(
modifier = Modifier
@@ -135,6 +94,53 @@ fun Page(name: String, innerPadding: PaddingValues, pages: List<NavigationPageDa
}
}
}
}
@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
)
}
}
}
@@ -5,31 +5,28 @@ import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
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.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.Sync
import androidx.compose.material.icons.outlined.Backup
import androidx.compose.material.icons.outlined.Code
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import kotlinx.serialization.json.Json
import ru.omni_devel.cards.ui.theme.OmniCardsTheme
private const val ANIMATION_DELAY = 300L
class MainActivity : ComponentActivity() {
private lateinit var db: DbHelper
@@ -81,11 +78,12 @@ fun MainPage(
Page(
stringResource(R.string.app_name),
innerPadding,
pages = listOf(
NavigationPageData(stringResource(R.string.do_add_card), EditCardActivity::class.java),
NavigationPageData(stringResource(R.string.do_sync)) {
floatingActionButton = {
ExpandableFab(
items = listOf(
NavigationPageData(stringResource(R.string.do_add_card), Icons.Outlined.Add, EditCardActivity::class.java),
NavigationPageData(stringResource(R.string.do_sync), Icons.Outlined.Sync) {
Toast.makeText(context, context.getString(R.string.sync_in_progress), Toast.LENGTH_SHORT).show()
sendToWatch(context, "/updateCards", Json.encodeToString(getDbFun().getCards())) { isSuccess ->
if (isSuccess) {
Toast.makeText(context, context.getString(R.string.sync_is_successful), Toast.LENGTH_SHORT).show()
@@ -94,11 +92,13 @@ fun MainPage(
}
}
},
NavigationPageData(stringResource(R.string.open_backup_menu), BackupActivity::class.java),
NavigationPageData(stringResource(R.string.source_code)) {
NavigationPageData(stringResource(R.string.open_backup_menu), Icons.Outlined.Backup, BackupActivity::class.java),
NavigationPageData(stringResource(R.string.source_code), Icons.Outlined.Code) {
uriHandler.openUri("https://github.com/omni-devel/OmniCards")
},
)
)
}
) {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(8.dp)
@@ -1,9 +1,11 @@
package ru.omni_devel.cards
import android.app.Activity
import androidx.compose.ui.graphics.vector.ImageVector
data class NavigationPageData(
val name: String,
val icon: ImageVector,
val pageClass: Class<out Activity>? = null,
val onClick: (() -> Unit)? = null
)
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
@@ -15,6 +16,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text
import ru.omni_devel.cards.R
@@ -35,7 +37,7 @@ class MainActivity : ComponentActivity() {
@SuppressLint("UnusedBoxWithConstraintsScope")
@Composable
fun App(cards: List<CardInfo>) {
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
BoxWithConstraints(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {
val topBottomPadding = maxHeight * 0.4f
if (cards.isEmpty()) {