Merge branch 'github/main'

pull/305/head
Automerger 2 years ago
commit 4169f33ec3

@ -518,24 +518,34 @@ fun NiaCatalog() {
item { Text("Tags", Modifier.padding(top = 16.dp)) }
item {
FlowRow(mainAxisSpacing = 16.dp) {
var expandedTopicId by remember { mutableStateOf<String?>(null) }
var firstFollowed by remember { mutableStateOf(false) }
NiaTopicTag(
expanded = expandedTopicId == "Topic 1",
followed = firstFollowed,
onDropMenuToggle = { show ->
expandedTopicId = if (show) "Topic 1" else null
},
onFollowClick = { firstFollowed = true },
onUnfollowClick = { firstFollowed = false },
onBrowseClick = {},
text = { Text(text = "Topic".uppercase()) },
text = { Text(text = "Topic 1".uppercase()) },
followText = { Text(text = "Follow") },
unFollowText = { Text(text = "Unfollow") },
browseText = { Text(text = "Browse topic") }
)
var secondFollowed by remember { mutableStateOf(true) }
NiaTopicTag(
expanded = expandedTopicId == "Topic 2",
followed = secondFollowed,
onDropMenuToggle = { show ->
expandedTopicId = if (show) "Topic 2" else null
},
onFollowClick = { secondFollowed = true },
onUnfollowClick = { secondFollowed = false },
onBrowseClick = {},
text = { Text(text = "Topic".uppercase()) },
text = { Text(text = "Topic 2".uppercase()) },
followText = { Text(text = "Follow") },
unFollowText = { Text(text = "Unfollow") },
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,
TopicEntity::class,
],
version = 9,
version = 10,
autoMigrations = [
AutoMigration(from = 1, to = 2),
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 = 7, to = 8),
AutoMigration(from = 8, to = 9),
AutoMigration(from = 9, to = 10),
],
exportSchema = true,
)

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

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

@ -268,13 +268,21 @@ fun NewsResourceTopics(
topics: List<Topic>,
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(
modifier = modifier.horizontalScroll(rememberScrollState()), // causes narrow chips
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
for (topic in topics) {
NiaTopicTag(
expanded = expandedTopicId == topic.id,
followed = true, // ToDo: Check if topic is followed
onDropMenuToggle = { show ->
expandedTopicId = if (show) topic.id else null
},
onFollowClick = { }, // ToDo
onUnfollowClick = { }, // ToDo
onBrowseClick = { }, // ToDo

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

Loading…
Cancel
Save