commit
7ca17f68ed
@ -0,0 +1,3 @@
|
||||
# :app-nia-catalog module
|
||||
|
||||
![Dependency graph](../docs/images/graphs/dep_graph_app_nia_catalog.png)
|
@ -0,0 +1,3 @@
|
||||
# :app module
|
||||
|
||||
![Dependency graph](../docs/images/graphs/dep_graph_app.png)
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.android.build.api.variant.LibraryAndroidComponentsExtension
|
||||
import com.google.samples.apps.nowinandroid.configureJacoco
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.VersionCatalogsExtension
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
import org.gradle.kotlin.dsl.kotlin
|
||||
|
||||
class AndroidHiltConventionPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
with(pluginManager) {
|
||||
apply("org.jetbrains.kotlin.kapt")
|
||||
apply("dagger.hilt.android.plugin")
|
||||
}
|
||||
|
||||
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
dependencies {
|
||||
"implementation"(libs.findLibrary("hilt.android").get())
|
||||
"kapt"(libs.findLibrary("hilt.compiler").get())
|
||||
"kaptAndroidTest"(libs.findLibrary("hilt.compiler").get())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.diffplug.gradle.spotless.SpotlessExtension
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.VersionCatalogsExtension
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
|
||||
class SpotlessConventionPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("com.diffplug.spotless")
|
||||
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
|
||||
extensions.configure<SpotlessExtension> {
|
||||
kotlin {
|
||||
target("**/*.kt")
|
||||
targetExclude("**/build/**/*.kt")
|
||||
ktlint(libs.findVersion("ktlint").get().toString()).userData(mapOf("android" to "true"))
|
||||
licenseHeaderFile(rootProject.file("spotless/copyright.kt"))
|
||||
}
|
||||
format("kts") {
|
||||
target("**/*.kts")
|
||||
targetExclude("**/build/**/*.kts")
|
||||
// Look for the first line that doesn't have a block comment (assumed to be the license)
|
||||
licenseHeaderFile(rootProject.file("spotless/copyright.kts"), "(^(?![\\/ ]\\*).*$)")
|
||||
}
|
||||
format("xml") {
|
||||
target("**/*.xml")
|
||||
targetExclude("**/build/**/*.xml")
|
||||
// Look for the first XML tag that isn't a comment (<!--) or the xml declaration (<?xml)
|
||||
licenseHeaderFile(rootProject.file("spotless/copyright.xml"), "(<[^!?])")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.android.build.api.artifact.SingleArtifact
|
||||
import com.android.build.api.variant.AndroidComponentsExtension
|
||||
import com.android.build.api.variant.BuiltArtifactsLoader
|
||||
import com.android.build.api.variant.HasAndroidTest
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import java.io.File
|
||||
|
||||
internal fun Project.configurePrintApksTask(extension: AndroidComponentsExtension<*, *, *>) {
|
||||
extension.onVariants { variant ->
|
||||
if (variant is HasAndroidTest) {
|
||||
val loader = variant.artifacts.getBuiltArtifactsLoader()
|
||||
val artifact = variant.androidTest?.artifacts?.get(SingleArtifact.APK)
|
||||
val javaSources = variant.androidTest?.sources?.java?.all
|
||||
val kotlinSources = variant.androidTest?.sources?.kotlin?.all
|
||||
|
||||
val testSources = if (javaSources != null && kotlinSources != null) {
|
||||
javaSources.zip(kotlinSources) { javaDirs, kotlinDirs ->
|
||||
javaDirs + kotlinDirs
|
||||
}
|
||||
} else javaSources ?: kotlinSources
|
||||
|
||||
if (artifact != null && testSources != null) {
|
||||
tasks.register(
|
||||
"${variant.name}PrintTestApk",
|
||||
PrintApkLocationTask::class.java
|
||||
) {
|
||||
apkFolder.set(artifact)
|
||||
builtArtifactsLoader.set(loader)
|
||||
variantName.set(variant.name)
|
||||
sources.set(testSources)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class PrintApkLocationTask : DefaultTask() {
|
||||
@get:InputDirectory
|
||||
abstract val apkFolder: DirectoryProperty
|
||||
|
||||
@get:InputFiles
|
||||
abstract val sources: ListProperty<Directory>
|
||||
|
||||
@get:Internal
|
||||
abstract val builtArtifactsLoader: Property<BuiltArtifactsLoader>
|
||||
|
||||
@get:Input
|
||||
abstract val variantName: Property<String>
|
||||
|
||||
@TaskAction
|
||||
fun taskAction() {
|
||||
val hasFiles = sources.orNull?.any { directory ->
|
||||
directory.asFileTree.files.any {
|
||||
it.isFile && it.parentFile.path.contains("build${File.separator}generated").not()
|
||||
}
|
||||
} ?: throw RuntimeException("Cannot check androidTest sources")
|
||||
|
||||
// Don't print APK location if there are no androidTest source files
|
||||
if (!hasFiles) {
|
||||
return
|
||||
}
|
||||
|
||||
val builtArtifacts = builtArtifactsLoader.get().load(apkFolder.get())
|
||||
?: throw RuntimeException("Cannot load APKs")
|
||||
if (builtArtifacts.elements.size != 1)
|
||||
throw RuntimeException("Expected one APK !")
|
||||
val apk = File(builtArtifacts.elements.single().outputFile).toPath()
|
||||
println(apk)
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
# :core:common module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_common.png)
|
@ -0,0 +1,3 @@
|
||||
# :core:data-test module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_data_test.png)
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
class AlwaysOnlineNetworkMonitor @Inject constructor() : NetworkMonitor {
|
||||
override val isOnline: Flow<Boolean> = flowOf(true)
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
# :core:data module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_data.png)
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.database.model.EpisodeEntity
|
||||
import com.google.samples.apps.nowinandroid.core.network.model.NetworkEpisode
|
||||
import com.google.samples.apps.nowinandroid.core.network.model.NetworkEpisodeExpanded
|
||||
|
||||
fun NetworkEpisode.asEntity() = EpisodeEntity(
|
||||
id = id,
|
||||
name = name,
|
||||
publishDate = publishDate,
|
||||
alternateVideo = alternateVideo,
|
||||
alternateAudio = alternateAudio,
|
||||
)
|
||||
|
||||
fun NetworkEpisodeExpanded.asEntity() = EpisodeEntity(
|
||||
id = id,
|
||||
name = name,
|
||||
publishDate = publishDate,
|
||||
alternateVideo = alternateVideo,
|
||||
alternateAudio = alternateAudio,
|
||||
)
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.ConnectivityManager.NetworkCallback
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest.Builder
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Build.VERSION_CODES
|
||||
import androidx.core.content.getSystemService
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
|
||||
class ConnectivityManagerNetworkMonitor @Inject constructor(
|
||||
@ApplicationContext private val context: Context
|
||||
) : NetworkMonitor {
|
||||
override val isOnline: Flow<Boolean> = callbackFlow<Boolean> {
|
||||
val callback = object : NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
channel.trySend(true)
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
channel.trySend(false)
|
||||
}
|
||||
}
|
||||
|
||||
val connectivityManager = context.getSystemService<ConnectivityManager>()
|
||||
|
||||
connectivityManager?.registerNetworkCallback(
|
||||
Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.build(),
|
||||
callback
|
||||
)
|
||||
|
||||
channel.trySend(connectivityManager.isCurrentlyConnected())
|
||||
|
||||
awaitClose {
|
||||
connectivityManager?.unregisterNetworkCallback(callback)
|
||||
}
|
||||
}
|
||||
.conflate()
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun ConnectivityManager?.isCurrentlyConnected() = when (this) {
|
||||
null -> false
|
||||
else -> when {
|
||||
VERSION.SDK_INT >= VERSION_CODES.M ->
|
||||
activeNetwork
|
||||
?.let(::getNetworkCapabilities)
|
||||
?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
?: false
|
||||
else -> activeNetworkInfo?.isConnected ?: false
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Reports on if synchronization is in progress
|
||||
*/
|
||||
interface SyncStatusMonitor {
|
||||
val isSyncing: Flow<Boolean>
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.testdoubles
|
||||
|
||||
import com.google.samples.apps.nowinandroid.core.database.dao.EpisodeDao
|
||||
import com.google.samples.apps.nowinandroid.core.database.model.EpisodeEntity
|
||||
import com.google.samples.apps.nowinandroid.core.database.model.PopulatedEpisode
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.datetime.Instant
|
||||
|
||||
/**
|
||||
* Test double for [EpisodeDao]
|
||||
*/
|
||||
class TestEpisodeDao : EpisodeDao {
|
||||
|
||||
private var entitiesStateFlow = MutableStateFlow(
|
||||
listOf(
|
||||
EpisodeEntity(
|
||||
id = "1",
|
||||
name = "Episode",
|
||||
publishDate = Instant.fromEpochMilliseconds(0),
|
||||
alternateVideo = null,
|
||||
alternateAudio = null,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
override fun getEpisodesStream(): Flow<List<PopulatedEpisode>> =
|
||||
entitiesStateFlow.map {
|
||||
it.map(EpisodeEntity::asPopulatedEpisode)
|
||||
}
|
||||
|
||||
override suspend fun insertOrIgnoreEpisodes(episodeEntities: List<EpisodeEntity>): List<Long> {
|
||||
entitiesStateFlow.value = episodeEntities
|
||||
// Assume no conflicts on insert
|
||||
return episodeEntities.map { it.id.toLong() }
|
||||
}
|
||||
|
||||
override suspend fun updateEpisodes(entities: List<EpisodeEntity>) {
|
||||
throw NotImplementedError("Unused in tests")
|
||||
}
|
||||
|
||||
override suspend fun deleteEpisodes(ids: List<String>) {
|
||||
val idSet = ids.toSet()
|
||||
entitiesStateFlow.update { entities ->
|
||||
entities.filterNot { idSet.contains(it.id) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun EpisodeEntity.asPopulatedEpisode() = PopulatedEpisode(
|
||||
entity = this,
|
||||
newsResources = emptyList(),
|
||||
authors = emptyList(),
|
||||
)
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* 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.database.model
|
||||
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.Author
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.Episode
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video
|
||||
import kotlinx.datetime.Instant
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class PopulatedEpisodeKtTest {
|
||||
@Test
|
||||
fun populated_episode_can_be_mapped_to_episode() {
|
||||
val populatedEpisode = PopulatedEpisode(
|
||||
entity = EpisodeEntity(
|
||||
id = "0",
|
||||
name = "Test",
|
||||
publishDate = Instant.fromEpochMilliseconds(1),
|
||||
alternateAudio = "audio",
|
||||
alternateVideo = "video"
|
||||
),
|
||||
newsResources = listOf(
|
||||
NewsResourceEntity(
|
||||
id = "1",
|
||||
episodeId = "0",
|
||||
title = "news",
|
||||
content = "Hilt",
|
||||
url = "url",
|
||||
headerImageUrl = "headerImageUrl",
|
||||
type = Video,
|
||||
publishDate = Instant.fromEpochMilliseconds(1),
|
||||
)
|
||||
),
|
||||
authors = listOf(
|
||||
AuthorEntity(
|
||||
id = "2",
|
||||
name = "name",
|
||||
imageUrl = "imageUrl",
|
||||
twitter = "twitter",
|
||||
mediumPage = "mediumPage",
|
||||
bio = "bio",
|
||||
)
|
||||
),
|
||||
)
|
||||
val episode = populatedEpisode.asExternalModel()
|
||||
|
||||
assertEquals(
|
||||
Episode(
|
||||
id = "0",
|
||||
name = "Test",
|
||||
publishDate = Instant.fromEpochMilliseconds(1),
|
||||
alternateAudio = "audio",
|
||||
alternateVideo = "video",
|
||||
newsResources = listOf(
|
||||
NewsResource(
|
||||
id = "1",
|
||||
episodeId = "0",
|
||||
title = "news",
|
||||
content = "Hilt",
|
||||
url = "url",
|
||||
headerImageUrl = "headerImageUrl",
|
||||
type = Video,
|
||||
publishDate = Instant.fromEpochMilliseconds(1),
|
||||
authors = listOf(),
|
||||
topics = listOf()
|
||||
)
|
||||
),
|
||||
authors = listOf(
|
||||
Author(
|
||||
id = "2",
|
||||
name = "name",
|
||||
imageUrl = "imageUrl",
|
||||
twitter = "twitter",
|
||||
mediumPage = "mediumPage",
|
||||
bio = "bio",
|
||||
)
|
||||
),
|
||||
),
|
||||
episode
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
# :core:database module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_database.png)
|
@ -0,0 +1,314 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 11,
|
||||
"identityHash": "2f83f889f6d8a96243f4ce387adbc604",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "authors",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `image_url` TEXT NOT NULL, `twitter` TEXT NOT NULL DEFAULT '', `medium_page` TEXT NOT NULL DEFAULT '', `bio` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "imageUrl",
|
||||
"columnName": "image_url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "twitter",
|
||||
"columnName": "twitter",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "mediumPage",
|
||||
"columnName": "medium_page",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "bio",
|
||||
"columnName": "bio",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "news_resources_authors",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`news_resource_id` TEXT NOT NULL, `author_id` TEXT NOT NULL, PRIMARY KEY(`news_resource_id`, `author_id`), FOREIGN KEY(`news_resource_id`) REFERENCES `news_resources`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`author_id`) REFERENCES `authors`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "newsResourceId",
|
||||
"columnName": "news_resource_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "authorId",
|
||||
"columnName": "author_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"news_resource_id",
|
||||
"author_id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_news_resources_authors_news_resource_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"news_resource_id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_news_resources_authors_news_resource_id` ON `${TABLE_NAME}` (`news_resource_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_news_resources_authors_author_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"author_id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_news_resources_authors_author_id` ON `${TABLE_NAME}` (`author_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "news_resources",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"news_resource_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "authors",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"author_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "news_resources",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `url` TEXT NOT NULL, `header_image_url` TEXT, `publish_date` INTEGER NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "headerImageUrl",
|
||||
"columnName": "header_image_url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "publishDate",
|
||||
"columnName": "publish_date",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "news_resources_topics",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`news_resource_id` TEXT NOT NULL, `topic_id` TEXT NOT NULL, PRIMARY KEY(`news_resource_id`, `topic_id`), FOREIGN KEY(`news_resource_id`) REFERENCES `news_resources`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`topic_id`) REFERENCES `topics`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "newsResourceId",
|
||||
"columnName": "news_resource_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "topicId",
|
||||
"columnName": "topic_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"news_resource_id",
|
||||
"topic_id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_news_resources_topics_news_resource_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"news_resource_id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_news_resources_topics_news_resource_id` ON `${TABLE_NAME}` (`news_resource_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_news_resources_topics_topic_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"topic_id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_news_resources_topics_topic_id` ON `${TABLE_NAME}` (`topic_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "news_resources",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"news_resource_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "topics",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"topic_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "topics",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `shortDescription` TEXT NOT NULL, `longDescription` TEXT NOT NULL DEFAULT '', `url` TEXT NOT NULL DEFAULT '', `imageUrl` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "shortDescription",
|
||||
"columnName": "shortDescription",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "longDescription",
|
||||
"columnName": "longDescription",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "imageUrl",
|
||||
"columnName": "imageUrl",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2f83f889f6d8a96243f4ce387adbc604')"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.database.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import com.google.samples.apps.nowinandroid.core.database.model.EpisodeEntity
|
||||
import com.google.samples.apps.nowinandroid.core.database.model.PopulatedEpisode
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.Episode
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* DAO for [EpisodeEntity] and [Episode] access
|
||||
*/
|
||||
@Dao
|
||||
interface EpisodeDao {
|
||||
@Transaction
|
||||
@Query(value = "SELECT * FROM episodes")
|
||||
fun getEpisodesStream(): Flow<List<PopulatedEpisode>>
|
||||
|
||||
/**
|
||||
* Inserts [episodeEntities] into the db if they don't exist, and ignores those that do
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insertOrIgnoreEpisodes(episodeEntities: List<EpisodeEntity>): List<Long>
|
||||
|
||||
/**
|
||||
* Updates [entities] in the db that match the primary key, and no-ops if they don't
|
||||
*/
|
||||
@Update
|
||||
suspend fun updateEpisodes(entities: List<EpisodeEntity>)
|
||||
|
||||
/**
|
||||
* Inserts or updates [entities] in the db under the specified primary keys
|
||||
*/
|
||||
@Transaction
|
||||
suspend fun upsertEpisodes(entities: List<EpisodeEntity>) = upsert(
|
||||
items = entities,
|
||||
insertMany = ::insertOrIgnoreEpisodes,
|
||||
updateMany = ::updateEpisodes
|
||||
)
|
||||
|
||||
/**
|
||||
* Deletes rows in the db matching the specified [ids]
|
||||
*/
|
||||
@Query(
|
||||
value = """
|
||||
DELETE FROM episodes
|
||||
WHERE id in (:ids)
|
||||
"""
|
||||
)
|
||||
suspend fun deleteEpisodes(ids: List<String>)
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.database.dao
|
||||
|
||||
/**
|
||||
* Performs an upsert by first attempting to insert [items] using [insertMany] with the the result
|
||||
* of the inserts returned.
|
||||
*
|
||||
* Items that were not inserted due to conflicts are then updated using [updateMany]
|
||||
*/
|
||||
suspend fun <T> upsert(
|
||||
items: List<T>,
|
||||
insertMany: suspend (List<T>) -> List<Long>,
|
||||
updateMany: suspend (List<T>) -> Unit,
|
||||
) {
|
||||
val insertResults = insertMany(items)
|
||||
|
||||
val updateList = items.zip(insertResults)
|
||||
.mapNotNull { (item, insertResult) ->
|
||||
if (insertResult == -1L) item else null
|
||||
}
|
||||
if (updateList.isNotEmpty()) updateMany(updateList)
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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.database.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
|
||||
/**
|
||||
* Cross reference for many to many relationship between [EpisodeEntity] and [AuthorEntity]
|
||||
*/
|
||||
@Entity(
|
||||
tableName = "episodes_authors",
|
||||
primaryKeys = ["episode_id", "author_id"],
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = EpisodeEntity::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["episode_id"],
|
||||
onDelete = ForeignKey.CASCADE
|
||||
),
|
||||
ForeignKey(
|
||||
entity = AuthorEntity::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["author_id"],
|
||||
onDelete = ForeignKey.CASCADE
|
||||
),
|
||||
],
|
||||
indices = [
|
||||
Index(value = ["episode_id"]),
|
||||
Index(value = ["author_id"]),
|
||||
],
|
||||
)
|
||||
data class EpisodeAuthorCrossRef(
|
||||
@ColumnInfo(name = "episode_id")
|
||||
val episodeId: String,
|
||||
@ColumnInfo(name = "author_id")
|
||||
val authorId: String,
|
||||
)
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.database.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.datetime.Instant
|
||||
|
||||
/**
|
||||
* Defines an NiA episode.
|
||||
* It is a parent in a 1 to many relationship with [NewsResourceEntity]
|
||||
*/
|
||||
@Entity(
|
||||
tableName = "episodes",
|
||||
)
|
||||
data class EpisodeEntity(
|
||||
@PrimaryKey
|
||||
val id: String,
|
||||
val name: String,
|
||||
@ColumnInfo(name = "publish_date")
|
||||
val publishDate: Instant,
|
||||
@ColumnInfo(name = "alternate_video")
|
||||
val alternateVideo: String?,
|
||||
@ColumnInfo(name = "alternate_audio")
|
||||
val alternateAudio: String?,
|
||||
)
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.database.model
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Junction
|
||||
import androidx.room.Relation
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.Episode
|
||||
|
||||
/**
|
||||
* External data layer representation of an NiA episode
|
||||
*/
|
||||
data class PopulatedEpisode(
|
||||
@Embedded
|
||||
val entity: EpisodeEntity,
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "episode_id"
|
||||
)
|
||||
val newsResources: List<NewsResourceEntity>,
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "id",
|
||||
associateBy = Junction(
|
||||
value = EpisodeAuthorCrossRef::class,
|
||||
parentColumn = "episode_id",
|
||||
entityColumn = "author_id",
|
||||
)
|
||||
)
|
||||
val authors: List<AuthorEntity>
|
||||
)
|
||||
|
||||
fun PopulatedEpisode.asExternalModel() = Episode(
|
||||
id = entity.id,
|
||||
name = entity.name,
|
||||
publishDate = entity.publishDate,
|
||||
alternateVideo = entity.alternateVideo,
|
||||
alternateAudio = entity.alternateAudio,
|
||||
newsResources = newsResources.map(NewsResourceEntity::asExternalModel),
|
||||
authors = authors.map(AuthorEntity::asExternalModel)
|
||||
)
|
@ -0,0 +1,3 @@
|
||||
# :core:datastore-test module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_datastore_test.png)
|
@ -0,0 +1,3 @@
|
||||
# :core:datastore module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_datastore.png)
|
@ -0,0 +1,3 @@
|
||||
# :core:designsystem module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_designsystem.png)
|
@ -0,0 +1,3 @@
|
||||
# :core:model module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_model.png)
|
@ -0,0 +1,3 @@
|
||||
# :core:navigation module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_navigation.png)
|
@ -0,0 +1,3 @@
|
||||
# :core:network module
|
||||
|
||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_network.png)
|
File diff suppressed because it is too large
Load Diff
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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.network.model
|
||||
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.Episode
|
||||
import com.google.samples.apps.nowinandroid.core.network.model.util.InstantSerializer
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Network representation of [Episode] when fetched from /episodes
|
||||
*/
|
||||
@Serializable
|
||||
data class NetworkEpisode(
|
||||
val id: String,
|
||||
val name: String,
|
||||
@Serializable(InstantSerializer::class)
|
||||
val publishDate: Instant,
|
||||
val alternateVideo: String?,
|
||||
val alternateAudio: String?,
|
||||
val newsResources: List<String> = listOf(),
|
||||
val authors: List<String> = listOf(),
|
||||
)
|
||||
|
||||
/**
|
||||
* Network representation of [Episode] when fetched from /episodes/{id}
|
||||
*/
|
||||
@Serializable
|
||||
data class NetworkEpisodeExpanded(
|
||||
val id: String,
|
||||
val name: String,
|
||||
@Serializable(InstantSerializer::class)
|
||||
val publishDate: Instant,
|
||||
val alternateVideo: String,
|
||||
val alternateAudio: String,
|
||||
val newsResources: List<NetworkNewsResource> = listOf(),
|
||||
val authors: List<NetworkAuthor> = listOf(),
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue