Skip to content

Commit

Permalink
feat: Basic shared element transitions
Browse files Browse the repository at this point in the history
  • Loading branch information
Lastaapps committed Jan 15, 2025
1 parent 53a2485 commit d40c60e
Show file tree
Hide file tree
Showing 16 changed files with 449 additions and 97 deletions.
4 changes: 4 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2024, Petr Laštovička as Lasta apps, All rights reserved
* Copyright 2025, Petr Laštovička as Lasta apps, All rights reserved
*
* This file is part of Menza.
*
Expand Down Expand Up @@ -27,6 +27,8 @@ data class DishCategory(
val name: String?,
val dishList: ImmutableList<Dish>,
) {
val someName get() = name ?: nameShort

companion object {
fun other(dishList: ImmutableList<Dish>) = DishCategory(null, null, dishList)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ internal fun MainScreen(
currentDest?.toNavItem()
}

val appearanceDelay = 200.milliseconds
val appearanceDelay = 0.milliseconds
MenzaScaffold(
drawerState = drawerState,
alternativeNavigation = alternativeNavigation,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2024, Petr Laštovička as Lasta apps, All rights reserved
* Copyright 2025, Petr Laštovička as Lasta apps, All rights reserved
*
* This file is part of Menza.
*
Expand Down Expand Up @@ -36,6 +36,7 @@ import cz.lastaapps.menza.features.today.ui.navigation.DefaultDishDetailComponen
import cz.lastaapps.menza.features.today.ui.navigation.DishDetailComponent.Child
import cz.lastaapps.menza.features.today.ui.screen.DishDetailScreen
import cz.lastaapps.menza.features.today.ui.vm.DishDetailViewModel
import cz.lastaapps.menza.ui.util.AnimationScopes
import cz.lastaapps.menza.ui.util.getOrCreateKoin
import kotlinx.serialization.Serializable
import org.koin.core.component.KoinComponent
Expand Down Expand Up @@ -101,11 +102,13 @@ internal class DefaultDishDetailComponent(
@Composable
internal fun DishDetailContent(
component: DishDetailComponent,
scopes: AnimationScopes,
modifier: Modifier = Modifier,
) {
DishDetailScreen(
component.viewModel,
onRating = component::onRateDish,
scopes = scopes,
modifier = modifier,
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2024, Petr Laštovička as Lasta apps, All rights reserved
* Copyright 2025, Petr Laštovička as Lasta apps, All rights reserved
*
* This file is part of Menza.
*
Expand Down Expand Up @@ -30,6 +30,7 @@ import cz.lastaapps.menza.features.panels.rateus.ui.RateUsViewModel
import cz.lastaapps.menza.features.panels.whatsnew.ui.vm.WhatsNewViewModel
import cz.lastaapps.menza.features.today.ui.screen.DishListScreen
import cz.lastaapps.menza.features.today.ui.vm.DishListViewModel
import cz.lastaapps.menza.ui.util.AnimationScopes
import cz.lastaapps.menza.ui.util.getOrCreateKoin
import org.koin.core.component.KoinComponent

Expand Down Expand Up @@ -59,6 +60,7 @@ internal fun DishListContent(
component: DishListComponent,
onOsturak: () -> Unit,
hostState: SnackbarHostState,
scopes: AnimationScopes,
modifier: Modifier = Modifier,
) {
val panels: @Composable (Modifier) -> Unit = {
Expand All @@ -78,6 +80,7 @@ internal fun DishListContent(
onDish = component.onDishSelected,
onRating = { error("Not supported") },
hostState = hostState,
scopes = scopes,
modifier = modifier,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@
* along with Menza. If not, see <https://www.gnu.org/licenses/>.
*/

@file:OptIn(ExperimentalDecomposeApi::class, ExperimentalSerializationApi::class)
@file:OptIn(
ExperimentalDecomposeApi::class,
ExperimentalSerializationApi::class,
ExperimentalSharedTransitionApi::class,
)

package cz.lastaapps.menza.features.today.ui.navigation

import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.animation.expandIn
import androidx.compose.animation.fadeIn
import androidx.compose.animation.slideIn
Expand Down Expand Up @@ -70,8 +76,9 @@ import cz.lastaapps.menza.features.today.ui.screen.ImagePreviewDialog
import cz.lastaapps.menza.features.today.ui.vm.TodayViewModel
import cz.lastaapps.menza.features.today.ui.widget.NoDishSelected
import cz.lastaapps.menza.ui.theme.Padding
import cz.lastaapps.menza.ui.theme.appPredictiveBackParams
import cz.lastaapps.menza.ui.theme.fadingPredictiveBackParams
import cz.lastaapps.menza.ui.util.AnimatedAppearance
import cz.lastaapps.menza.ui.util.AnimationScopes
import cz.lastaapps.menza.ui.util.ChildPanelsModeFoldingEffect
import cz.lastaapps.menza.ui.util.getOrCreateKoin
import cz.lastaapps.menza.ui.util.rememberChildPanelsFoldingLayout
Expand Down Expand Up @@ -211,44 +218,47 @@ internal fun TodayContent(
}
},
) { padding ->
ChildPanels(
modifier =
Modifier
.padding(padding)
.fillMaxSize(),
panels = component.content,
layout = rememberChildPanelsFoldingLayout(),
mainChild = {
DishListContent(
it.instance,
onOsturak = onOsturak,
hostState = hostState,
modifier = panelModifier,
)
},
detailsChild = {
DishDetailContent(
it.instance,
modifier = panelModifier,
)
},
secondPanelPlaceholder = {
NoDishSelected(
modifier = panelModifier,
)
},
animators =
ChildPanelsAnimators(
single = fade() + scale(),
dual = fade() to fade(),
),
predictiveBackParams = {
appPredictiveBackParams(
backHandler = component.backHandler,
onBack = component::onBackClicked,
)
},
)
SharedTransitionLayout(
modifier = Modifier.padding(padding),
) {
ChildPanels(
modifier = Modifier.fillMaxSize(),
panels = component.content,
layout = rememberChildPanelsFoldingLayout(),
mainChild = {
DishListContent(
it.instance,
onOsturak = onOsturak,
hostState = hostState,
scopes = AnimationScopes(),
modifier = panelModifier,
)
},
detailsChild = {
DishDetailContent(
it.instance,
scopes = AnimationScopes(),
modifier = panelModifier,
)
},
secondPanelPlaceholder = {
NoDishSelected(
modifier = panelModifier,
)
},
animators =
ChildPanelsAnimators(
single = fade() + scale(),
dual = fade() to fade(),
),
predictiveBackParams = {
fadingPredictiveBackParams(
backHandler = component.backHandler,
onBack = component::onBackClicked,
)
},
)
}
}

videoFeedUrl?.let {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2024, Petr Laštovička as Lasta apps, All rights reserved
* Copyright 2025, Petr Laštovička as Lasta apps, All rights reserved
*
* This file is part of Menza.
*
Expand All @@ -19,18 +19,22 @@

package cz.lastaapps.menza.features.today.ui.screen

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import cz.lastaapps.api.core.domain.model.DishOriginDescriptor
import cz.lastaapps.menza.features.today.ui.vm.DishDetailState
import cz.lastaapps.menza.features.today.ui.vm.DishDetailViewModel
import cz.lastaapps.menza.features.today.ui.widget.TodayDishDetail
import cz.lastaapps.menza.ui.util.AnimationScopes

@Composable
internal fun DishDetailScreen(
viewModel: DishDetailViewModel,
onRating: (DishOriginDescriptor) -> Unit,
scopes: AnimationScopes,
modifier: Modifier = Modifier,
) {
DishDetailEffects(viewModel)
Expand All @@ -39,6 +43,7 @@ internal fun DishDetailScreen(
DishDetailContent(
state = state,
onRating = onRating,
scopes = scopes,
modifier = modifier,
)
}
Expand All @@ -52,13 +57,19 @@ private fun DishDetailEffects(viewModel: DishDetailViewModel) {
private fun DishDetailContent(
state: DishDetailState,
onRating: (DishOriginDescriptor) -> Unit,
scopes: AnimationScopes,
modifier: Modifier = Modifier,
) {
state.dish?.let { dish ->
TodayDishDetail(
dish = dish,
onRating = { onRating(DishOriginDescriptor.from(it)) },
modifier = modifier,
)
Surface(
modifier = modifier,
) {
state.dish?.let { dish ->
TodayDishDetail(
dish = dish,
onRating = { onRating(DishOriginDescriptor.from(it)) },
scopes = scopes,
modifier = Modifier.fillMaxSize(),
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import cz.lastaapps.menza.features.today.ui.widget.TodayDishGrid
import cz.lastaapps.menza.features.today.ui.widget.TodayDishHorizontal
import cz.lastaapps.menza.features.today.ui.widget.TodayDishList
import cz.lastaapps.menza.ui.theme.Padding
import cz.lastaapps.menza.ui.util.AnimationScopes
import cz.lastaapps.menza.ui.util.HandleError

@Composable
Expand All @@ -65,6 +66,7 @@ internal fun DishListScreen(
onDish: (Dish) -> Unit,
onRating: (Dish) -> Unit,
hostState: SnackbarHostState,
scopes: AnimationScopes,
modifier: Modifier = Modifier,
) {
DishListEffects(viewModel, hostState)
Expand All @@ -91,6 +93,7 @@ internal fun DishListScreen(
panels = panels,
onOsturak = onOsturak,
scrollStates = scrollStates,
scopes = scopes,
)
}

Expand All @@ -116,6 +119,7 @@ private fun DishListContent(
onOsturak: () -> Unit,
onRating: (Dish) -> Unit,
scrollStates: ScrollStates,
scopes: AnimationScopes,
modifier: Modifier = Modifier,
) {
Column(
Expand All @@ -140,6 +144,7 @@ private fun DishListContent(
onViewMode = onViewMode,
onImageScale = onImageScale,
onOliverRow = onOliverRow,
scopes = scopes,
)
}

Expand All @@ -163,6 +168,7 @@ private fun DishListComposing(
onOliverRow: (Boolean) -> Unit,
onRating: (Dish) -> Unit,
scrollStates: ScrollStates,
scopes: AnimationScopes,
modifier: Modifier = Modifier,
) = Column {
val userSettings = state.userSettings
Expand Down Expand Up @@ -226,6 +232,7 @@ private fun DishListComposing(
},
modifier = modifier.fillMaxSize(),
scroll = scrollStates.list,
scopes = scopes,
)

GRID ->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2025, Petr Laštovička as Lasta apps, All rights reserved
*
* This file is part of Menza.
*
* Menza is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Menza is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Menza. If not, see <https://www.gnu.org/licenses/>.
*/

package cz.lastaapps.menza.features.today.ui.util

import cz.lastaapps.api.core.domain.model.dish.DishID

fun dishContainerKey(dishID: DishID) = "dishContainer_${dishID.value}"

fun dishImageKey(dishID: DishID) = "dishImage_${dishID.value}"

fun dishTitleKey(dishID: DishID) = "dishName_${dishID.value}"
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ internal class DishListViewModel(
}.launchIn(scope)

// Refreshes the screen if user is looking at the data for at least 42 seconds
if (appInfoProvider.isDebug()) {
if (!appInfoProvider.isDebug()) {
flow
.map { it.selectedMenza?.getOrNull() }
.distinctUntilChanged()
Expand Down
Loading

0 comments on commit d40c60e

Please sign in to comment.