diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceFloatingActionButton.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceFloatingActionButton.kt index 40b153c83..d5e797974 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceFloatingActionButton.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceFloatingActionButton.kt @@ -3,12 +3,12 @@ package eu.kanade.presentation.browse.components import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.FilterList import androidx.compose.material3.Icon +import androidx.compose.material3.SmallExtendedFloatingActionButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import tachiyomi.i18n.MR import tachiyomi.i18n.sy.SYMR -import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton import tachiyomi.presentation.core.i18n.stringResource @Composable @@ -17,7 +17,7 @@ fun BrowseSourceFloatingActionButton( onFabClick: () -> Unit, modifier: Modifier = Modifier, ) { - ExtendedFloatingActionButton( + SmallExtendedFloatingActionButton( modifier = modifier, text = { Text( diff --git a/app/src/main/java/eu/kanade/presentation/category/components/CategoryFloatingActionButton.kt b/app/src/main/java/eu/kanade/presentation/category/components/CategoryFloatingActionButton.kt index a151e9b2f..bb246b066 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/CategoryFloatingActionButton.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/CategoryFloatingActionButton.kt @@ -4,11 +4,11 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Add import androidx.compose.material3.Icon +import androidx.compose.material3.SmallExtendedFloatingActionButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import tachiyomi.i18n.MR -import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.util.shouldExpandFAB @@ -18,7 +18,7 @@ fun CategoryFloatingActionButton( onCreate: () -> Unit, modifier: Modifier = Modifier, ) { - ExtendedFloatingActionButton( + SmallExtendedFloatingActionButton( text = { Text(text = stringResource(MR.strings.action_add)) }, icon = { Icon(imageVector = Icons.Outlined.Add, contentDescription = null) }, onClick = onCreate, diff --git a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt index 4a43e25fe..f1c80accf 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -1,10 +1,7 @@ package eu.kanade.presentation.manga import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut import androidx.compose.foundation.gestures.detectHorizontalDragGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -32,9 +29,11 @@ import androidx.compose.material3.FabPosition import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SmallExtendedFloatingActionButton import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text +import androidx.compose.material3.animateFloatingActionButton import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableFloatState import androidx.compose.runtime.State @@ -123,7 +122,6 @@ import tachiyomi.i18n.MR import tachiyomi.i18n.kmk.KMR import tachiyomi.presentation.core.components.TwoPanelBox import tachiyomi.presentation.core.components.VerticalFastScroller -import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton import tachiyomi.presentation.core.components.material.PullRefresh import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.padding @@ -537,12 +535,23 @@ private fun MangaScreenSmallImpl( val isFABVisible = remember(chapters) { chapters.fastAny { !it.chapter.read } && !isAnySelected } - AnimatedVisibility( - visible = isFABVisible, - enter = fadeIn(), - exit = fadeOut(), - // KMK --> - modifier = Modifier + SmallExtendedFloatingActionButton( + text = { + val isReading = remember(state.chapters) { + state.chapters.fastAny { it.chapter.read } + } + Text( + text = stringResource(if (isReading) MR.strings.action_resume else MR.strings.action_start), + ) + }, + icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) }, + onClick = onContinueReading, + expanded = chapterListState.shouldExpandFAB(), + modifier = Modifier.animateFloatingActionButton( + visible = isFABVisible, + alignment = Alignment.BottomEnd, + ) + // KMK --> .offset { IntOffset(offsetX.roundToInt(), 0) } .onGloballyPositioned { coordinates -> fabSize = coordinates.size @@ -566,25 +575,9 @@ private fun MangaScreenSmallImpl( } } }, + containerColor = MaterialTheme.colorScheme.primary, // KMK <-- - ) { - ExtendedFloatingActionButton( - text = { - val isReading = remember(state.chapters) { - state.chapters.fastAny { it.chapter.read } - } - Text( - text = stringResource(if (isReading) MR.strings.action_resume else MR.strings.action_start), - ) - }, - icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) }, - onClick = onContinueReading, - expanded = chapterListState.shouldExpandFAB(), - // KMK --> - containerColor = MaterialTheme.colorScheme.primary, - // KMK <-- - ) - } + ) }, // KMK --> floatingActionButtonPosition = if (fabPosition == FabPosition.End.toString()) { @@ -1002,12 +995,25 @@ private fun MangaScreenLargeImpl( val isFABVisible = remember(chapters) { chapters.fastAny { !it.chapter.read } && !isAnySelected } - AnimatedVisibility( - visible = isFABVisible, - enter = fadeIn(), - exit = fadeOut(), - // KMK --> - modifier = Modifier + SmallExtendedFloatingActionButton( + text = { + val isReading = remember(state.chapters) { + state.chapters.fastAny { it.chapter.read } + } + Text( + text = stringResource( + if (isReading) MR.strings.action_resume else MR.strings.action_start, + ), + ) + }, + icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) }, + onClick = onContinueReading, + expanded = chapterListState.shouldExpandFAB(), + modifier = Modifier.animateFloatingActionButton( + visible = isFABVisible, + alignment = Alignment.BottomEnd, + ) + // KMK --> .offset { IntOffset(offsetX.roundToInt(), 0) } .onGloballyPositioned { coordinates -> fabSize = coordinates.size @@ -1031,27 +1037,9 @@ private fun MangaScreenLargeImpl( } } }, + containerColor = MaterialTheme.colorScheme.primary, // KMK <-- - ) { - ExtendedFloatingActionButton( - text = { - val isReading = remember(state.chapters) { - state.chapters.fastAny { it.chapter.read } - } - Text( - text = stringResource( - if (isReading) MR.strings.action_resume else MR.strings.action_start, - ), - ) - }, - icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) }, - onClick = onContinueReading, - expanded = chapterListState.shouldExpandFAB(), - // KMK --> - containerColor = MaterialTheme.colorScheme.primary, - // KMK <-- - ) - } + ) }, // KMK --> floatingActionButtonPosition = if (fabPosition == FabPosition.End.toString()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreen.kt index a3332d0ac..de136e6a9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreen.kt @@ -33,6 +33,7 @@ import androidx.compose.material.icons.outlined.SelectAll import androidx.compose.material.icons.outlined.ToggleOn import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SmallExtendedFloatingActionButton import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults @@ -86,7 +87,6 @@ import kotlinx.coroutines.launch import tachiyomi.i18n.MR import tachiyomi.i18n.kmk.KMR import tachiyomi.i18n.sy.SYMR -import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.stringResource @@ -178,7 +178,7 @@ class PreMigrationScreen(val migration: MigrationType) : Screen() { }, // KMK <-- floatingActionButton = { - ExtendedFloatingActionButton( + SmallExtendedFloatingActionButton( text = { Text(text = stringResource(MR.strings.action_migrate)) }, icon = { Icon( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt index 2e068715b..756515b15 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt @@ -1,9 +1,6 @@ package eu.kanade.tachiyomi.ui.download import android.view.LayoutInflater -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -16,8 +13,10 @@ import androidx.compose.material.icons.outlined.Pause import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SmallExtendedFloatingActionButton import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.animateFloatingActionButton import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -57,13 +56,13 @@ import kotlinx.collections.immutable.persistentListOf import tachiyomi.core.common.util.lang.launchUI import tachiyomi.i18n.MR import tachiyomi.presentation.core.components.Pill -import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.screens.EmptyScreen import kotlin.math.roundToInt object DownloadQueueScreen : Screen() { + @Suppress("unused") private fun readResolve(): Any = DownloadQueueScreen @Composable @@ -209,39 +208,37 @@ object DownloadQueueScreen : Screen() { ) }, floatingActionButton = { - AnimatedVisibility( - visible = downloadList.isNotEmpty(), - enter = fadeIn(), - exit = fadeOut(), - ) { - val isRunning by screenModel.isDownloaderRunning.collectAsState() - ExtendedFloatingActionButton( - text = { - val id = if (isRunning) { - MR.strings.action_pause - } else { - MR.strings.action_resume - } - Text(text = stringResource(id)) - }, - icon = { - val icon = if (isRunning) { - Icons.Outlined.Pause - } else { - Icons.Filled.PlayArrow - } - Icon(imageVector = icon, contentDescription = null) - }, - onClick = { - if (isRunning) { - screenModel.pauseDownloads() - } else { - screenModel.startDownloads() - } - }, - expanded = fabExpanded, - ) - } + val isRunning by screenModel.isDownloaderRunning.collectAsState() + SmallExtendedFloatingActionButton( + text = { + val id = if (isRunning) { + MR.strings.action_pause + } else { + MR.strings.action_resume + } + Text(text = stringResource(id)) + }, + icon = { + val icon = if (isRunning) { + Icons.Outlined.Pause + } else { + Icons.Filled.PlayArrow + } + Icon(imageVector = icon, contentDescription = null) + }, + onClick = { + if (isRunning) { + screenModel.pauseDownloads() + } else { + screenModel.startDownloads() + } + }, + expanded = fabExpanded, + modifier = Modifier.animateFloatingActionButton( + visible = downloadList.isNotEmpty(), + alignment = Alignment.BottomEnd, + ), + ) }, ) { contentPadding -> if (downloadList.isEmpty()) { diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt deleted file mode 100644 index c43a6849d..000000000 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt +++ /dev/null @@ -1,131 +0,0 @@ -package tachiyomi.presentation.core.components.material - -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.CubicBezierEasing -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.tween -import androidx.compose.animation.expandHorizontally -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkHorizontally -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.sizeIn -import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.FloatingActionButtonDefaults -import androidx.compose.material3.FloatingActionButtonElevation -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.contentColorFor -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.unit.dp - -/** - * ExtendedFloatingActionButton with custom transition between collapsed/expanded state. - * - * @see androidx.compose.material3.ExtendedFloatingActionButton - */ -@Composable -fun ExtendedFloatingActionButton( - text: @Composable () -> Unit, - icon: @Composable () -> Unit, - onClick: () -> Unit, - modifier: Modifier = Modifier, - expanded: Boolean = true, - interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - shape: Shape = MaterialTheme.shapes.large, - containerColor: Color = MaterialTheme.colorScheme.primaryContainer, - contentColor: Color = contentColorFor(containerColor), - elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(), -) { - FloatingActionButton( - modifier = modifier, - onClick = onClick, - interactionSource = interactionSource, - shape = shape, - containerColor = containerColor, - contentColor = contentColor, - elevation = elevation, - ) { - val minWidth by animateDpAsState( - targetValue = if (expanded) ExtendedFabMinimumWidth else FabContainerWidth, - animationSpec = tween( - durationMillis = 500, - easing = EasingEmphasizedCubicBezier, - ), - label = "minWidth", - ) - val startPadding by animateDpAsState( - targetValue = if (expanded) ExtendedFabIconSize / 2 else 0.dp, - animationSpec = tween( - durationMillis = if (expanded) 300 else 900, - easing = EasingEmphasizedCubicBezier, - ), - label = "startPadding", - ) - - Row( - modifier = Modifier - .sizeIn(minWidth = minWidth) - .padding(start = startPadding), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - ) { - icon() - AnimatedVisibility( - visible = expanded, - enter = ExtendedFabExpandAnimation, - exit = ExtendedFabCollapseAnimation, - ) { - Box(modifier = Modifier.padding(start = ExtendedFabIconPadding, end = ExtendedFabTextPadding)) { - text() - } - } - } - } -} - -private val EasingLinearCubicBezier = CubicBezierEasing(0.0f, 0.0f, 1.0f, 1.0f) -private val EasingEmphasizedCubicBezier = CubicBezierEasing(0.2f, 0.0f, 0.0f, 1.0f) - -private val ExtendedFabMinimumWidth = 80.dp -private val ExtendedFabIconSize = 24.0.dp -private val ExtendedFabIconPadding = 12.dp -private val ExtendedFabTextPadding = 20.dp - -private val ExtendedFabCollapseAnimation = fadeOut( - animationSpec = tween( - durationMillis = 100, - easing = EasingLinearCubicBezier, - ), -) + shrinkHorizontally( - animationSpec = tween( - durationMillis = 500, - easing = EasingEmphasizedCubicBezier, - ), - shrinkTowards = Alignment.Start, -) - -private val ExtendedFabExpandAnimation = fadeIn( - animationSpec = tween( - durationMillis = 200, - delayMillis = 100, - easing = EasingLinearCubicBezier, - ), -) + expandHorizontally( - animationSpec = tween( - durationMillis = 500, - easing = EasingEmphasizedCubicBezier, - ), - expandFrom = Alignment.Start, -) - -private val FabContainerWidth = 56.0.dp diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/util/LazyListState.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/util/LazyListState.kt index 5d77db82c..69d9b0b5e 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/util/LazyListState.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/util/LazyListState.kt @@ -12,17 +12,7 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import kotlinx.coroutines.flow.distinctUntilChanged -@Composable -fun LazyListState.shouldExpandFAB(): Boolean { - return remember { - derivedStateOf { - (firstVisibleItemIndex == 0 && firstVisibleItemScrollOffset == 0) || - lastScrolledBackward || - !canScrollForward - } - } - .value -} +fun LazyListState.shouldExpandFAB(): Boolean = lastScrolledBackward || !canScrollForward || !canScrollBackward @Composable fun LazyListState.isScrolledToStart(): Boolean {