diff --git a/app/build.gradle b/app/build.gradle index 87ffa57c7..f5aceda74 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -139,6 +139,9 @@ dependencies { implementation libs.material3 implementation libs.androidx.profileinstaller + implementation libs.coil.kt + implementation libs.coil.kt.svg + implementation libs.hilt.android kapt libs.hilt.compiler kaptAndroidTest libs.hilt.compiler diff --git a/app/src/main/java/com/google/samples/apps/nowinandroid/NiAApp.kt b/app/src/main/java/com/google/samples/apps/nowinandroid/NiAApp.kt index f0e9c3102..3db60f128 100644 --- a/app/src/main/java/com/google/samples/apps/nowinandroid/NiAApp.kt +++ b/app/src/main/java/com/google/samples/apps/nowinandroid/NiAApp.kt @@ -17,6 +17,9 @@ package com.google.samples.apps.nowinandroid import android.app.Application +import coil.ImageLoader +import coil.ImageLoaderFactory +import coil.decode.SvgDecoder import com.google.samples.apps.nowinandroid.sync.initializers.Sync import dagger.hilt.android.HiltAndroidApp @@ -24,10 +27,25 @@ import dagger.hilt.android.HiltAndroidApp * [Application] class for NiA */ @HiltAndroidApp -class NiAApp : Application() { +class NiAApp : Application(), ImageLoaderFactory { override fun onCreate() { super.onCreate() // Initialize Sync; the system responsible for keeping data in the app up to date. Sync.initialize(context = this) } + + /** + * Since we're displaying SVGs in the app, Coil needs an ImageLoader which supports this + * format. During Coil's initialization it will call `applicationContext.newImageLoader()` to + * obtain an ImageLoader. + * + * @see https://github.com/coil-kt/coil/blob/main/coil-singleton/src/main/java/coil/Coil.kt#L63 + */ + override fun newImageLoader(): ImageLoader { + return ImageLoader.Builder(this) + .components { + add(SvgDecoder.Factory()) + } + .build() + } } diff --git a/core-database/schemas/com.google.samples.apps.nowinandroid.core.database.NiADatabase/3.json b/core-database/schemas/com.google.samples.apps.nowinandroid.core.database.NiADatabase/3.json new file mode 100644 index 000000000..e6b0a4e14 --- /dev/null +++ b/core-database/schemas/com.google.samples.apps.nowinandroid.core.database.NiADatabase/3.json @@ -0,0 +1,387 @@ +{ + "formatVersion": 1, + "database": { + "version": 3, + "identityHash": "f593c030a1a8b5af8e13c6ac6a0926a9", + "entities": [ + { + "tableName": "authors", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `image_url` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "image_url", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_authors_name", + "unique": true, + "columnNames": [ + "name" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_authors_name` ON `${TABLE_NAME}` (`name`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "episodes_authors", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`episode_id` INTEGER NOT NULL, `author_id` INTEGER NOT NULL, PRIMARY KEY(`episode_id`, `author_id`), FOREIGN KEY(`episode_id`) REFERENCES `episodes`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`author_id`) REFERENCES `authors`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "episodeId", + "columnName": "episode_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "authorId", + "columnName": "author_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "episode_id", + "author_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "episodes", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "episode_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "authors", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "author_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "episodes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `publish_date` INTEGER NOT NULL, `alternate_video` TEXT, `alternate_audio` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "publishDate", + "columnName": "publish_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "alternateVideo", + "columnName": "alternate_video", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "alternateAudio", + "columnName": "alternate_audio", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "news_resources_authors", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`news_resource_id` INTEGER NOT NULL, `author_id` INTEGER 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": "INTEGER", + "notNull": true + }, + { + "fieldPath": "authorId", + "columnName": "author_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "news_resource_id", + "author_id" + ], + "autoGenerate": false + }, + "indices": [], + "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` INTEGER NOT NULL, `episode_id` INTEGER 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`), FOREIGN KEY(`episode_id`) REFERENCES `episodes`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "episodeId", + "columnName": "episode_id", + "affinity": "INTEGER", + "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": [ + { + "table": "episodes", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "episode_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "news_resources_topics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`news_resource_id` INTEGER NOT NULL, `topic_id` INTEGER 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": "INTEGER", + "notNull": true + }, + { + "fieldPath": "topicId", + "columnName": "topic_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "news_resource_id", + "topic_id" + ], + "autoGenerate": false + }, + "indices": [], + "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` INTEGER 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": "INTEGER", + "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": [ + { + "name": "index_topics_name", + "unique": true, + "columnNames": [ + "name" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_topics_name` ON `${TABLE_NAME}` (`name`)" + } + ], + "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, 'f593c030a1a8b5af8e13c6ac6a0926a9')" + ] + } +} \ No newline at end of file diff --git a/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/DatabaseMigrations.kt b/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/DatabaseMigrations.kt new file mode 100644 index 000000000..948f0f158 --- /dev/null +++ b/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/DatabaseMigrations.kt @@ -0,0 +1,37 @@ +/* + * 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 + +import androidx.room.RenameColumn +import androidx.room.migration.AutoMigrationSpec + +/** + * Automatic schema migrations sometimes require extra instructions to perform the migration, for + * example, when a column is renamed. These extra instructions are placed here by creating a class + * using the following naming convention `SchemaXtoY` where X is the schema version you're migrating + * from and Y is the schema version you're migrating to. The class should implement + * `AutoMigrationSpec`. + */ +class DatabaseMigrations { + + @RenameColumn( + tableName = "topics", + fromColumnName = "description", + toColumnName = "shortDescription" + ) + class Schema2to3 : AutoMigrationSpec +} diff --git a/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/NiADatabase.kt b/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/NiADatabase.kt index 5f370314a..068533855 100644 --- a/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/NiADatabase.kt +++ b/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/NiADatabase.kt @@ -44,9 +44,10 @@ import com.google.samples.apps.nowinandroid.core.database.util.NewsResourceTypeC NewsResourceTopicCrossRef::class, TopicEntity::class, ], - version = 2, + version = 3, autoMigrations = [ - AutoMigration(from = 1, to = 2) + AutoMigration(from = 1, to = 2), + AutoMigration(from = 2, to = 3, spec = DatabaseMigrations.Schema2to3::class), ], exportSchema = true, ) diff --git a/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/model/TopicEntity.kt b/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/model/TopicEntity.kt index 314c0868e..4d07cf773 100644 --- a/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/model/TopicEntity.kt +++ b/core-database/src/main/java/com/google/samples/apps/nowinandroid/core/database/model/TopicEntity.kt @@ -16,6 +16,7 @@ package com.google.samples.apps.nowinandroid.core.database.model +import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.Index import androidx.room.PrimaryKey @@ -35,11 +36,20 @@ data class TopicEntity( @PrimaryKey val id: Int, val name: String, - val description: String, + val shortDescription: String, + @ColumnInfo(defaultValue = "") + val longDescription: String, + @ColumnInfo(defaultValue = "") + val url: String, + @ColumnInfo(defaultValue = "") + val imageUrl: String, ) fun TopicEntity.asExternalModel() = Topic( id = id, name = name, - description = description, + shortDescription = shortDescription, + longDescription = longDescription, + url = url, + imageUrl = imageUrl, ) diff --git a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/Topic.kt b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/Topic.kt index 4a7b1cb22..803aee5e7 100644 --- a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/Topic.kt +++ b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/Topic.kt @@ -22,5 +22,8 @@ import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic fun NetworkTopic.asEntity() = TopicEntity( id = id, name = name, - description = description, + shortDescription = shortDescription, + longDescription = longDescription, + url = url, + imageUrl = imageUrl ) diff --git a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeTopicsRepository.kt b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeTopicsRepository.kt index f999e8ea9..82d03ba25 100644 --- a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeTopicsRepository.kt +++ b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeTopicsRepository.kt @@ -49,7 +49,10 @@ class FakeTopicsRepository @Inject constructor( Topic( id = it.id, name = it.name, - description = it.description + shortDescription = it.shortDescription, + longDescription = it.longDescription, + url = it.url, + imageUrl = it.imageUrl ) } ) diff --git a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/database/model/PopulatedNewsResourceKtTest.kt b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/database/model/PopulatedNewsResourceKtTest.kt index 60daf497e..ef9559f2b 100644 --- a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/database/model/PopulatedNewsResourceKtTest.kt +++ b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/database/model/PopulatedNewsResourceKtTest.kt @@ -56,7 +56,10 @@ class PopulatedNewsResourceKtTest { TopicEntity( id = 3, name = "name", - description = "description", + shortDescription = "short description", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ) ), ) @@ -83,7 +86,10 @@ class PopulatedNewsResourceKtTest { Topic( id = 3, name = "name", - description = "description", + shortDescription = "short description", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ) ) ), diff --git a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/model/NetworkEntityKtTest.kt b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/model/NetworkEntityKtTest.kt index 9df641edd..bd36dba82 100644 --- a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/model/NetworkEntityKtTest.kt +++ b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/model/NetworkEntityKtTest.kt @@ -48,13 +48,19 @@ class NetworkEntityKtTest { val networkModel = NetworkTopic( id = 0, name = "Test", - description = "something" + shortDescription = "short description", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ) val entity = networkModel.asEntity() assertEquals(0, entity.id) assertEquals("Test", entity.name) - assertEquals("something", entity.description) + assertEquals("short description", entity.shortDescription) + assertEquals("long description", entity.longDescription) + assertEquals("URL", entity.url) + assertEquals("image URL", entity.imageUrl) } @Test diff --git a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/testdoubles/TestNewsResourceDao.kt b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/testdoubles/TestNewsResourceDao.kt index a790fecc0..b8bb33af9 100644 --- a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/testdoubles/TestNewsResourceDao.kt +++ b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/testdoubles/TestNewsResourceDao.kt @@ -94,7 +94,10 @@ private fun NewsResourceEntity.asPopulatedNewsResource() = PopulatedNewsResource TopicEntity( id = filteredTopicIds.random(), name = "name", - description = "description", + shortDescription = "short description", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ) ), ) diff --git a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/testdoubles/TestTopicDao.kt b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/testdoubles/TestTopicDao.kt index f4ec8346b..08af69d93 100644 --- a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/testdoubles/TestTopicDao.kt +++ b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/testdoubles/TestTopicDao.kt @@ -31,7 +31,10 @@ class TestTopicDao : TopicDao { TopicEntity( id = 1, name = "Topic", - description = "A topic", + shortDescription = "short description", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ) ) diff --git a/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Topic.kt b/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Topic.kt index f4c809260..f42dcad9a 100644 --- a/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Topic.kt +++ b/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Topic.kt @@ -22,5 +22,8 @@ package com.google.samples.apps.nowinandroid.core.model.data data class Topic( val id: Int, val name: String, - val description: String, + val shortDescription: String, + val longDescription: String, + val url: String, + val imageUrl: String, ) diff --git a/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/fake/FakeData.kt b/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/fake/FakeData.kt index 65b93cf48..2e65e5871 100644 --- a/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/fake/FakeData.kt +++ b/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/fake/FakeData.kt @@ -26,9 +26,12 @@ import org.intellij.lang.annotations.Language object FakeDataSource { val sampleTopic = NetworkTopic( - id = 0, - name = "Headlines", - description = "At vero eos et accusamus et iusto odio dignissimos ducimus qui.", + id = 1, + name = "UI", + shortDescription = "Material Design, Navigation, Text, Paging, Compose, Accessibility (a11y), Internationalization (i18n), Localization (l10n), Animations, Large Screens, Widgets", + longDescription = "Learn how to optimize your app's user interface - everything that users can see and interact with. Stay up to date on tocpis such as Material Design, Navigation, Text, Paging, Compose, Accessibility (a11y), Internationalization (i18n), Localization (l10n), Animations, Large Screens, Widgets, and many more!", + url = "url", + imageUrl = "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_UI.svg?alt=media&token=5d1d25a8-db1b-4cf1-9706-82ba0d133bf9" ) val sampleResource = NetworkNewsResource( id = 1, @@ -54,101 +57,166 @@ object FakeDataSource { @Language("JSON") val topicsData = """ [ - { - "id": 0, - "name": "Headlines", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 1, - "name": "UI", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 2, - "name": "Testing", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 3, - "name": "Performance", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 4, - "name": "Camera & Media", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 5, - "name": "Android Studio", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 6, - "name": "New APIs & Libraries", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 7, - "name": "Data Storage", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 8, - "name": "Kotlin", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 9, - "name": "Compose", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 10, - "name": "Privacy & Security", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 11, - "name": "Publishing & Distribution", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 12, - "name": "Tools", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 13, - "name": "Platform & Releases", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 14, - "name": "Architecture", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 15, - "name": "Accessibility", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 16, - "name": "Android Auto", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 17, - "name": "Games", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - }, - { - "id": 18, - "name": "Wear OS", - "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui." - } + { + "id": "1", + "name": "UI", + "shortDescription": "Material Design, Navigation, Text, Paging, Compose, Accessibility (a11y), Internationalization (i18n), Localization (l10n), Animations, Large Screens, Widgets", + "longDescription": "Learn how to optimize your app's user interface - everything that users can see and interact with. Stay up to date on tocpis such as Material Design, Navigation, Text, Paging, Compose, Accessibility (a11y), Internationalization (i18n), Localization (l10n), Animations, Large Screens, Widgets, and many more!", + "url": "url", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_UI.svg?alt=media&token=5d1d25a8-db1b-4cf1-9706-82ba0d133bf9" + }, + { + "id": "0", + "name": "Headlines", + "shortDescription": "News we want everyone to see", + "longDescription": "Stay up to date with the latest events and announcements from Android!", + "url": "", + "imageUrl": "" + }, + { + "id": "2", + "name": "Testing", + "shortDescription": "CI, Espresso, TestLab, etc", + "longDescription": "Testing is an integral part of the app development process. By running tests against your app consistently, you can verify your app's correctness, functional behavior, and usability before you release it publicly. Stay up to date on the latest tricks in CI, Espresso, and Firebase TestLab.", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Testing.svg?alt=media&token=0d11b0b9-3eee-438e-8f64-b420ba6d445c" + }, + { + "id": "3", + "name": "Performance", + "shortDescription": "Optimization, profiling", + "longDescription": "Topics here will try to optimize your app perfoamnce by profiling and identifying areas in which your app makes inefficient use of resources such as the CPU, memory, graphics, network, or the device battery.", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Performance.svg?alt=media&token=2becab75-8ba0-4af8-8f46-1aee1b299463" + }, + { + "id": "4", + "name": "Camera & Media", + "shortDescription": "", + "longDescription": "Learn about Android's robust APIs for playing and recording media, help add video, audio, and photo capabilities to your app!", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Camera%20%26%20Media.svg?alt=media&token=1c4efeec-88fa-4777-b50b-fb79e5cdfef9" + }, + { + "id": "5", + "name": "Android Studio", + "shortDescription": "", + "longDescription": "Android Studio is the official integrated development environment (IDE) for Android development. It provides the fastest tools for building apps on every type of Android device.", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Android%20Studio.svg?alt=media&token=b946fbef-5a27-49e6-8f58-12d89d6b6512" + }, + { + "id": "6", + "name": "New APIs & Libraries", + "shortDescription": "New Jetpack libraries", + "longDescription": "Stay up to date with the latest new APIs & libraires", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_New%20APIs%20%26%20Libraries.svg?alt=media&token=317397c4-a173-435b-9a07-2ca35b7beaf6" + }, + { + "id": "7", + "name": "Data Storage", + "shortDescription": "Room, Data Store", + "longDescription": "Android uses a file system that's similar to disk-based file systems on other platforms. The system provides several options for you to save your app data: App-specific storage, shared storage, preferences, and databases - learn about Room and Data Store!", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Data%20Storage.svg?alt=media&token=1dcddccc-b088-45a4-a23d-d874bd047eab" + }, + { + "id": "8", + "name": "Kotlin", + "shortDescription": "", + "longDescription": "Kotlin is a modern statically typed programming language used by over 60% of professional Android developers that helps boost productivity, developer satisfaction, and code safety.", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Kotlin.svg?alt=media&token=e0bc5290-3670-4abb-b6a3-abf47327c332" + }, + { + "id": "9", + "name": "Compose", + "shortDescription": "", + "longDescription": "Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Compose.svg?alt=media&token=c7cee979-5062-49a9-a653-6fb10530d59d" + }, + { + "id": "10", + "name": "Privacy & Security", + "shortDescription": "Privacy, Security", + "longDescription": "Learn about best practices and resources to help developers design and implement safe, secure, and private apps.", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Privacy%20%26%20Security.svg?alt=media&token=48cb3487-32f9-40fc-bf62-c488973150fc" + }, + { + "id": "11", + "name": "Publishing & Distribution", + "shortDescription": "Google Play", + "longDescription": "Learn about Google Play publish and distrubution system to make your Android applications available to users.", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Publishing%20%26%20Distribution.svg?alt=media&token=e65d36cb-4050-4f56-be9f-34c599d38805" + }, + { + "id": "12", + "name": "Tools", + "shortDescription": "Gradle, Memory Safety, Debugging", + "longDescription": "Android Studio, Compose tooling, APK Analyzer, Fast emulator, Intelligent code editor, Flexible build system, Realtime profilers, Gradle, Memory Safety, Debugging", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Tools.svg?alt=media&token=4df6167c-06ef-4fdd-9f7b-94a5d7f3376b" + }, + { + "id": "13", + "name": "Platform & Releases", + "shortDescription": "Android 12, Android 13, etc", + "longDescription": "Stay up to date with the latest Android releases and features!", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Platform%20%26%20Releases.svg?alt=media&token=57779dd8-3b19-4e58-9959-25ff4aeef5a2" + }, + { + "id": "14", + "name": "Architecture", + "shortDescription": "Lifecycle, Dependency Injection, WorkManager", + "longDescription": "Lifecycle, Dependency Injection, WorkManager", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Architecture.svg?alt=media&token=8f946cb6-2efa-462f-94b9-fb5112bcee48" + }, + { + "id": "15", + "name": "Accessibility", + "shortDescription": "", + "longDescription": "Accessibility is an important part of any app. Whether you're developing a new app or improving an existing one, consider the accessibility of your app's components.\n\nBy integrating accessibility features and services, you can improve your app's usability, particularly for users with disabilities.", + "url": "", + "imageUrl": "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Accessibility.svg?alt=media&token=6333941e-eeaf-4ab5-bec7-19920cc81d97" + }, + { + "id": "16", + "name": "Android Auto", + "shortDescription": "", + "longDescription": "Lean about how to build apps that help users connect on the road through Android Automotive OS and Android Auto", + "url": "", + "imageUrl": "" + }, + { + "id": "17", + "name": "Android TV", + "shortDescription": "", + "longDescription": "Learn about how to build a great user experience for your TV app: create immersive content on the big screen and for a remote control", + "url": "", + "imageUrl": "" + }, + { + "id": "18", + "name": "Games", + "shortDescription": "", + "longDescription": "Learn about new tools and best practices to support your game app development and game performance.", + "url": "", + "imageUrl": "" + }, + { + "id": "19", + "name": "Wear OS", + "shortDescription": "", + "longDescription": "Learn about new tools and best practices to support your Wear OS development and watch performance.", + "url": "", + "imageUrl": "" + } ] """.trimIndent() diff --git a/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/model/NetworkTopic.kt b/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/model/NetworkTopic.kt index 95860e790..064b49c6a 100644 --- a/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/model/NetworkTopic.kt +++ b/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/model/NetworkTopic.kt @@ -26,6 +26,9 @@ import kotlinx.serialization.Serializable data class NetworkTopic( val id: Int, val name: String = "", - val description: String = "", + val shortDescription: String = "", + val longDescription: String = "", + val url: String = "", + val imageUrl: String = "", val followed: Boolean = false, ) diff --git a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt index 07f245aec..20dbea518 100644 --- a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt +++ b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt @@ -291,7 +291,10 @@ private val newsResource = NewsResource( Topic( id = 1, name = "Name", - description = "Description", + shortDescription = "Short description", + longDescription = "Long description", + url = "URL", + imageUrl = "image URL" ) ) ) diff --git a/feature-following/build.gradle b/feature-following/build.gradle index 3e8d64cca..05cb10c92 100644 --- a/feature-following/build.gradle +++ b/feature-following/build.gradle @@ -52,6 +52,9 @@ dependencies { testImplementation project(':core-testing') androidTestImplementation project(':core-testing') + implementation libs.coil.kt + implementation libs.coil.kt.compose + implementation libs.kotlinx.coroutines.android implementation libs.androidx.hilt.navigation.compose diff --git a/feature-following/src/androidTest/java/com/google/samples/apps/nowinandroid/following/FollowingScreenTest.kt b/feature-following/src/androidTest/java/com/google/samples/apps/nowinandroid/following/FollowingScreenTest.kt index f251da7d0..2b8bb1f1c 100644 --- a/feature-following/src/androidTest/java/com/google/samples/apps/nowinandroid/following/FollowingScreenTest.kt +++ b/feature-following/src/androidTest/java/com/google/samples/apps/nowinandroid/following/FollowingScreenTest.kt @@ -98,7 +98,7 @@ class FollowingScreenTest { .assertIsDisplayed() composeTestRule - .onAllNodesWithText(TOPIC_DESC) + .onAllNodesWithText(TOPIC_SHORT_DESC) .assertCountEquals(testTopics.count()) composeTestRule @@ -133,14 +133,20 @@ class FollowingScreenTest { private const val TOPIC_1_NAME = "Headlines" private const val TOPIC_2_NAME = "UI" private const val TOPIC_3_NAME = "Tools" -private const val TOPIC_DESC = "At vero eos et accusamus et iusto odio dignissimos ducimus qui." +private const val TOPIC_SHORT_DESC = "At vero eos et accusamus." +private const val TOPIC_LONG_DESC = "At vero eos et accusamus et iusto odio dignissimos ducimus." +private const val TOPIC_URL = "URL" +private const val TOPIC_IMAGE_URL = "Image URL" private val testTopics = listOf( FollowableTopic( Topic( id = 0, name = TOPIC_1_NAME, - description = TOPIC_DESC, + shortDescription = TOPIC_SHORT_DESC, + longDescription = TOPIC_LONG_DESC, + url = TOPIC_URL, + imageUrl = TOPIC_IMAGE_URL, ), isFollowed = true ), @@ -148,7 +154,10 @@ private val testTopics = listOf( Topic( id = 1, name = TOPIC_2_NAME, - description = TOPIC_DESC + shortDescription = TOPIC_SHORT_DESC, + longDescription = TOPIC_LONG_DESC, + url = TOPIC_URL, + imageUrl = TOPIC_IMAGE_URL, ), isFollowed = false ), @@ -156,7 +165,10 @@ private val testTopics = listOf( Topic( id = 2, name = TOPIC_3_NAME, - description = TOPIC_DESC + shortDescription = TOPIC_SHORT_DESC, + longDescription = TOPIC_LONG_DESC, + url = TOPIC_URL, + imageUrl = TOPIC_IMAGE_URL, ), isFollowed = false ) diff --git a/feature-following/src/main/java/com/google/samples/apps/nowinandroid/feature/following/FollowingScreen.kt b/feature-following/src/main/java/com/google/samples/apps/nowinandroid/feature/following/FollowingScreen.kt index 288617fcc..cfc412a28 100644 --- a/feature-following/src/main/java/com/google/samples/apps/nowinandroid/feature/following/FollowingScreen.kt +++ b/feature-following/src/main/java/com/google/samples/apps/nowinandroid/feature/following/FollowingScreen.kt @@ -45,6 +45,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import coil.compose.AsyncImage import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.ui.NiaLoadingIndicator @@ -140,16 +141,17 @@ fun FollowingTopicCard( ) { TopicIcon( modifier = Modifier.padding(end = 24.dp), + topicImageUrl = followableTopic.topic.imageUrl, onClick = onTopicClick ) Column( Modifier - .wrapContentSize(Alignment.Center) + .wrapContentSize(Alignment.CenterStart) .weight(1f) .clickable { onTopicClick() } ) { TopicTitle(topicName = followableTopic.topic.name) - TopicDescription(topicDescription = followableTopic.topic.description) + TopicDescription(topicDescription = followableTopic.topic.shortDescription) } FollowButton( topicId = followableTopic.topic.id, @@ -176,23 +178,35 @@ fun TopicDescription(topicDescription: String) { Text( text = topicDescription, style = MaterialTheme.typography.body2, - modifier = Modifier.wrapContentSize(Alignment.Center) + modifier = Modifier.wrapContentSize(Alignment.CenterStart) ) } @Composable fun TopicIcon( modifier: Modifier = Modifier, + topicImageUrl: String, onClick: () -> Unit ) { - Icon( - imageVector = Icons.Filled.Android, - tint = Color.Magenta, - contentDescription = stringResource(id = R.string.following_topic_card_icon_content_desc), - modifier = modifier - .size(64.dp) - .clickable { onClick() } - ) + + val iconModifier = modifier.size(64.dp) + .clickable { onClick() } + val contentDescription = stringResource(id = R.string.following_topic_card_icon_content_desc) + + if (topicImageUrl.isEmpty()) { + Icon( + imageVector = Icons.Filled.Android, + tint = Color.Magenta, + contentDescription = contentDescription, + modifier = iconModifier + ) + } else { + AsyncImage( + model = topicImageUrl, + contentDescription = contentDescription, + modifier = iconModifier + ) + } } @Composable @@ -249,7 +263,10 @@ fun TopicCardPreview() { Topic( id = 0, name = "Compose", - description = "Description" + shortDescription = "Short description", + longDescription = "Long description", + url = "URL", + imageUrl = "imageUrl" ), isFollowed = false ), diff --git a/feature-following/src/test/java/com/google/samples/apps/nowinandroid/following/FollowingViewModelTest.kt b/feature-following/src/test/java/com/google/samples/apps/nowinandroid/following/FollowingViewModelTest.kt index 07d3f5ae7..e0437111b 100644 --- a/feature-following/src/test/java/com/google/samples/apps/nowinandroid/following/FollowingViewModelTest.kt +++ b/feature-following/src/test/java/com/google/samples/apps/nowinandroid/following/FollowingViewModelTest.kt @@ -111,14 +111,20 @@ class FollowingViewModelTest { private const val TOPIC_1_NAME = "Android Studio" private const val TOPIC_2_NAME = "Build" private const val TOPIC_3_NAME = "Compose" -private const val TOPIC_DESC = "At vero eos et accusamus et iusto odio dignissimos ducimus qui." +private const val TOPIC_SHORT_DESC = "At vero eos et accusamus." +private const val TOPIC_LONG_DESC = "At vero eos et accusamus et iusto odio dignissimos ducimus." +private const val TOPIC_URL = "URL" +private const val TOPIC_IMAGE_URL = "Image URL" private val testInputTopics = listOf( FollowableTopic( Topic( id = 0, name = TOPIC_1_NAME, - description = TOPIC_DESC, + shortDescription = TOPIC_SHORT_DESC, + longDescription = TOPIC_LONG_DESC, + url = TOPIC_URL, + imageUrl = TOPIC_IMAGE_URL, ), isFollowed = true ), @@ -126,7 +132,10 @@ private val testInputTopics = listOf( Topic( id = 1, name = TOPIC_2_NAME, - description = TOPIC_DESC + shortDescription = TOPIC_SHORT_DESC, + longDescription = TOPIC_LONG_DESC, + url = TOPIC_URL, + imageUrl = TOPIC_IMAGE_URL, ), isFollowed = false ), @@ -134,7 +143,10 @@ private val testInputTopics = listOf( Topic( id = 2, name = TOPIC_3_NAME, - description = TOPIC_DESC + shortDescription = TOPIC_SHORT_DESC, + longDescription = TOPIC_LONG_DESC, + url = TOPIC_URL, + imageUrl = TOPIC_IMAGE_URL, ), isFollowed = false ) @@ -145,7 +157,10 @@ private val testOutputTopics = listOf( Topic( id = 0, name = TOPIC_1_NAME, - description = TOPIC_DESC, + shortDescription = TOPIC_SHORT_DESC, + longDescription = TOPIC_LONG_DESC, + url = TOPIC_URL, + imageUrl = TOPIC_IMAGE_URL, ), isFollowed = true ), @@ -153,7 +168,10 @@ private val testOutputTopics = listOf( Topic( id = 1, name = TOPIC_2_NAME, - description = TOPIC_DESC + shortDescription = TOPIC_SHORT_DESC, + longDescription = TOPIC_LONG_DESC, + url = TOPIC_URL, + imageUrl = TOPIC_IMAGE_URL, ), isFollowed = true ), @@ -161,7 +179,10 @@ private val testOutputTopics = listOf( Topic( id = 2, name = TOPIC_3_NAME, - description = TOPIC_DESC + shortDescription = TOPIC_SHORT_DESC, + longDescription = TOPIC_LONG_DESC, + url = TOPIC_URL, + imageUrl = TOPIC_IMAGE_URL, ), isFollowed = false ) diff --git a/feature-foryou/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt b/feature-foryou/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt index 426e0ba70..225d96169 100644 --- a/feature-foryou/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt +++ b/feature-foryou/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt @@ -63,7 +63,7 @@ class ForYouScreenTest { topic = Topic( id = 0, name = "Headlines", - description = "" + shortDescription = "" ), isFollowed = false ), @@ -71,7 +71,7 @@ class ForYouScreenTest { topic = Topic( id = 1, name = "UI", - description = "" + shortDescription = "" ), isFollowed = false ), @@ -79,7 +79,7 @@ class ForYouScreenTest { topic = Topic( id = 2, name = "Tools", - description = "", + shortDescription = "", ), isFollowed = false ), @@ -127,7 +127,7 @@ class ForYouScreenTest { topic = Topic( id = 0, name = "Headlines", - description = "" + shortDescription = "" ), isFollowed = false ), @@ -135,7 +135,7 @@ class ForYouScreenTest { topic = Topic( id = 1, name = "UI", - description = "" + shortDescription = "" ), isFollowed = true ), @@ -143,7 +143,7 @@ class ForYouScreenTest { topic = Topic( id = 2, name = "Tools", - description = "", + shortDescription = "", ), isFollowed = false ), diff --git a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index eea37b6f0..93d793b57 100644 --- a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -190,7 +190,10 @@ fun ForYouScreenTopicSelection() { topic = Topic( id = 0, name = "Headlines", - description = "" + shortDescription = "", + longDescription = "", + url = "", + imageUrl = "" ), isFollowed = false ), @@ -198,7 +201,10 @@ fun ForYouScreenTopicSelection() { topic = Topic( id = 1, name = "UI", - description = "" + shortDescription = "", + longDescription = "", + url = "", + imageUrl = "" ), isFollowed = false ), @@ -206,7 +212,10 @@ fun ForYouScreenTopicSelection() { topic = Topic( id = 2, name = "Tools", - description = "", + shortDescription = "", + longDescription = "", + url = "", + imageUrl = "" ), isFollowed = false ), @@ -229,7 +238,10 @@ fun ForYouScreenTopicSelection() { Topic( id = 0, name = "Headlines", - description = "" + shortDescription = "", + longDescription = "", + url = "", + imageUrl = "" ) ), authors = emptyList() @@ -253,7 +265,10 @@ fun ForYouScreenTopicSelection() { Topic( id = 1, name = "UI", - description = "" + shortDescription = "", + longDescription = "", + url = "", + imageUrl = "" ), ), authors = emptyList() @@ -274,7 +289,10 @@ fun ForYouScreenTopicSelection() { Topic( id = 1, name = "UI", - description = "" + shortDescription = "", + longDescription = "", + url = "", + imageUrl = "" ), ), authors = emptyList() diff --git a/feature-foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt b/feature-foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt index 935df6378..1ed4ce9b4 100644 --- a/feature-foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt +++ b/feature-foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt @@ -105,7 +105,10 @@ class ForYouViewModelTest { topic = Topic( id = 0, name = "Headlines", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), isFollowed = false ), @@ -113,7 +116,10 @@ class ForYouViewModelTest { topic = Topic( id = 1, name = "UI", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), isFollowed = false ), @@ -121,7 +127,10 @@ class ForYouViewModelTest { topic = Topic( id = 2, name = "Tools", - description = "", + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), isFollowed = false ), @@ -177,7 +186,10 @@ class ForYouViewModelTest { topic = Topic( id = 0, name = "Headlines", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), isFollowed = false ), @@ -185,7 +197,10 @@ class ForYouViewModelTest { topic = Topic( id = 1, name = "UI", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), isFollowed = true ), @@ -193,7 +208,10 @@ class ForYouViewModelTest { topic = Topic( id = 2, name = "Tools", - description = "", + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), isFollowed = false ) @@ -237,7 +255,10 @@ class ForYouViewModelTest { topic = Topic( id = 0, name = "Headlines", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), isFollowed = false ), @@ -245,7 +266,10 @@ class ForYouViewModelTest { topic = Topic( id = 1, name = "UI", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), isFollowed = false ), @@ -253,7 +277,10 @@ class ForYouViewModelTest { topic = Topic( id = 2, name = "Tools", - description = "", + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), isFollowed = false ) @@ -335,17 +362,26 @@ private val sampleTopics = listOf( Topic( id = 0, name = "Headlines", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), Topic( id = 1, name = "UI", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), Topic( id = 2, name = "Tools", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ) ) @@ -366,7 +402,10 @@ private val sampleNewsResources = listOf( Topic( id = 0, name = "Headlines", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ) ), authors = emptyList() @@ -386,7 +425,10 @@ private val sampleNewsResources = listOf( Topic( id = 1, name = "UI", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), ), authors = emptyList() @@ -404,7 +446,10 @@ private val sampleNewsResources = listOf( Topic( id = 1, name = "UI", - description = "" + shortDescription = "", + longDescription = "long description", + url = "URL", + imageUrl = "image URL", ), ), authors = emptyList() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90fd347a5..4719c1005 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -82,6 +82,7 @@ androidx-work-ktx = { group = "androidx.work", name = "work-runtime-ktx", versio androidx-work-testing = { group = "androidx.work", name = "work-testing", version.ref = "androidxWork" } coil-kt = { group = "io.coil-kt", name = "coil", version.ref = "coil"} coil-kt-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil"} +coil-kt-svg = { group = "io.coil-kt", name = "coil-svg", version.ref = "coil"} hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" } hilt-ext-work = { group = "androidx.hilt", name = "hilt-work", version.ref = "hiltExt" } hilt-ext-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hiltExt" }