Merge branch 'github/main'

av/paparazzi-showkase-preview-screenshot-testing
Automerger 2 years ago
commit 4169f33ec3

@ -518,24 +518,34 @@ fun NiaCatalog() {
item { Text("Tags", Modifier.padding(top = 16.dp)) } item { Text("Tags", Modifier.padding(top = 16.dp)) }
item { item {
FlowRow(mainAxisSpacing = 16.dp) { FlowRow(mainAxisSpacing = 16.dp) {
var expandedTopicId by remember { mutableStateOf<String?>(null) }
var firstFollowed by remember { mutableStateOf(false) } var firstFollowed by remember { mutableStateOf(false) }
NiaTopicTag( NiaTopicTag(
expanded = expandedTopicId == "Topic 1",
followed = firstFollowed, followed = firstFollowed,
onDropMenuToggle = { show ->
expandedTopicId = if (show) "Topic 1" else null
},
onFollowClick = { firstFollowed = true }, onFollowClick = { firstFollowed = true },
onUnfollowClick = { firstFollowed = false }, onUnfollowClick = { firstFollowed = false },
onBrowseClick = {}, onBrowseClick = {},
text = { Text(text = "Topic".uppercase()) }, text = { Text(text = "Topic 1".uppercase()) },
followText = { Text(text = "Follow") }, followText = { Text(text = "Follow") },
unFollowText = { Text(text = "Unfollow") }, unFollowText = { Text(text = "Unfollow") },
browseText = { Text(text = "Browse topic") } browseText = { Text(text = "Browse topic") }
) )
var secondFollowed by remember { mutableStateOf(true) } var secondFollowed by remember { mutableStateOf(true) }
NiaTopicTag( NiaTopicTag(
expanded = expandedTopicId == "Topic 2",
followed = secondFollowed, followed = secondFollowed,
onDropMenuToggle = { show ->
expandedTopicId = if (show) "Topic 2" else null
},
onFollowClick = { secondFollowed = true }, onFollowClick = { secondFollowed = true },
onUnfollowClick = { secondFollowed = false }, onUnfollowClick = { secondFollowed = false },
onBrowseClick = {}, onBrowseClick = {},
text = { Text(text = "Topic".uppercase()) }, text = { Text(text = "Topic 2".uppercase()) },
followText = { Text(text = "Follow") }, followText = { Text(text = "Follow") },
unFollowText = { Text(text = "Unfollow") }, unFollowText = { Text(text = "Unfollow") },
browseText = { Text(text = "Browse topic") } browseText = { Text(text = "Browse topic") }

@ -0,0 +1,455 @@
{
"formatVersion": 1,
"database": {
"version": 10,
"identityHash": "d90e438da4b3b9cf552df536431dacb3",
"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": "episodes_authors",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`episode_id` TEXT NOT NULL, `author_id` TEXT 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": "TEXT",
"notNull": true
},
{
"fieldPath": "authorId",
"columnName": "author_id",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"episode_id",
"author_id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_episodes_authors_episode_id",
"unique": false,
"columnNames": [
"episode_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_episodes_authors_episode_id` ON `${TABLE_NAME}` (`episode_id`)"
},
{
"name": "index_episodes_authors_author_id",
"unique": false,
"columnNames": [
"author_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_episodes_authors_author_id` ON `${TABLE_NAME}` (`author_id`)"
}
],
"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` TEXT 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": "TEXT",
"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` 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, `episode_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`), FOREIGN KEY(`episode_id`) REFERENCES `episodes`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "episodeId",
"columnName": "episode_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": [
{
"name": "index_news_resources_episode_id",
"unique": false,
"columnNames": [
"episode_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_news_resources_episode_id` ON `${TABLE_NAME}` (`episode_id`)"
}
],
"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` 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, 'd90e438da4b3b9cf552df536431dacb3')"
]
}
}

@ -44,7 +44,7 @@ import com.google.samples.apps.nowinandroid.core.database.util.NewsResourceTypeC
NewsResourceTopicCrossRef::class, NewsResourceTopicCrossRef::class,
TopicEntity::class, TopicEntity::class,
], ],
version = 9, version = 10,
autoMigrations = [ autoMigrations = [
AutoMigration(from = 1, to = 2), AutoMigration(from = 1, to = 2),
AutoMigration(from = 2, to = 3, spec = DatabaseMigrations.Schema2to3::class), AutoMigration(from = 2, to = 3, spec = DatabaseMigrations.Schema2to3::class),
@ -54,6 +54,7 @@ import com.google.samples.apps.nowinandroid.core.database.util.NewsResourceTypeC
AutoMigration(from = 6, to = 7), AutoMigration(from = 6, to = 7),
AutoMigration(from = 7, to = 8), AutoMigration(from = 7, to = 8),
AutoMigration(from = 8, to = 9), AutoMigration(from = 8, to = 9),
AutoMigration(from = 9, to = 10),
], ],
exportSchema = true, exportSchema = true,
) )

@ -19,6 +19,7 @@ package com.google.samples.apps.nowinandroid.core.database.model
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
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.NewsResourceType import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType
@ -37,6 +38,9 @@ import kotlinx.datetime.Instant
childColumns = ["episode_id"], childColumns = ["episode_id"],
onDelete = ForeignKey.CASCADE onDelete = ForeignKey.CASCADE
), ),
],
indices = [
Index(value = ["episode_id"])
] ]
) )
data class NewsResourceEntity( data class NewsResourceEntity(

@ -21,10 +21,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.contentColorFor import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -32,7 +28,9 @@ import com.google.samples.apps.nowinandroid.core.designsystem.R
@Composable @Composable
fun NiaTopicTag( fun NiaTopicTag(
expanded: Boolean = false,
followed: Boolean, followed: Boolean,
onDropMenuToggle: (show: Boolean) -> Unit = {},
onFollowClick: () -> Unit, onFollowClick: () -> Unit,
onUnfollowClick: () -> Unit, onUnfollowClick: () -> Unit,
onBrowseClick: () -> Unit, onBrowseClick: () -> Unit,
@ -43,7 +41,7 @@ fun NiaTopicTag(
unFollowText: @Composable () -> Unit = { Text(stringResource(R.string.unfollow)) }, unFollowText: @Composable () -> Unit = { Text(stringResource(R.string.unfollow)) },
browseText: @Composable () -> Unit = { Text(stringResource(R.string.browse_topic)) } browseText: @Composable () -> Unit = { Text(stringResource(R.string.browse_topic)) }
) { ) {
var expanded by remember { mutableStateOf(false) }
Box(modifier = modifier) { Box(modifier = modifier) {
val containerColor = if (followed) { val containerColor = if (followed) {
MaterialTheme.colorScheme.primaryContainer MaterialTheme.colorScheme.primaryContainer
@ -51,7 +49,7 @@ fun NiaTopicTag(
MaterialTheme.colorScheme.surfaceVariant MaterialTheme.colorScheme.surfaceVariant
} }
NiaTextButton( NiaTextButton(
onClick = { expanded = true }, onClick = { onDropMenuToggle(true) },
enabled = enabled, enabled = enabled,
small = true, small = true,
colors = NiaButtonDefaults.textButtonColors( colors = NiaButtonDefaults.textButtonColors(
@ -69,7 +67,7 @@ fun NiaTopicTag(
) )
NiaDropdownMenu( NiaDropdownMenu(
expanded = expanded, expanded = expanded,
onDismissRequest = { expanded = false }, onDismissRequest = { onDropMenuToggle(false) },
items = if (followed) listOf(UNFOLLOW, BROWSE) else listOf(FOLLOW, BROWSE), items = if (followed) listOf(UNFOLLOW, BROWSE) else listOf(FOLLOW, BROWSE),
onItemClick = { item -> onItemClick = { item ->
when (item) { when (item) {

@ -268,13 +268,21 @@ fun NewsResourceTopics(
topics: List<Topic>, topics: List<Topic>,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
// Store the ID of the Topic which has its "following" menu expanded, if any.
// To avoid UI confusion, only one topic can have an expanded menu at a time.
var expandedTopicId by remember { mutableStateOf<String?>(null) }
Row( Row(
modifier = modifier.horizontalScroll(rememberScrollState()), // causes narrow chips modifier = modifier.horizontalScroll(rememberScrollState()), // causes narrow chips
horizontalArrangement = Arrangement.spacedBy(4.dp), horizontalArrangement = Arrangement.spacedBy(4.dp),
) { ) {
for (topic in topics) { for (topic in topics) {
NiaTopicTag( NiaTopicTag(
expanded = expandedTopicId == topic.id,
followed = true, // ToDo: Check if topic is followed followed = true, // ToDo: Check if topic is followed
onDropMenuToggle = { show ->
expandedTopicId = if (show) topic.id else null
},
onFollowClick = { }, // ToDo onFollowClick = { }, // ToDo
onUnfollowClick = { }, // ToDo onUnfollowClick = { }, // ToDo
onBrowseClick = { }, // ToDo onBrowseClick = { }, // ToDo

@ -4,7 +4,7 @@ androidDesugarJdkLibs = "1.1.5"
androidGradlePlugin = "7.2.2" androidGradlePlugin = "7.2.2"
androidxActivity = "1.5.1" androidxActivity = "1.5.1"
androidxAppCompat = "1.5.0" androidxAppCompat = "1.5.0"
androidxCompose = "1.2.0-rc03" androidxCompose = "1.2.1"
androidxComposeCompiler = "1.2.0" androidxComposeCompiler = "1.2.0"
androidxComposeMaterial3 = "1.0.0-alpha13" androidxComposeMaterial3 = "1.0.0-alpha13"
androidxCore = "1.8.0" androidxCore = "1.8.0"
@ -34,7 +34,7 @@ junit4 = "4.13.2"
kotlin = "1.7.0" kotlin = "1.7.0"
kotlinxCoroutines = "1.6.3" kotlinxCoroutines = "1.6.3"
kotlinxDatetime = "0.4.0" kotlinxDatetime = "0.4.0"
kotlinxSerializationJson = "1.3.3" kotlinxSerializationJson = "1.4.0"
ksp = "1.7.0-1.0.6" ksp = "1.7.0-1.0.6"
ktlint = "0.43.0" ktlint = "0.43.0"
lint = "30.2.2" lint = "30.2.2"

Loading…
Cancel
Save