Skip to content

Commit

Permalink
Make game's info header animatable using Compose's MotionLayout (#245)
Browse files Browse the repository at this point in the history
  • Loading branch information
mars885 authored Oct 23, 2024
1 parent 4926cb6 commit 0a582d4
Show file tree
Hide file tree
Showing 7 changed files with 1,006 additions and 1,518 deletions.
2 changes: 1 addition & 1 deletion app/src/main/res/values-night/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
<style name="GamedgeThemeSplash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/dark_colorPrimary</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_splash_light</item>
<item name="postSplashScreenTheme">@style/Theme.AppCompat.NoActionBar</item>
<item name="postSplashScreenTheme">@android:style/Theme.Material.NoActionBar</item>
</style>
</resources>
2 changes: 1 addition & 1 deletion app/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
<style name="GamedgeThemeSplash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/light_colorPrimary</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_splash_dark</item>
<item name="postSplashScreenTheme">@style/Theme.AppCompat.Light.NoActionBar</item>
<item name="postSplashScreenTheme">@android:style/Theme.Material.Light.NoActionBar</item>
</style>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class Spaces(
spacing_6_5: Dp = 26.dp,
spacing_7_0: Dp = 28.dp,
spacing_7_5: Dp = 30.dp,
spacing_8_0: Dp = 32.dp,
spacing_8_5: Dp = 34.dp,
spacing_9_0: Dp = 36.dp,
) {
var spacing_0_5 by mutableStateOf(spacing_0_5)
private set
Expand Down Expand Up @@ -73,6 +76,12 @@ class Spaces(
private set
var spacing_7_5 by mutableStateOf(spacing_7_5)
private set
var spacing_8_0 by mutableStateOf(spacing_8_0)
private set
var spacing_8_5 by mutableStateOf(spacing_8_5)
private set
var spacing_9_0 by mutableStateOf(spacing_9_0)
private set

override fun toString(): String {
return "Spaces(" +
Expand All @@ -90,7 +99,10 @@ class Spaces(
"spacing_6_0=$spacing_6_0, " +
"spacing_6_5=$spacing_6_5, " +
"spacing_7_0=$spacing_7_0, " +
"spacing_7_5=$spacing_7_5" +
"spacing_7_5=$spacing_7_5, " +
"spacing_8_0=$spacing_8_0, " +
"spacing_8_5=$spacing_8_5, " +
"spacing_9_0=$spacing_9_0" +
")"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
Expand All @@ -32,13 +34,15 @@ import androidx.compose.foundation.layout.windowInsetsTopHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
Expand Down Expand Up @@ -233,89 +237,83 @@ private fun SuccessState(
onCompanyClicked: (GameInfoCompanyUiModel) -> Unit,
onRelatedGameClicked: (GameInfoRelatedGameUiModel) -> Unit,
) {
LazyColumn(
modifier = Modifier.fillMaxWidth(),
contentPadding = contentPadding,
verticalArrangement = Arrangement.spacedBy(GamedgeTheme.spaces.spacing_3_5),
) {
headerItem(
model = gameInfo.headerModel,
onArtworkClicked = onArtworkClicked,
onBackButtonClicked = onBackButtonClicked,
onCoverClicked = onCoverClicked,
onLikeButtonClicked = onLikeButtonClicked,
)

if (gameInfo.hasVideos) {
videosItem(
videos = gameInfo.videoModels,
onVideoClicked = onVideoClicked,
)
}
val listState = rememberLazyListState()

GameInfoHeader(
headerInfo = gameInfo.headerModel,
listState = listState,
onArtworkClicked = onArtworkClicked,
onBackButtonClicked = onBackButtonClicked,
onCoverClicked = onCoverClicked,
onLikeButtonClicked = onLikeButtonClicked,
) { modifier ->
val layoutDirection = LocalLayoutDirection.current
val spacing = GamedgeTheme.spaces.spacing_3_5

LazyColumn(
modifier = modifier,
state = listState,
contentPadding = PaddingValues(
start = contentPadding.calculateStartPadding(layoutDirection),
top = contentPadding.calculateTopPadding().plus(spacing),
end = contentPadding.calculateEndPadding(layoutDirection),
bottom = contentPadding.calculateBottomPadding(),
),
verticalArrangement = Arrangement.spacedBy(spacing),
) {
if (gameInfo.hasVideos) {
videosItem(
videos = gameInfo.videoModels,
onVideoClicked = onVideoClicked,
)
}

if (gameInfo.hasScreenshots) {
screenshotsItem(
screenshots = gameInfo.screenshotModels,
onScreenshotClicked = onScreenshotClicked,
)
}
if (gameInfo.hasScreenshots) {
screenshotsItem(
screenshots = gameInfo.screenshotModels,
onScreenshotClicked = onScreenshotClicked,
)
}

if (gameInfo.hasSummary) {
summaryItem(model = checkNotNull(gameInfo.summary))
}
if (gameInfo.hasSummary) {
summaryItem(model = checkNotNull(gameInfo.summary))
}

if (gameInfo.hasDetails) {
detailsItem(model = checkNotNull(gameInfo.detailsModel))
}
if (gameInfo.hasDetails) {
detailsItem(model = checkNotNull(gameInfo.detailsModel))
}

if (gameInfo.hasLinks) {
linksItem(
model = gameInfo.linkModels,
onLinkClicked = onLinkClicked,
)
}
if (gameInfo.hasLinks) {
linksItem(
model = gameInfo.linkModels,
onLinkClicked = onLinkClicked,
)
}

if (gameInfo.hasCompanies) {
companiesItem(
model = gameInfo.companyModels,
onCompanyClicked = onCompanyClicked,
)
}
if (gameInfo.hasCompanies) {
companiesItem(
model = gameInfo.companyModels,
onCompanyClicked = onCompanyClicked,
)
}

if (gameInfo.hasOtherCompanyGames) {
relatedGamesItem(
model = checkNotNull(gameInfo.otherCompanyGames),
onGameClicked = onRelatedGameClicked,
)
}
if (gameInfo.hasOtherCompanyGames) {
relatedGamesItem(
model = checkNotNull(gameInfo.otherCompanyGames),
onGameClicked = onRelatedGameClicked,
)
}

if (gameInfo.hasSimilarGames) {
relatedGamesItem(
model = checkNotNull(gameInfo.similarGames),
onGameClicked = onRelatedGameClicked,
)
if (gameInfo.hasSimilarGames) {
relatedGamesItem(
model = checkNotNull(gameInfo.similarGames),
onGameClicked = onRelatedGameClicked,
)
}
}
}
}

private fun LazyListScope.headerItem(
model: GameInfoHeaderUiModel,
onArtworkClicked: (artworkIndex: Int) -> Unit,
onBackButtonClicked: () -> Unit,
onCoverClicked: () -> Unit,
onLikeButtonClicked: () -> Unit,
) {
gameInfoItem(item = GameInfoItem.Header) {
GameInfoHeader(
headerInfo = model,
onArtworkClicked = onArtworkClicked,
onBackButtonClicked = onBackButtonClicked,
onCoverClicked = onCoverClicked,
onLikeButtonClicked = onLikeButtonClicked,
)
}
}

private fun LazyListScope.videosItem(
videos: List<GameInfoVideoUiModel>,
onVideoClicked: (GameInfoVideoUiModel) -> Unit,
Expand Down Expand Up @@ -418,19 +416,18 @@ private enum class GameInfoItem(
val key: Int,
val contentType: Int,
) {
Header(key = 1, contentType = 1),
Videos(key = 2, contentType = 2),
Screenshots(key = 3, contentType = 3),
Summary(key = 4, contentType = 4),
Details(key = 5, contentType = 5),
Links(key = 6, contentType = 6),
Companies(key = 7, contentType = 7),
Videos(key = 1, contentType = 1),
Screenshots(key = 2, contentType = 2),
Summary(key = 3, contentType = 3),
Details(key = 4, contentType = 4),
Links(key = 5, contentType = 5),
Companies(key = 6, contentType = 6),

// Both other & similar games is the same composable
// filled with different data. That's why contentType
// is the same for them two.
OtherCompanyGames(key = 8, contentType = 8),
SimilarGames(key = 9, contentType = 8),
OtherCompanyGames(key = 7, contentType = 7),
SimilarGames(key = 8, contentType = 7),
}

// TODO (02.01.2022): Currently, preview height is limited to 2k DP.
Expand Down
Loading

0 comments on commit 0a582d4

Please sign in to comment.