Introduce SealedX KSP library

pull/222/head
skydoves 3 years ago
parent e0687e9aae
commit fd95532270
No known key found for this signature in database
GPG Key ID: D7662013FA1A5596

@ -20,6 +20,13 @@ plugins {
id("kotlinx-serialization") id("kotlinx-serialization")
id("dagger.hilt.android.plugin") id("dagger.hilt.android.plugin")
id("nowinandroid.spotless") id("nowinandroid.spotless")
alias(libs.plugins.ksp)
}
kotlin {
sourceSets.configureEach {
kotlin.srcDir("$buildDir/generated/ksp/$name/kotlin/")
}
} }
dependencies { dependencies {
@ -38,4 +45,7 @@ dependencies {
implementation(libs.hilt.android) implementation(libs.hilt.android)
kapt(libs.hilt.compiler) kapt(libs.hilt.compiler)
implementation(libs.sealedx.core)
ksp(libs.sealedx.processor)
} }

@ -0,0 +1,39 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.data.model
import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceExtensive
import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResourceExtensive
import com.skydoves.sealedx.core.Extensive
import com.skydoves.sealedx.core.annotations.ExtensiveModel
import com.skydoves.sealedx.core.annotations.ExtensiveSealed
@ExtensiveSealed(
models = [
ExtensiveModel(type = FollowableTopic::class, name = "Topic"),
ExtensiveModel(type = FollowableAuthor::class, name = "Author"),
ExtensiveModel(type = SaveableNewsResourceExtensive::class, name = "SaveableNews"),
ExtensiveModel(type = NewsResourceExtensive::class, name = "News"),
]
)
sealed interface UiState {
data class Success(val data: Extensive) : UiState
object Error : UiState
object Loading : UiState
}

@ -41,6 +41,14 @@ data class NewsResource(
val topics: List<Topic> val topics: List<Topic>
) )
data class NewsResourceExtensive(
val newsResources: List<NewsResource>
)
fun List<NewsResource>.toExtensive(): NewsResourceExtensive {
return NewsResourceExtensive(this)
}
val previewNewsResources = listOf( val previewNewsResources = listOf(
NewsResource( NewsResource(
id = "1", id = "1",

@ -23,3 +23,11 @@ data class SaveableNewsResource(
val newsResource: NewsResource, val newsResource: NewsResource,
val isSaved: Boolean, val isSaved: Boolean,
) )
data class SaveableNewsResourceExtensive(
val newsResources: List<SaveableNewsResource>
)
fun List<SaveableNewsResource>.toExtensive(): SaveableNewsResourceExtensive {
return SaveableNewsResourceExtensive(this)
}

@ -50,6 +50,8 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.google.samples.apps.nowinandroid.core.data.model.AuthorUiState
import com.google.samples.apps.nowinandroid.core.data.model.SaveableNewsUiState
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilterChip import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilterChip
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaLoadingWheel import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaLoadingWheel
@ -59,6 +61,7 @@ import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResource import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResource
import com.google.samples.apps.nowinandroid.core.model.data.previewAuthors import com.google.samples.apps.nowinandroid.core.model.data.previewAuthors
import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources
import com.google.samples.apps.nowinandroid.core.model.data.toExtensive
import com.google.samples.apps.nowinandroid.core.ui.newsResourceCardItems import com.google.samples.apps.nowinandroid.core.ui.newsResourceCardItems
@OptIn(ExperimentalLifecycleComposeApi::class) @OptIn(ExperimentalLifecycleComposeApi::class)
@ -69,7 +72,7 @@ fun AuthorRoute(
viewModel: AuthorViewModel = hiltViewModel(), viewModel: AuthorViewModel = hiltViewModel(),
) { ) {
val authorUiState: AuthorUiState by viewModel.authorUiState.collectAsStateWithLifecycle() val authorUiState: AuthorUiState by viewModel.authorUiState.collectAsStateWithLifecycle()
val newsUiState: NewsUiState by viewModel.newUiState.collectAsStateWithLifecycle() val newsUiState: SaveableNewsUiState by viewModel.newUiState.collectAsStateWithLifecycle()
AuthorScreen( AuthorScreen(
authorUiState = authorUiState, authorUiState = authorUiState,
@ -85,7 +88,7 @@ fun AuthorRoute(
@Composable @Composable
internal fun AuthorScreen( internal fun AuthorScreen(
authorUiState: AuthorUiState, authorUiState: AuthorUiState,
newsUiState: NewsUiState, newsUiState: SaveableNewsUiState,
onBackClick: () -> Unit, onBackClick: () -> Unit,
onFollowClick: (Boolean) -> Unit, onFollowClick: (Boolean) -> Unit,
onBookmarkChanged: (String, Boolean) -> Unit, onBookmarkChanged: (String, Boolean) -> Unit,
@ -115,11 +118,11 @@ internal fun AuthorScreen(
AuthorToolbar( AuthorToolbar(
onBackClick = onBackClick, onBackClick = onBackClick,
onFollowClick = onFollowClick, onFollowClick = onFollowClick,
uiState = authorUiState.followableAuthor, uiState = authorUiState.data,
) )
} }
authorBody( authorBody(
author = authorUiState.followableAuthor.author, author = authorUiState.data.author,
news = newsUiState, news = newsUiState,
onBookmarkChanged = onBookmarkChanged, onBookmarkChanged = onBookmarkChanged,
) )
@ -133,7 +136,7 @@ internal fun AuthorScreen(
private fun LazyListScope.authorBody( private fun LazyListScope.authorBody(
author: Author, author: Author,
news: NewsUiState, news: SaveableNewsUiState,
onBookmarkChanged: (String, Boolean) -> Unit onBookmarkChanged: (String, Boolean) -> Unit
) { ) {
item { item {
@ -170,20 +173,20 @@ private fun AuthorHeader(author: Author) {
} }
private fun LazyListScope.authorCards( private fun LazyListScope.authorCards(
news: NewsUiState, news: SaveableNewsUiState,
onBookmarkChanged: (String, Boolean) -> Unit onBookmarkChanged: (String, Boolean) -> Unit
) { ) {
when (news) { when (news) {
is NewsUiState.Success -> { is SaveableNewsUiState.Success -> {
newsResourceCardItems( newsResourceCardItems(
items = news.news, items = news.data.newsResources,
newsResourceMapper = { it.newsResource }, newsResourceMapper = { it.newsResource },
isBookmarkedMapper = { it.isSaved }, isBookmarkedMapper = { it.isSaved },
onToggleBookmark = { onBookmarkChanged(it.newsResource.id, !it.isSaved) }, onToggleBookmark = { onBookmarkChanged(it.newsResource.id, !it.isSaved) },
itemModifier = Modifier.padding(24.dp) itemModifier = Modifier.padding(24.dp)
) )
} }
is NewsUiState.Loading -> item { is SaveableNewsUiState.Loading -> item {
NiaLoadingWheel(contentDesc = "Loading news") // TODO NiaLoadingWheel(contentDesc = "Loading news") // TODO
} }
else -> item { else -> item {
@ -237,13 +240,13 @@ fun AuthorScreenPopulated() {
NiaBackground { NiaBackground {
AuthorScreen( AuthorScreen(
authorUiState = AuthorUiState.Success(FollowableAuthor(previewAuthors[0], false)), authorUiState = AuthorUiState.Success(FollowableAuthor(previewAuthors[0], false)),
newsUiState = NewsUiState.Success( newsUiState = SaveableNewsUiState.Success(
previewNewsResources.mapIndexed { index, newsResource -> previewNewsResources.mapIndexed { index, newsResource ->
SaveableNewsResource( SaveableNewsResource(
newsResource = newsResource, newsResource = newsResource,
isSaved = index % 2 == 0, isSaved = index % 2 == 0,
) )
} }.toExtensive()
), ),
onBackClick = {}, onBackClick = {},
onFollowClick = {}, onFollowClick = {},
@ -263,7 +266,7 @@ fun AuthorScreenLoading() {
NiaBackground { NiaBackground {
AuthorScreen( AuthorScreen(
authorUiState = AuthorUiState.Loading, authorUiState = AuthorUiState.Loading,
newsUiState = NewsUiState.Loading, newsUiState = SaveableNewsUiState.Loading,
onBackClick = {}, onBackClick = {},
onFollowClick = {}, onFollowClick = {},
onBookmarkChanged = { _, _ -> }, onBookmarkChanged = { _, _ -> },

@ -19,6 +19,8 @@ package com.google.samples.apps.nowinandroid.feature.author
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.samples.apps.nowinandroid.core.data.model.AuthorUiState
import com.google.samples.apps.nowinandroid.core.data.model.SaveableNewsUiState
import com.google.samples.apps.nowinandroid.core.data.repository.AuthorsRepository import com.google.samples.apps.nowinandroid.core.data.repository.AuthorsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.NewsRepository import com.google.samples.apps.nowinandroid.core.data.repository.NewsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
@ -26,6 +28,7 @@ import com.google.samples.apps.nowinandroid.core.model.data.Author
import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResource import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResource
import com.google.samples.apps.nowinandroid.core.model.data.toExtensive
import com.google.samples.apps.nowinandroid.core.result.Result import com.google.samples.apps.nowinandroid.core.result.Result
import com.google.samples.apps.nowinandroid.core.result.asResult import com.google.samples.apps.nowinandroid.core.result.asResult
import com.google.samples.apps.nowinandroid.feature.author.navigation.AuthorDestination import com.google.samples.apps.nowinandroid.feature.author.navigation.AuthorDestination
@ -62,7 +65,7 @@ class AuthorViewModel @Inject constructor(
initialValue = AuthorUiState.Loading initialValue = AuthorUiState.Loading
) )
val newUiState: StateFlow<NewsUiState> = newsUiStateStream( val newUiState: StateFlow<SaveableNewsUiState> = newsUiStateStream(
authorId = authorId, authorId = authorId,
userDataRepository = userDataRepository, userDataRepository = userDataRepository,
newsRepository = newsRepository newsRepository = newsRepository
@ -70,7 +73,7 @@ class AuthorViewModel @Inject constructor(
.stateIn( .stateIn(
scope = viewModelScope, scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000), started = SharingStarted.WhileSubscribed(5_000),
initialValue = NewsUiState.Loading initialValue = SaveableNewsUiState.Loading
) )
fun followAuthorToggle(followed: Boolean) { fun followAuthorToggle(followed: Boolean) {
@ -113,7 +116,7 @@ private fun authorUiStateStream(
val (followedAuthors, author) = followedAuthorToAuthorResult.data val (followedAuthors, author) = followedAuthorToAuthorResult.data
val followed = followedAuthors.contains(authorId) val followed = followedAuthors.contains(authorId)
AuthorUiState.Success( AuthorUiState.Success(
followableAuthor = FollowableAuthor( data = FollowableAuthor(
author = author, author = author,
isFollowed = followed isFollowed = followed
) )
@ -133,7 +136,7 @@ private fun newsUiStateStream(
authorId: String, authorId: String,
newsRepository: NewsRepository, newsRepository: NewsRepository,
userDataRepository: UserDataRepository, userDataRepository: UserDataRepository,
): Flow<NewsUiState> { ): Flow<SaveableNewsUiState> {
// Observe news // Observe news
val newsStream: Flow<List<NewsResource>> = newsRepository.getNewsResourcesStream( val newsStream: Flow<List<NewsResource>> = newsRepository.getNewsResourcesStream(
filterAuthorIds = setOf(element = authorId), filterAuthorIds = setOf(element = authorId),
@ -154,33 +157,21 @@ private fun newsUiStateStream(
when (newsToBookmarksResult) { when (newsToBookmarksResult) {
is Result.Success -> { is Result.Success -> {
val (news, bookmarks) = newsToBookmarksResult.data val (news, bookmarks) = newsToBookmarksResult.data
NewsUiState.Success( SaveableNewsUiState.Success(
news.map { newsResource -> news.map { newsResource ->
SaveableNewsResource( SaveableNewsResource(
newsResource, newsResource,
isSaved = bookmarks.contains(newsResource.id) isSaved = bookmarks.contains(newsResource.id)
) )
} }.toExtensive()
) )
} }
is Result.Loading -> { is Result.Loading -> {
NewsUiState.Loading SaveableNewsUiState.Loading
} }
is Result.Error -> { is Result.Error -> {
NewsUiState.Error SaveableNewsUiState.Error
} }
} }
} }
} }
sealed interface AuthorUiState {
data class Success(val followableAuthor: FollowableAuthor) : AuthorUiState
object Error : AuthorUiState
object Loading : AuthorUiState
}
sealed interface NewsUiState {
data class Success(val news: List<SaveableNewsResource>) : NewsUiState
object Error : NewsUiState
object Loading : NewsUiState
}

@ -47,16 +47,19 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.google.samples.apps.nowinandroid.core.data.model.NewsUiState
import com.google.samples.apps.nowinandroid.core.data.model.TopicUiState
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilterChip import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilterChip
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaLoadingWheel import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaLoadingWheel
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceExtensive
import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources
import com.google.samples.apps.nowinandroid.core.model.data.previewTopics import com.google.samples.apps.nowinandroid.core.model.data.previewTopics
import com.google.samples.apps.nowinandroid.core.model.data.toExtensive
import com.google.samples.apps.nowinandroid.core.ui.newsResourceCardItems import com.google.samples.apps.nowinandroid.core.ui.newsResourceCardItems
import com.google.samples.apps.nowinandroid.feature.topic.R.string import com.google.samples.apps.nowinandroid.feature.topic.R.string
import com.google.samples.apps.nowinandroid.feature.topic.TopicUiState.Loading
@OptIn(ExperimentalLifecycleComposeApi::class) @OptIn(ExperimentalLifecycleComposeApi::class)
@Composable @Composable
@ -93,7 +96,7 @@ internal fun TopicScreen(
Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing)) Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing))
} }
when (topicState) { when (topicState) {
Loading -> item { TopicUiState.Loading -> item {
NiaLoadingWheel( NiaLoadingWheel(
modifier = modifier, modifier = modifier,
contentDesc = stringResource(id = string.topic_loading), contentDesc = stringResource(id = string.topic_loading),
@ -105,14 +108,14 @@ internal fun TopicScreen(
TopicToolbar( TopicToolbar(
onBackClick = onBackClick, onBackClick = onBackClick,
onFollowClick = onFollowClick, onFollowClick = onFollowClick,
uiState = topicState.followableTopic, uiState = topicState.data,
) )
} }
TopicBody( TopicBody(
name = topicState.followableTopic.topic.name, name = topicState.data.topic.name,
description = topicState.followableTopic.topic.longDescription, description = topicState.data.topic.longDescription,
news = newsState, news = newsState,
imageUrl = topicState.followableTopic.topic.imageUrl imageUrl = topicState.data.topic.imageUrl
) )
} }
} }
@ -164,7 +167,7 @@ private fun LazyListScope.TopicCards(news: NewsUiState) {
when (news) { when (news) {
is NewsUiState.Success -> { is NewsUiState.Success -> {
newsResourceCardItems( newsResourceCardItems(
items = news.news, items = news.data.newsResources,
newsResourceMapper = { it }, newsResourceMapper = { it },
isBookmarkedMapper = { /* TODO */ false }, isBookmarkedMapper = { /* TODO */ false },
onToggleBookmark = { /* TODO */ }, onToggleBookmark = { /* TODO */ },
@ -187,7 +190,7 @@ private fun TopicBodyPreview() {
LazyColumn { LazyColumn {
TopicBody( TopicBody(
"Jetpack Compose", "Lorem ipsum maximum", "Jetpack Compose", "Lorem ipsum maximum",
NewsUiState.Success(emptyList()), "" NewsUiState.Success(NewsResourceExtensive(emptyList())), ""
) )
} }
} }
@ -238,7 +241,7 @@ fun TopicScreenPopulated() {
NiaBackground { NiaBackground {
TopicScreen( TopicScreen(
topicState = TopicUiState.Success(FollowableTopic(previewTopics[0], false)), topicState = TopicUiState.Success(FollowableTopic(previewTopics[0], false)),
newsState = NewsUiState.Success(previewNewsResources), newsState = NewsUiState.Success(previewNewsResources.toExtensive()),
onBackClick = {}, onBackClick = {},
onFollowClick = {} onFollowClick = {}
) )

@ -19,12 +19,15 @@ package com.google.samples.apps.nowinandroid.feature.topic
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.samples.apps.nowinandroid.core.data.model.NewsUiState
import com.google.samples.apps.nowinandroid.core.data.model.TopicUiState
import com.google.samples.apps.nowinandroid.core.data.repository.NewsRepository import com.google.samples.apps.nowinandroid.core.data.repository.NewsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.model.data.toExtensive
import com.google.samples.apps.nowinandroid.core.result.Result import com.google.samples.apps.nowinandroid.core.result.Result
import com.google.samples.apps.nowinandroid.core.result.asResult import com.google.samples.apps.nowinandroid.core.result.asResult
import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicDestination import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicDestination
@ -73,7 +76,7 @@ class TopicViewModel @Inject constructor(
if (topicResult is Result.Success && followedTopicsResult is Result.Success) { if (topicResult is Result.Success && followedTopicsResult is Result.Success) {
val followed = followedTopicsResult.data.contains(topicId) val followed = followedTopicsResult.data.contains(topicId)
TopicUiState.Success( TopicUiState.Success(
followableTopic = FollowableTopic( data = FollowableTopic(
topic = topicResult.data, topic = topicResult.data,
isFollowed = followed isFollowed = followed
) )
@ -87,7 +90,7 @@ class TopicViewModel @Inject constructor(
} }
val news: NewsUiState = when (newsResult) { val news: NewsUiState = when (newsResult) {
is Result.Success -> NewsUiState.Success(newsResult.data) is Result.Success -> NewsUiState.Success(newsResult.data.toExtensive())
is Result.Loading -> NewsUiState.Loading is Result.Loading -> NewsUiState.Loading
is Result.Error -> NewsUiState.Error is Result.Error -> NewsUiState.Error
} }
@ -107,18 +110,6 @@ class TopicViewModel @Inject constructor(
} }
} }
sealed interface TopicUiState {
data class Success(val followableTopic: FollowableTopic) : TopicUiState
object Error : TopicUiState
object Loading : TopicUiState
}
sealed interface NewsUiState {
data class Success(val news: List<NewsResource>) : NewsUiState
object Error : NewsUiState
object Loading : NewsUiState
}
data class TopicScreenUiState( data class TopicScreenUiState(
val topicState: TopicUiState, val topicState: TopicUiState,
val newsState: NewsUiState val newsState: NewsUiState

@ -36,6 +36,7 @@ kotlinxCoroutines = "1.6.3"
kotlinxDatetime = "0.3.3" kotlinxDatetime = "0.3.3"
kotlinxSerializationJson = "1.3.3" kotlinxSerializationJson = "1.3.3"
ksp = "1.7.0-1.0.6" ksp = "1.7.0-1.0.6"
sealedx = "1.0.0"
ktlint = "0.43.0" ktlint = "0.43.0"
lint = "30.2.1" lint = "30.2.1"
okhttp = "4.10.0" okhttp = "4.10.0"
@ -120,6 +121,8 @@ room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
secrets-gradlePlugin = { group = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", name = "secrets-gradle-plugin", version.ref = "secrets" } secrets-gradlePlugin = { group = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", name = "secrets-gradle-plugin", version.ref = "secrets" }
spotless-gradlePlugin = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version.ref = "spotless" } spotless-gradlePlugin = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version.ref = "spotless" }
sealedx-core = { group = "com.github.skydoves", name = "sealedx-core", version.ref = "sealedx" }
sealedx-processor = { group = "com.github.skydoves", name = "sealedx-processor", version.ref = "sealedx" }
[plugins] [plugins]
protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" }

Loading…
Cancel
Save