diff --git a/app/compose-stability-config.txt b/app/compose-stability-config.txt new file mode 100644 index 0000000..5fe0b1c --- /dev/null +++ b/app/compose-stability-config.txt @@ -0,0 +1 @@ +kotlin.collections.* \ No newline at end of file diff --git a/app/src/main/java/com/sirelon/marsroverphotos/feature/photos/RoverPhotosScreen.kt b/app/src/main/java/com/sirelon/marsroverphotos/feature/photos/RoverPhotosScreen.kt index 0192316..9535ebd 100644 --- a/app/src/main/java/com/sirelon/marsroverphotos/feature/photos/RoverPhotosScreen.kt +++ b/app/src/main/java/com/sirelon/marsroverphotos/feature/photos/RoverPhotosScreen.kt @@ -127,6 +127,7 @@ fun RoverPhotosScreen( viewModel.randomize() }) } + else -> { PhotosList(modifier, it) { image -> viewModel.onPhotoClick(image) @@ -138,8 +139,18 @@ fun RoverPhotosScreen( } } - val fabVisible = photos?.isNotEmpty() == true - RefreshButton(fabVisible, modifier, viewModel) + val fabVisible = remember(photos?.size) { + photos?.isNotEmpty() == true + } + + RefreshButton( + fabVisible = fabVisible, + modifier = modifier, + onClick = { + viewModel.track("click_refresh") + viewModel.goToLatest() + }, + ) } @ExperimentalAnimationApi @@ -147,7 +158,7 @@ fun RoverPhotosScreen( private fun RefreshButton( fabVisible: Boolean, modifier: Modifier, - viewModel: PhotosViewModel + onClick: () -> Unit, ) { AnimatedVisibility(visible = fabVisible, enter = fadeIn(), exit = fadeOut()) { Box( @@ -157,10 +168,8 @@ private fun RefreshButton( ) { FloatingActionButton( modifier = Modifier.align(Alignment.BottomEnd), - onClick = { - viewModel.track("click_refresh") - viewModel.goToLatest() - }) { + onClick = onClick + ) { Icon( imageVector = Icons.Filled.Autorenew, contentDescription = "refresh" @@ -179,34 +188,43 @@ private fun PhotosList( ) { LazyVerticalGrid(columns = GridCells.Fixed(2), modifier = modifier) { - items(photos) { image -> - Card( + items( + photos, + key = { it.id }, + contentType = { "MarsPhotoContentType" }, + ) { image -> + PhotoCard(image = image, onPhotoClick = onPhotoClick) + } + } +} + +@Composable +private fun PhotoCard( + image: MarsImage, + onPhotoClick: (image: MarsImage) -> Unit +) { + Card( + modifier = Modifier + .padding(8.dp) + .fillMaxWidth() + .clickable { + onPhotoClick(image) + }, + shape = MaterialTheme.shapes.large + ) { + Column(verticalArrangement = Arrangement.SpaceBetween) { + NetworkImage( modifier = Modifier - .padding(8.dp) .fillMaxWidth() - .clickable { - onPhotoClick(image) - }, - shape = MaterialTheme.shapes.large - ) { - Column(verticalArrangement = Arrangement.SpaceBetween) { - NetworkImage( - modifier = Modifier - .fillMaxWidth() - .aspectRatio(1F), - imageUrl = image.imageUrl - ) - val title = image.name - if (title != null) { - Text( - text = title, - style = MaterialTheme.typography.bodySmall, - modifier = Modifier.padding(4.dp), - textAlign = TextAlign.Center - ) - } - } - } + .aspectRatio(1F), + imageUrl = image.imageUrl + ) + Text( + text = image.name.orEmpty(), + style = MaterialTheme.typography.bodySmall, + modifier = Modifier.padding(4.dp), + textAlign = TextAlign.Center + ) } } } diff --git a/app/src/main/java/com/sirelon/marsroverphotos/models/Rover.kt b/app/src/main/java/com/sirelon/marsroverphotos/models/Rover.kt index 54ea9c4..7903e8c 100644 --- a/app/src/main/java/com/sirelon/marsroverphotos/models/Rover.kt +++ b/app/src/main/java/com/sirelon/marsroverphotos/models/Rover.kt @@ -3,6 +3,8 @@ package com.sirelon.marsroverphotos.models import android.content.Context import androidx.annotation.DrawableRes import androidx.annotation.Keep +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.Stable import androidx.room.Entity import androidx.room.PrimaryKey import kotlinx.serialization.SerialName @@ -13,6 +15,8 @@ import kotlinx.serialization.Serializable * @since 31.10.16 on 15:14 */ @Keep +@Stable +@Immutable @Entity @Serializable data class Rover( diff --git a/app/src/main/java/com/sirelon/marsroverphotos/storage/MarsImage.kt b/app/src/main/java/com/sirelon/marsroverphotos/storage/MarsImage.kt index aeecfee..d2b7474 100644 --- a/app/src/main/java/com/sirelon/marsroverphotos/storage/MarsImage.kt +++ b/app/src/main/java/com/sirelon/marsroverphotos/storage/MarsImage.kt @@ -3,6 +3,7 @@ package com.sirelon.marsroverphotos.storage import androidx.room.Embedded import androidx.room.Entity import androidx.room.PrimaryKey +import com.google.common.math.Stats import com.sirelon.marsroverphotos.models.RoverCamera /** @@ -24,7 +25,7 @@ data class MarsImage( val favorite: Boolean = false, val popular: Boolean = false, @Embedded(prefix = "counter_") - val stats: Stats + val stats: Stats, ) { class Stats( diff --git a/build.gradle b/build.gradle index 369cc54..2027cc3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { alias(libs.plugins.android.application) apply false @@ -19,3 +21,29 @@ allprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// To check perfomance run script +// ./gradlew assembleRelease -PcomposeCompilerReports=true +// what's need to pay attention for check here https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md#enabling-metrics +subprojects { + tasks.withType(KotlinCompile) { + def dirProperty = project.layout.getProjectDirectory().asFile + + def rootDirPath = dirProperty.absolutePath + + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=$rootDirPath/compose-stability-config.txt" + ) + + def composeAnalyticsDir = rootDirPath + "/compose_compiler_analytics" + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + composeAnalyticsDir, + ) + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + composeAnalyticsDir, + ) + } +} \ No newline at end of file