diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c278ff2bc..28905fb30 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,8 +1,8 @@ import com.guru.composecookbook.build.configurations.ProjectConfigs +import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { id("com.android.application") - id("kotlin-android") id("com.google.devtools.ksp") id("org.jetbrains.kotlin.plugin.compose") } @@ -31,16 +31,15 @@ android { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } - kotlinOptions { - jvmTarget = "1.8" - // useIR = true - freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn" - } buildFeatures { compose = true } lint { abortOnError = false } testOptions { unitTests.all { it.useJUnitPlatform() } } } +// AGP 9.0 ships built-in Kotlin (replacing the kotlin-android plugin), so the +// JVM target is configured through the Kotlin compiler options. +kotlin { compilerOptions { jvmTarget.set(JvmTarget.JVM_1_8) } } + dependencies { implementation(project(":data")) implementation(project(":theme")) diff --git a/app/src/main/java/com/guru/composecookbook/ui/animation/AnimatableSuspendingAnimations.kt b/app/src/main/java/com/guru/composecookbook/ui/animation/AnimatableSuspendingAnimations.kt index cc3db233e..47bfdf180 100644 --- a/app/src/main/java/com/guru/composecookbook/ui/animation/AnimatableSuspendingAnimations.kt +++ b/app/src/main/java/com/guru/composecookbook/ui/animation/AnimatableSuspendingAnimations.kt @@ -115,7 +115,9 @@ fun DraggableCardWithAnimatable() { Material3Card( backgroundColor = green200, modifier = - modifier.size(100.dp).offset(x = pointerAnimatableX.value.dp, y = pointerAnimatableX.value.dp), + modifier + .size(100.dp) + .offset(x = pointerAnimatableX.value.dp, y = pointerAnimatableX.value.dp), ) {} Spacer(modifier = Modifier.height(100.dp)) } diff --git a/app/src/main/java/com/guru/composecookbook/ui/animation/AnimateAsStateAnimations.kt b/app/src/main/java/com/guru/composecookbook/ui/animation/AnimateAsStateAnimations.kt index 462083c3f..1249f4532 100644 --- a/app/src/main/java/com/guru/composecookbook/ui/animation/AnimateAsStateAnimations.kt +++ b/app/src/main/java/com/guru/composecookbook/ui/animation/AnimateAsStateAnimations.kt @@ -173,7 +173,8 @@ fun SimpleAnimateCustomStateClass() { Button( onClick = { enabled = !enabled }, - modifier = Modifier.padding(16.dp).width(animatedUiState.width).rotate(animatedUiState.rotation), + modifier = + Modifier.padding(16.dp).width(animatedUiState.width).rotate(animatedUiState.rotation), ) { Text("Custom State Animation") } diff --git a/app/src/main/java/com/guru/composecookbook/ui/home/contrast/ContrastThemeActivity.kt b/app/src/main/java/com/guru/composecookbook/ui/home/contrast/ContrastThemeActivity.kt index f18002668..397a1959a 100644 --- a/app/src/main/java/com/guru/composecookbook/ui/home/contrast/ContrastThemeActivity.kt +++ b/app/src/main/java/com/guru/composecookbook/ui/home/contrast/ContrastThemeActivity.kt @@ -139,7 +139,10 @@ fun ContrastThemeDemo(dark: Boolean) { selected = level == value, onClick = { level = value }, shape = - SegmentedButtonDefaults.itemShape(index = index, count = ContrastLevel.entries.size), + SegmentedButtonDefaults.itemShape( + index = index, + count = ContrastLevel.entries.size, + ), ) { Text(value.label) } diff --git a/app/src/main/java/com/guru/composecookbook/ui/learnwidgets/Layouts.kt b/app/src/main/java/com/guru/composecookbook/ui/learnwidgets/Layouts.kt index f2f67ceba..35628c0d8 100644 --- a/app/src/main/java/com/guru/composecookbook/ui/learnwidgets/Layouts.kt +++ b/app/src/main/java/com/guru/composecookbook/ui/learnwidgets/Layouts.kt @@ -70,7 +70,8 @@ fun TypesOfRows() { ) Row( horizontalArrangement = Arrangement.SpaceAround, - modifier = Modifier.padding(8.dp).fillMaxWidth().testTag(TestTags.HOME_LAYOUTS_ROW_SPACE_AROUND), + modifier = + Modifier.padding(8.dp).fillMaxWidth().testTag(TestTags.HOME_LAYOUTS_ROW_SPACE_AROUND), ) { MultipleTexts() } @@ -93,7 +94,8 @@ fun TypesOfRows() { ) Row( horizontalArrangement = Arrangement.SpaceEvenly, - modifier = Modifier.padding(8.dp).fillMaxWidth().testTag(TestTags.HOME_LAYOUTS_ROW_SPACE_EVENLY), + modifier = + Modifier.padding(8.dp).fillMaxWidth().testTag(TestTags.HOME_LAYOUTS_ROW_SPACE_EVENLY), ) { MultipleTexts() } diff --git a/app/src/main/java/com/guru/composecookbook/ui/learnwidgets/SegmentedButtons.kt b/app/src/main/java/com/guru/composecookbook/ui/learnwidgets/SegmentedButtons.kt index 2fa24a569..1e5ec177f 100644 --- a/app/src/main/java/com/guru/composecookbook/ui/learnwidgets/SegmentedButtons.kt +++ b/app/src/main/java/com/guru/composecookbook/ui/learnwidgets/SegmentedButtons.kt @@ -54,7 +54,10 @@ fun SegmentedButtons() { selected = selected == option, onClick = { selected = option }, shape = - SegmentedButtonDefaults.itemShape(index = options.indexOf(option), count = options.size), + SegmentedButtonDefaults.itemShape( + index = options.indexOf(option), + count = options.size, + ), ) { Text(option) } diff --git a/build.gradle.kts b/build.gradle.kts index 639ddad40..68e957afc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,22 +3,22 @@ // build classpath through buildSrc's dependencies (also catalog-driven), so // only ktfmt needs to be declared here. plugins { - alias(libs.plugins.ktfmt) apply false - alias(libs.plugins.roborazzi) apply false + alias(libs.plugins.ktfmt) apply false + alias(libs.plugins.roborazzi) apply false } allprojects { - repositories { - mavenCentral() - google() - maven(url = "https://jitpack.io") - } + repositories { + mavenCentral() + google() + maven(url = "https://jitpack.io") + } - // Apply ktfmt to all projects - apply(plugin = "com.ncorti.ktfmt.gradle") + // Apply ktfmt to all projects + apply(plugin = "com.ncorti.ktfmt.gradle") - configure { - googleStyle() - maxWidth.set(100) - } + configure { + googleStyle() + maxWidth.set(100) + } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 994df7979..63e9fafd1 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -17,7 +17,7 @@ repositories { } dependencies { - // in order to be able to use "kotlin-android" in the common script + // for the Kotlin Gradle plugin DSL (kotlin { compilerOptions }, JvmTarget) in the common scripts implementation(libs.kotlin.gradle.plugin) // in order to be able to apply "org.jetbrains.kotlin.plugin.compose" in the common scripts @@ -27,7 +27,7 @@ dependencies { implementation(libs.kotlin.serialization.plugin) // in order to be able to apply "com.google.devtools.ksp" in the common scripts - // (the KSP version in the catalog must match the Kotlin version) + // (KSP 2.3.x is versioned independently of Kotlin since Kotlin 2.2) implementation(libs.ksp.gradle.plugin) // in order to recognize the "plugins" block in the common script diff --git a/buildSrc/src/main/kotlin/common-compose-module-configs-script-plugin.gradle.kts b/buildSrc/src/main/kotlin/common-compose-module-configs-script-plugin.gradle.kts index f2389f7c2..e3b9aec5a 100644 --- a/buildSrc/src/main/kotlin/common-compose-module-configs-script-plugin.gradle.kts +++ b/buildSrc/src/main/kotlin/common-compose-module-configs-script-plugin.gradle.kts @@ -1,8 +1,8 @@ import com.guru.composecookbook.build.configurations.ProjectConfigs +import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { id("com.android.library") - id("kotlin-android") id("org.jetbrains.kotlin.plugin.compose") } @@ -11,7 +11,6 @@ android { defaultConfig { minSdk = ProjectConfigs.minSdkVersion - targetSdk = ProjectConfigs.targetSdkVersion testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -19,13 +18,17 @@ android { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = "17" - freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn" - } buildFeatures { compose = true } } +// AGP 9.0 ships built-in Kotlin (replacing the kotlin-android plugin), so the +// JVM target is configured through the Kotlin compiler options. +kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } +} + // Namespace will be set by individual module diff --git a/buildSrc/src/main/kotlin/common-kotlin-module-configs-script-plugin.gradle.kts b/buildSrc/src/main/kotlin/common-kotlin-module-configs-script-plugin.gradle.kts index 77b352c22..4711b72e8 100644 --- a/buildSrc/src/main/kotlin/common-kotlin-module-configs-script-plugin.gradle.kts +++ b/buildSrc/src/main/kotlin/common-kotlin-module-configs-script-plugin.gradle.kts @@ -1,31 +1,35 @@ import com.guru.composecookbook.build.configurations.ProjectConfigs +import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { id("com.android.library") - id("kotlin-android") id("com.google.devtools.ksp") id("org.jetbrains.kotlin.plugin.compose") } android { compileSdk = ProjectConfigs.compileSdkVersion - + defaultConfig { minSdk = ProjectConfigs.minSdkVersion - targetSdk = ProjectConfigs.targetSdkVersion } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = "17" - } - + buildFeatures { compose = true } } +// AGP 9.0 ships built-in Kotlin (replacing the kotlin-android plugin), so the +// JVM target is configured through the Kotlin compiler options. +kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } +} + // Namespace will be set by individual module diff --git a/components/verticalgrid/src/main/java/com/guru/composecookbook/verticalgrid/StaggeredVerticalGrid.kt b/components/verticalgrid/src/main/java/com/guru/composecookbook/verticalgrid/StaggeredVerticalGrid.kt index 4b0cda210..63fad2b85 100644 --- a/components/verticalgrid/src/main/java/com/guru/composecookbook/verticalgrid/StaggeredVerticalGrid.kt +++ b/components/verticalgrid/src/main/java/com/guru/composecookbook/verticalgrid/StaggeredVerticalGrid.kt @@ -37,14 +37,13 @@ fun StaggeredVerticalGrid( val columnWidth = constraints.maxWidth / columns val itemConstraints = constraints.copy(maxWidth = columnWidth) val colHeights = IntArray(columns) { 0 } // track each column's height - val placeables = - measurables.map { measurable -> - val column = shortestColumn(colHeights) - val placeable = measurable.measure(itemConstraints) - placeableXY[placeable] = Pair(columnWidth * column, colHeights[column]) - colHeights[column] += placeable.height - placeable - } + val placeables = measurables.map { measurable -> + val column = shortestColumn(colHeights) + val placeable = measurable.measure(itemConstraints) + placeableXY[placeable] = Pair(columnWidth * column, colHeights[column]) + colHeights[column] += placeable.height + placeable + } val height = colHeights.maxOrNull()?.coerceIn(constraints.minHeight, constraints.maxHeight) diff --git a/demos/cryptoapp/app/build.gradle.kts b/demos/cryptoapp/app/build.gradle.kts index 7d2f1282e..513527ab5 100644 --- a/demos/cryptoapp/app/build.gradle.kts +++ b/demos/cryptoapp/app/build.gradle.kts @@ -1,7 +1,6 @@ plugins { /** See [common-compose-module-configs-script-plugin.gradle.kts] file */ id("common-compose-module-configs-script-plugin") - id("org.jetbrains.kotlin.android") } android { namespace = "com.guru.composecookbook.cryptoapp" } diff --git a/demos/cryptoapp/data/src/main/java/com/guru/composecookbook/cryptoapp/data/repositories/CryptoRepositoryImpl.kt b/demos/cryptoapp/data/src/main/java/com/guru/composecookbook/cryptoapp/data/repositories/CryptoRepositoryImpl.kt index b3d8f8565..af347738c 100644 --- a/demos/cryptoapp/data/src/main/java/com/guru/composecookbook/cryptoapp/data/repositories/CryptoRepositoryImpl.kt +++ b/demos/cryptoapp/data/src/main/java/com/guru/composecookbook/cryptoapp/data/repositories/CryptoRepositoryImpl.kt @@ -18,8 +18,9 @@ class CryptoRepositoryImpl( val response = cryptoApi.getAllCrypto(page) return if (response.isSuccessful && !response.body().isNullOrEmpty()) { val cryptoApiResponseList = response.body() - val cryptoList = - cryptoApiResponseList?.map { cryptoApiResponse -> cryptoApiMapper.map(cryptoApiResponse) } + val cryptoList = cryptoApiResponseList?.map { cryptoApiResponse -> + cryptoApiMapper.map(cryptoApiResponse) + } cryptoList ?: emptyList() } else { emptyList() diff --git a/demos/datingapp/src/main/java/com/guru/composecookbook/datingapp/components/home/DatingHomeScreen.kt b/demos/datingapp/src/main/java/com/guru/composecookbook/datingapp/components/home/DatingHomeScreen.kt index 8e191c13b..da058d750 100644 --- a/demos/datingapp/src/main/java/com/guru/composecookbook/datingapp/components/home/DatingHomeScreen.kt +++ b/demos/datingapp/src/main/java/com/guru/composecookbook/datingapp/components/home/DatingHomeScreen.kt @@ -92,9 +92,7 @@ fun DatingHomeScreen() { .alpha(animateFloatAsState(if (listEmpty.value) 0f else 1f).value), ) { IconButton( - onClick = { - /* TODO Hook to swipe event */ - }, + onClick = { /* TODO Hook to swipe event */ }, modifier = Modifier.padding(horizontal = 16.dp) .size(60.dp) @@ -109,9 +107,7 @@ fun DatingHomeScreen() { ) } IconButton( - onClick = { - /* TODO Hook to swipe event */ - }, + onClick = { /* TODO Hook to swipe event */ }, modifier = Modifier.padding(horizontal = 16.dp) .size(60.dp) diff --git a/demos/gmail/src/main/java/com/guru/composecookbook/gmail/data/SampleData.kt b/demos/gmail/src/main/java/com/guru/composecookbook/gmail/data/SampleData.kt index e118c4201..f93ea7a94 100644 --- a/demos/gmail/src/main/java/com/guru/composecookbook/gmail/data/SampleData.kt +++ b/demos/gmail/src/main/java/com/guru/composecookbook/gmail/data/SampleData.kt @@ -2,119 +2,119 @@ package com.guru.composecookbook.gmail.data var sampleMessage = """ - - - - - Demystifying Email Design - - + + + + Demystifying Email Design + - - - - - + +
+ - - - - - - - - - - -
- Creating Email Magic. -
- - - - - - - - - - -
-

Lorem ipsum dolor sit amet!

-
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tempus adipiscing felis, sit amet blandit ipsum volutpat sed. Morbi porttitor, eget accumsan dictum, nisi libero ultricies ipsum, in posuere mauris neque at erat.

-
- - - - - - -
- - - - - - - -
- -
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tempus adipiscing felis, sit amet blandit ipsum volutpat sed. Morbi porttitor, eget accumsan dictum, nisi libero ultricies ipsum, in posuere mauris neque at erat.

-
-
  - - - - - - - -
- -
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tempus adipiscing felis, sit amet blandit ipsum volutpat sed. Morbi porttitor, eget accumsan dictum, nisi libero ultricies ipsum, in posuere mauris neque at erat.

-
-
-
-
- - - - - -
-

® Someone, somewhere 2025
- Unsubscribe to this newsletter instantly

-
- - - - - - -
- - Twitter. - -   - - Facebook. - -
-
-
+ + + + + - -
-
- - - - -""" + + + + + + + + + + +
+ Creating Email Magic. +
+ + + + + + + + + + +
+

Lorem ipsum dolor sit amet!

+
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tempus adipiscing felis, sit amet blandit ipsum volutpat sed. Morbi porttitor, eget accumsan dictum, nisi libero ultricies ipsum, in posuere mauris neque at erat.

+
+ + + + + + +
+ + + + + + + +
+ +
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tempus adipiscing felis, sit amet blandit ipsum volutpat sed. Morbi porttitor, eget accumsan dictum, nisi libero ultricies ipsum, in posuere mauris neque at erat.

+
+
  + + + + + + + +
+ +
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tempus adipiscing felis, sit amet blandit ipsum volutpat sed. Morbi porttitor, eget accumsan dictum, nisi libero ultricies ipsum, in posuere mauris neque at erat.

+
+
+
+
+ + + + + +
+

® Someone, somewhere 2025
+ Unsubscribe to this newsletter instantly

+
+ + + + + + +
+ + Twitter. + +   + + Facebook. + +
+
+
+ +
+ + + + + """ .trimIndent() diff --git a/demos/moviesapp/app/src/main/java/com/guru/composecookbook/moviesapp/ui/home/MoviesHomeActivity.kt b/demos/moviesapp/app/src/main/java/com/guru/composecookbook/moviesapp/ui/home/MoviesHomeActivity.kt index 93efedf02..fde70dc68 100644 --- a/demos/moviesapp/app/src/main/java/com/guru/composecookbook/moviesapp/ui/home/MoviesHomeActivity.kt +++ b/demos/moviesapp/app/src/main/java/com/guru/composecookbook/moviesapp/ui/home/MoviesHomeActivity.kt @@ -36,8 +36,7 @@ import com.guru.composecookbook.theme.ComposeCookBookTheme import com.guru.composecookbook.theme.graySurface sealed class MoviesHomeInteractionEvents { - data class OpenMovieDetail(val movie: Movie, val imageId: Int = 0) : - MoviesHomeInteractionEvents() + data class OpenMovieDetail(val movie: Movie, val imageId: Int = 0) : MoviesHomeInteractionEvents() data class AddToMyWatchlist(val movie: Movie) : MoviesHomeInteractionEvents() diff --git a/demos/moviesapp/data/src/main/java/com/guru/composecookbook/moviesapp/data/repositories/MovieRepositoryImpl.kt b/demos/moviesapp/data/src/main/java/com/guru/composecookbook/moviesapp/data/repositories/MovieRepositoryImpl.kt index 01098aa8b..4a548112e 100644 --- a/demos/moviesapp/data/src/main/java/com/guru/composecookbook/moviesapp/data/repositories/MovieRepositoryImpl.kt +++ b/demos/moviesapp/data/src/main/java/com/guru/composecookbook/moviesapp/data/repositories/MovieRepositoryImpl.kt @@ -18,29 +18,27 @@ class MovieRepositoryImpl( private val genreDao: GenreDao, ) : MovieRepository { - override suspend fun getNowShowing(): Flow> = - flow { - val response = movieApi.getMovies(1) - if (response.isSuccessful) { - emit(response.body()?.movies ?: emptyList()) - } else { - emit(emptyList()) - } - } - .catch { e -> emit(emptyList()) } - .flowOn(Dispatchers.IO) + override suspend fun getNowShowing(): Flow> = flow { + val response = movieApi.getMovies(1) + if (response.isSuccessful) { + emit(response.body()?.movies ?: emptyList()) + } else { + emit(emptyList()) + } + } + .catch { e -> emit(emptyList()) } + .flowOn(Dispatchers.IO) - override suspend fun getSimilarMovies(movieId: String): Flow> = - flow { - val response = movieApi.getSimilarMovies(movieId) - if (response.isSuccessful) { - emit(response.body()?.movies ?: emptyList()) - } else { - emit(emptyList()) - } - } - .catch { emit(emptyList()) } - .flowOn(Dispatchers.IO) + override suspend fun getSimilarMovies(movieId: String): Flow> = flow { + val response = movieApi.getSimilarMovies(movieId) + if (response.isSuccessful) { + emit(response.body()?.movies ?: emptyList()) + } else { + emit(emptyList()) + } + } + .catch { emit(emptyList()) } + .flowOn(Dispatchers.IO) override suspend fun getMyWatchlist(): LiveData> { return moviesDao.getMyWatchlist() @@ -56,19 +54,18 @@ class MovieRepositoryImpl( override suspend fun getGenres(): LiveData> = genreDao.getAllGenres() - override suspend fun fetchAndSaveGenresToDatabase(): Flow> = - flow { - val response = movieApi.getGenres() - if (response.isSuccessful) { - response.body()?.let { - if (it.genres.isNotEmpty()) { - genreDao.insertAllGenres(it.genres) - } - } - } else { - emit(emptyList()) + override suspend fun fetchAndSaveGenresToDatabase(): Flow> = flow { + val response = movieApi.getGenres() + if (response.isSuccessful) { + response.body()?.let { + if (it.genres.isNotEmpty()) { + genreDao.insertAllGenres(it.genres) } } - .catch { emit(emptyList()) } - .flowOn(Dispatchers.IO) + } else { + emit(emptyList()) + } + } + .catch { emit(emptyList()) } + .flowOn(Dispatchers.IO) } diff --git a/demos/moviesapp/data/src/main/java/com/guru/composecookbook/moviesapp/data/repositories/MoviesLaneRepositoryImpl.kt b/demos/moviesapp/data/src/main/java/com/guru/composecookbook/moviesapp/data/repositories/MoviesLaneRepositoryImpl.kt index 03d52f13b..32de9dd58 100644 --- a/demos/moviesapp/data/src/main/java/com/guru/composecookbook/moviesapp/data/repositories/MoviesLaneRepositoryImpl.kt +++ b/demos/moviesapp/data/src/main/java/com/guru/composecookbook/moviesapp/data/repositories/MoviesLaneRepositoryImpl.kt @@ -10,63 +10,58 @@ import kotlinx.coroutines.flow.flowOn class MoviesLaneRepositoryImpl(private val movieApi: MovieApi) : MoviesLanesRepository { - override suspend fun getTrendingMovies(): Flow> = - flow { - val response = movieApi.getTrendingMovies() - if (response.isSuccessful) { - emit(response.body()?.movies ?: emptyList()) - } else { - emit(emptyList()) - } - } - .catch { emit(emptyList()) } - .flowOn(Dispatchers.Default) + override suspend fun getTrendingMovies(): Flow> = flow { + val response = movieApi.getTrendingMovies() + if (response.isSuccessful) { + emit(response.body()?.movies ?: emptyList()) + } else { + emit(emptyList()) + } + } + .catch { emit(emptyList()) } + .flowOn(Dispatchers.Default) - override suspend fun getTrendingTVShows(): Flow> = - flow { - val response = movieApi.getTrendingTVShows() - if (response.isSuccessful) { - emit(response.body()?.movies ?: emptyList()) - } else { - emit(emptyList()) - } - } - .catch { emit(emptyList()) } - .flowOn(Dispatchers.Default) + override suspend fun getTrendingTVShows(): Flow> = flow { + val response = movieApi.getTrendingTVShows() + if (response.isSuccessful) { + emit(response.body()?.movies ?: emptyList()) + } else { + emit(emptyList()) + } + } + .catch { emit(emptyList()) } + .flowOn(Dispatchers.Default) - override suspend fun getPopularMovies(): Flow> = - flow { - val response = movieApi.getPopularMovies() - if (response.isSuccessful) { - emit(response.body()?.movies ?: emptyList()) - } else { - emit(emptyList()) - } - } - .catch { emit(emptyList()) } - .flowOn(Dispatchers.Default) + override suspend fun getPopularMovies(): Flow> = flow { + val response = movieApi.getPopularMovies() + if (response.isSuccessful) { + emit(response.body()?.movies ?: emptyList()) + } else { + emit(emptyList()) + } + } + .catch { emit(emptyList()) } + .flowOn(Dispatchers.Default) - override suspend fun getTopRatedMovies(): Flow> = - flow { - val response = movieApi.getTopRatedMovies() - if (response.isSuccessful) { - emit(response.body()?.movies ?: emptyList()) - } else { - emit(emptyList()) - } - } - .catch { emit(emptyList()) } - .flowOn(Dispatchers.Default) + override suspend fun getTopRatedMovies(): Flow> = flow { + val response = movieApi.getTopRatedMovies() + if (response.isSuccessful) { + emit(response.body()?.movies ?: emptyList()) + } else { + emit(emptyList()) + } + } + .catch { emit(emptyList()) } + .flowOn(Dispatchers.Default) - override suspend fun getTopRatedTVShwos(): Flow> = - flow { - val response = movieApi.getTopRatedTvShows() - if (response.isSuccessful) { - emit(response.body()?.movies ?: emptyList()) - } else { - emit(emptyList()) - } - } - .catch { emit(emptyList()) } - .flowOn(Dispatchers.Default) + override suspend fun getTopRatedTVShwos(): Flow> = flow { + val response = movieApi.getTopRatedTvShows() + if (response.isSuccessful) { + emit(response.body()?.movies ?: emptyList()) + } else { + emit(emptyList()) + } + } + .catch { emit(emptyList()) } + .flowOn(Dispatchers.Default) } diff --git a/demos/spotify/src/main/java/com/guru/composecookbook/spotify/ui/home/components/SpotifyHome.kt b/demos/spotify/src/main/java/com/guru/composecookbook/spotify/ui/home/components/SpotifyHome.kt index 5a4fa260f..11d6d5a4a 100644 --- a/demos/spotify/src/main/java/com/guru/composecookbook/spotify/ui/home/components/SpotifyHome.kt +++ b/demos/spotify/src/main/java/com/guru/composecookbook/spotify/ui/home/components/SpotifyHome.kt @@ -76,7 +76,9 @@ fun SpotifyTitle(text: String, modifier: Modifier = Modifier) { text = text, style = typography.h5.copy(fontWeight = FontWeight.ExtraBold), modifier = - modifier.padding(start = 8.dp, end = 4.dp, bottom = 8.dp, top = 24.dp).semantics { heading() }, + modifier.padding(start = 8.dp, end = 4.dp, bottom = 8.dp, top = 24.dp).semantics { + heading() + }, ) } diff --git a/demos/tiktok/src/main/java/com/guru/composecookbook/tiktok/components/home/HomeScreen.kt b/demos/tiktok/src/main/java/com/guru/composecookbook/tiktok/components/home/HomeScreen.kt index 4a125edec..198acfb05 100644 --- a/demos/tiktok/src/main/java/com/guru/composecookbook/tiktok/components/home/HomeScreen.kt +++ b/demos/tiktok/src/main/java/com/guru/composecookbook/tiktok/components/home/HomeScreen.kt @@ -210,7 +210,10 @@ fun ProfileImageWithFollow(modifier: Modifier, showFollow: Boolean, imageId: Int imageVector = Icons.Filled.Add, contentDescription = null, modifier = - Modifier.size(20.dp).clip(CircleShape).background(tiktokRed).align(Alignment.BottomCenter), + Modifier.size(20.dp) + .clip(CircleShape) + .background(tiktokRed) + .align(Alignment.BottomCenter), ) } } else { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 649ebdaf1..01fab64e3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,9 @@ [versions] -agp = "8.7.3" -kotlin = "2.1.20" -ksp = "2.1.20-1.0.31" -ktfmt = "0.22.0" -roborazzi = "1.46.1" +agp = "9.5.0" +kotlin = "2.4.21" +ksp = "2.3.13" +ktfmt = "0.27.0" +roborazzi = "1.66.0" robolectric = "4.14.1" activity-compose = "1.10.1" @@ -179,7 +179,6 @@ screenshot-test = ["roborazzi", "roborazzi-compose", "robolectric"] [plugins] android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } -kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b953..9fa7f2882 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0e5..91c4fc64a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.2-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index f3b75f3b0..249efbb03 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -29,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -205,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019c7..03754c4c3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -19,12 +19,39 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +@rem Catch executions from older scripts and ensure they exit cleanly. +@rem This can be removed once we can be reasonably confident that few people +@rem will be migrating directly to this new wrapper. +goto afterSafetyNet +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +goto exitWithErrorLevel +:afterSafetyNet set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -45,13 +72,14 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 +1>&2 echo. +1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +1>&2 echo. +1>&2 echo Please set the JAVA_HOME variable in your environment to match the +1>&2 echo location of your Java installation. -goto fail +"%COMSPEC%" /c exit 1 +goto exitWithErrorLevel :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -59,36 +87,26 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 +1>&2 echo. +1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +1>&2 echo. +1>&2 echo Please set the JAVA_HOME variable in your environment to match the +1>&2 echo location of your Java installation. -goto fail +"%COMSPEC%" /c exit 1 +goto exitWithErrorLevel :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel & goto exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem This label must not be changed. We rely on old scripts being able to jump to this point. +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/settings.gradle.kts b/settings.gradle.kts index 7aadc5f2a..703a2bf6f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,32 +1,63 @@ rootProject.name = "ComposeCookBook" + include(":app") + include(":demos:instagram") + include(":data") + include(":theme") + include(":demos:cryptoapp:app") + include(":demos:cryptoapp:data") + include(":demos:moviesapp:app") + include(":demos:moviesapp:data") + include(":components:charts") + include(":components:tags") + include(":components:carousel") + include(":components:verticalgrid") + include(":demos:spotify") + include(":demos:twitter") + include(":demos:youtube") + include(":demos:gmail") + include(":components:fab") + include(":demos:paint") + include(":components:colorpicker") + include(":demos:tiktok") + include(":demos:datingapp") + include(":animations:lottie") + include(":animations:canvas") + include(":components:comingsoon") + include(":templates:onboarding") + include(":templates:paymentcard") + include(":templates:profile") + include(":templates:login") + include(":templates:pinlock") + include(":templates:cascademenu") + include(":demos:meditation")