commit
4d4f7d4a15
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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.google.devtools.ksp.gradle.KspExtension
|
||||||
|
import org.gradle.api.Plugin
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.VersionCatalogsExtension
|
||||||
|
import org.gradle.api.tasks.InputDirectory
|
||||||
|
import org.gradle.api.tasks.PathSensitive
|
||||||
|
import org.gradle.api.tasks.PathSensitivity
|
||||||
|
import org.gradle.kotlin.dsl.configure
|
||||||
|
import org.gradle.kotlin.dsl.dependencies
|
||||||
|
import org.gradle.kotlin.dsl.getByType
|
||||||
|
import org.gradle.process.CommandLineArgumentProvider
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class AndroidRoomConventionPlugin : Plugin<Project> {
|
||||||
|
|
||||||
|
override fun apply(target: Project) {
|
||||||
|
with(target) {
|
||||||
|
pluginManager.apply("com.google.devtools.ksp")
|
||||||
|
|
||||||
|
extensions.configure<KspExtension> {
|
||||||
|
// The schemas directory contains a schema file for each version of the Room database.
|
||||||
|
// This is required to enable Room auto migrations.
|
||||||
|
// See https://developer.android.com/reference/kotlin/androidx/room/AutoMigration.
|
||||||
|
arg(RoomSchemaArgProvider(File(projectDir, "schemas")))
|
||||||
|
}
|
||||||
|
|
||||||
|
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||||
|
dependencies {
|
||||||
|
add("implementation", libs.findLibrary("room.runtime").get())
|
||||||
|
add("implementation", libs.findLibrary("room.ktx").get())
|
||||||
|
add("ksp", libs.findLibrary("room.compiler").get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://issuetracker.google.com/issues/132245929
|
||||||
|
* [Export schemas](https://developer.android.com/training/data-storage/room/migrating-db-versions#export-schemas)
|
||||||
|
*/
|
||||||
|
class RoomSchemaArgProvider(
|
||||||
|
@get:InputDirectory
|
||||||
|
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||||
|
val schemaDir: File,
|
||||||
|
) : CommandLineArgumentProvider {
|
||||||
|
override fun asArguments() = listOf("room.schemaLocation=${schemaDir.path}")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 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.dsl.CommonExtension
|
||||||
|
import com.android.build.api.dsl.ManagedVirtualDevice
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.kotlin.dsl.invoke
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure project for Gradle managed devices
|
||||||
|
*/
|
||||||
|
internal fun configureGradleManagedDevices(
|
||||||
|
commonExtension: CommonExtension<*, *, *, *>,
|
||||||
|
) {
|
||||||
|
val deviceConfigs = listOf(
|
||||||
|
DeviceConfig("Pixel 4", 30, "aosp-atd"),
|
||||||
|
DeviceConfig("Pixel 6", 31, "aosp"),
|
||||||
|
DeviceConfig("Pixel C", 30, "aosp-atd"),
|
||||||
|
)
|
||||||
|
|
||||||
|
commonExtension.testOptions {
|
||||||
|
managedDevices {
|
||||||
|
devices {
|
||||||
|
deviceConfigs.forEach { deviceConfig ->
|
||||||
|
maybeCreate(deviceConfig.taskName, ManagedVirtualDevice::class.java).apply {
|
||||||
|
device = deviceConfig.device
|
||||||
|
apiLevel = deviceConfig.apiLevel
|
||||||
|
systemImageSource = deviceConfig.systemImageSource
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class DeviceConfig(
|
||||||
|
val device: String,
|
||||||
|
val apiLevel: Int,
|
||||||
|
val systemImageSource: String,
|
||||||
|
) {
|
||||||
|
val taskName = buildString {
|
||||||
|
append(device.toLowerCase(Locale.ROOT).replace(" ", ""))
|
||||||
|
append("api")
|
||||||
|
append(apiLevel.toString())
|
||||||
|
append(systemImageSource.replace("-", ""))
|
||||||
|
}
|
||||||
|
}
|
@ -1,218 +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.designsystem.component
|
|
||||||
|
|
||||||
import androidx.compose.foundation.BorderStroke
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.sizeIn
|
|
||||||
import androidx.compose.material3.ButtonDefaults
|
|
||||||
import androidx.compose.material3.DropdownMenu
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.OutlinedButton
|
|
||||||
import androidx.compose.material3.ProvideTextStyle
|
|
||||||
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.unit.dp
|
|
||||||
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Now in Android dropdown menu button with included trailing icon as well as text label and item
|
|
||||||
* content slots.
|
|
||||||
*
|
|
||||||
* @param items The list of items to display in the menu.
|
|
||||||
* @param onItemClick Called when the user clicks on a menu item.
|
|
||||||
* @param modifier Modifier to be applied to the button.
|
|
||||||
* @param enabled Controls the enabled state of the button. When `false`, this button will not be
|
|
||||||
* clickable and will appear disabled to accessibility services.
|
|
||||||
* @param dismissOnItemClick Whether the menu should be dismissed when an item is clicked.
|
|
||||||
* @param itemText The text label content for a given item.
|
|
||||||
* @param itemLeadingIcon The leading icon content for a given item.
|
|
||||||
* @param itemTrailingIcon The trailing icon content for a given item.
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
fun <T> NiaDropdownMenuButton(
|
|
||||||
items: List<T>,
|
|
||||||
onItemClick: (item: T) -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
enabled: Boolean = true,
|
|
||||||
dismissOnItemClick: Boolean = true,
|
|
||||||
text: @Composable () -> Unit,
|
|
||||||
itemText: @Composable (item: T) -> Unit,
|
|
||||||
itemLeadingIcon: @Composable ((item: T) -> Unit)? = null,
|
|
||||||
itemTrailingIcon: @Composable ((item: T) -> Unit)? = null,
|
|
||||||
) {
|
|
||||||
var expanded by remember { mutableStateOf(false) }
|
|
||||||
Box(modifier = modifier) {
|
|
||||||
OutlinedButton(
|
|
||||||
onClick = { expanded = true },
|
|
||||||
enabled = enabled,
|
|
||||||
colors = ButtonDefaults.outlinedButtonColors(
|
|
||||||
contentColor = MaterialTheme.colorScheme.onBackground,
|
|
||||||
),
|
|
||||||
border = BorderStroke(
|
|
||||||
width = NiaDropdownMenuDefaults.DropdownMenuButtonBorderWidth,
|
|
||||||
color = if (enabled) {
|
|
||||||
MaterialTheme.colorScheme.outline
|
|
||||||
} else {
|
|
||||||
MaterialTheme.colorScheme.onSurface.copy(
|
|
||||||
alpha = NiaDropdownMenuDefaults.DisabledDropdownMenuButtonBorderAlpha,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
contentPadding = NiaDropdownMenuDefaults.DropdownMenuButtonContentPadding,
|
|
||||||
) {
|
|
||||||
NiaDropdownMenuButtonContent(
|
|
||||||
text = text,
|
|
||||||
trailingIcon = {
|
|
||||||
Icon(
|
|
||||||
imageVector = if (expanded) {
|
|
||||||
NiaIcons.ArrowDropUp
|
|
||||||
} else {
|
|
||||||
NiaIcons.ArrowDropDown
|
|
||||||
},
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
NiaDropdownMenu(
|
|
||||||
expanded = expanded,
|
|
||||||
onDismissRequest = { expanded = false },
|
|
||||||
items = items,
|
|
||||||
onItemClick = onItemClick,
|
|
||||||
dismissOnItemClick = dismissOnItemClick,
|
|
||||||
itemText = itemText,
|
|
||||||
itemLeadingIcon = itemLeadingIcon,
|
|
||||||
itemTrailingIcon = itemTrailingIcon,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal Now in Android dropdown menu button content layout for arranging the text label and
|
|
||||||
* trailing icon.
|
|
||||||
*
|
|
||||||
* @param text The button text label content.
|
|
||||||
* @param trailingIcon The button trailing icon content. Default is `null` for no trailing icon.
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
private fun NiaDropdownMenuButtonContent(
|
|
||||||
text: @Composable () -> Unit,
|
|
||||||
trailingIcon: @Composable (() -> Unit)? = null,
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
Modifier
|
|
||||||
.padding(
|
|
||||||
end = if (trailingIcon != null) {
|
|
||||||
ButtonDefaults.IconSpacing
|
|
||||||
} else {
|
|
||||||
0.dp
|
|
||||||
},
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
ProvideTextStyle(value = MaterialTheme.typography.labelSmall) {
|
|
||||||
text()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (trailingIcon != null) {
|
|
||||||
Box(Modifier.sizeIn(maxHeight = ButtonDefaults.IconSize)) {
|
|
||||||
trailingIcon()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Now in Android dropdown menu with item content slots. Wraps Material 3 [DropdownMenu] and
|
|
||||||
* [DropdownMenuItem].
|
|
||||||
*
|
|
||||||
* @param expanded Whether the menu is currently open and visible to the user.
|
|
||||||
* @param onDismissRequest Called when the user requests to dismiss the menu, such as by
|
|
||||||
* tapping outside the menu's bounds.
|
|
||||||
* @param items The list of items to display in the menu.
|
|
||||||
* @param onItemClick Called when the user clicks on a menu item.
|
|
||||||
* @param dismissOnItemClick Whether the menu should be dismissed when an item is clicked.
|
|
||||||
* @param itemText The text label content for a given item.
|
|
||||||
* @param itemLeadingIcon The leading icon content for a given item.
|
|
||||||
* @param itemTrailingIcon The trailing icon content for a given item.
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
fun <T> NiaDropdownMenu(
|
|
||||||
expanded: Boolean,
|
|
||||||
onDismissRequest: () -> Unit,
|
|
||||||
items: List<T>,
|
|
||||||
onItemClick: (item: T) -> Unit,
|
|
||||||
dismissOnItemClick: Boolean = true,
|
|
||||||
itemText: @Composable (item: T) -> Unit,
|
|
||||||
itemLeadingIcon: @Composable ((item: T) -> Unit)? = null,
|
|
||||||
itemTrailingIcon: @Composable ((item: T) -> Unit)? = null,
|
|
||||||
) {
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = expanded,
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
) {
|
|
||||||
items.forEach { item ->
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { itemText(item) },
|
|
||||||
onClick = {
|
|
||||||
onItemClick(item)
|
|
||||||
if (dismissOnItemClick) onDismissRequest()
|
|
||||||
},
|
|
||||||
leadingIcon = if (itemLeadingIcon != null) {
|
|
||||||
{ itemLeadingIcon(item) }
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
},
|
|
||||||
trailingIcon = if (itemTrailingIcon != null) {
|
|
||||||
{ itemTrailingIcon(item) }
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Now in Android dropdown menu default values.
|
|
||||||
*/
|
|
||||||
object NiaDropdownMenuDefaults {
|
|
||||||
// TODO: File bug
|
|
||||||
// OutlinedButton border color doesn't respect disabled state by default
|
|
||||||
const val DisabledDropdownMenuButtonBorderAlpha = 0.12f
|
|
||||||
|
|
||||||
// TODO: File bug
|
|
||||||
// OutlinedButton default border width isn't exposed via ButtonDefaults
|
|
||||||
val DropdownMenuButtonBorderWidth = 1.dp
|
|
||||||
|
|
||||||
// TODO: File bug
|
|
||||||
// Various default button padding values aren't exposed via ButtonDefaults
|
|
||||||
val DropdownMenuButtonContentPadding =
|
|
||||||
PaddingValues(
|
|
||||||
start = 24.dp,
|
|
||||||
top = 8.dp,
|
|
||||||
end = 16.dp,
|
|
||||||
bottom = 8.dp,
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
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
|
|
||||||
|
|
||||||
http://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.
|
|
||||||
-->
|
|
||||||
<resources>
|
|
||||||
<string name="follow">Follow</string>
|
|
||||||
<string name="unfollow">Unfollow</string>
|
|
||||||
<string name="browse_topic">Browse topic</string>
|
|
||||||
</resources>
|
|
Loading…
Reference in new issue