From 0c07bce2569a8514dc209ae0696ab0f73c282ba8 Mon Sep 17 00:00:00 2001 From: Ben Weiss Date: Thu, 26 Feb 2026 11:18:32 +0100 Subject: [PATCH 1/4] Add CODEOWNERS for ai snippets --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index 3e5ad6203..e8b930100 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,3 +6,4 @@ /wearcompanion/ @android/devrel-wear /xr/ @android/devrel-xr /compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/ @android/devrel-adaptive-apps +/misc/src/main/java/com/example/snippets/ai/ @android/devrel-ai From d7a5941620f473b30eb7ef8215e84adec2f95802 Mon Sep 17 00:00:00 2001 From: Ben Weiss Date: Mon, 2 Mar 2026 09:52:59 +0100 Subject: [PATCH 2/4] Move AI snippets to dedicated module --- CODEOWNERS | 6 +- ai/build.gradle.kts | 93 +++++++++ ai/proguard-rules.pro | 21 ++ ...viceCompatibilityModeTestJavaSnippets.java | 51 +++++ ...viceCompatibilityModeTestKotlinSnippets.kt | 46 +++++ ai/src/main/AndroidManifest.xml | 52 +++++ .../java/com/example/snippets/MainActivity.kt | 58 ++++++ .../snippets/ai/AppFunctionsApiSnippets.kt | 0 .../snippets/ai/GeminiDeveloperApiSnippets.kt | 0 .../ai/GeminiDeveloperApiSnippetsJava.java | 0 .../com/example/snippets/ai/GeminiOverview.kt | 0 .../snippets/ai/GeminiOverviewJava.java | 0 .../com/example/snippets/ai/ImagenSnippets.kt | 0 .../snippets/ai/ImagenSnippetsJava.java | 0 .../example/snippets/ai/VertexAiGeminiApi.kt | 0 .../snippets/ai/VertexAiGeminiApiJava.java | 0 .../snippets/navigation/Destination.kt | 21 ++ .../snippets/navigation/LandingScreen.kt | 101 ++++++++++ .../com/example/snippets/ui/theme/Color.kt | 27 +++ .../com/example/snippets/ui/theme/Theme.kt | 73 +++++++ .../com/example/snippets/ui/theme/Type.kt | 50 +++++ .../res/drawable/ic_launcher_background.xml | 185 ++++++++++++++++++ .../res/drawable/ic_launcher_foreground.xml | 46 +++++ ai/src/main/res/drawable/scones.xml | 19 ++ ai/src/main/res/layout/activity_main.xml | 54 +++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 ++ ai/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes ai/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes ai/src/main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes ai/src/main/res/values/colors.xml | 27 +++ ai/src/main/res/values/strings.xml | 19 ++ ai/src/main/res/values/themes.xml | 20 ++ ai/src/main/res/xml/main_split_config.xml | 19 ++ settings.gradle.kts | 1 + 42 files changed, 1028 insertions(+), 3 deletions(-) create mode 100644 ai/build.gradle.kts create mode 100644 ai/proguard-rules.pro create mode 100644 ai/src/androidTest/java/com/example/snippets/DeviceCompatibilityModeTestJavaSnippets.java create mode 100644 ai/src/androidTest/java/com/example/snippets/DeviceCompatibilityModeTestKotlinSnippets.kt create mode 100644 ai/src/main/AndroidManifest.xml create mode 100644 ai/src/main/java/com/example/snippets/MainActivity.kt rename {misc => ai}/src/main/java/com/example/snippets/ai/AppFunctionsApiSnippets.kt (100%) rename {misc => ai}/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippets.kt (100%) rename {misc => ai}/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippetsJava.java (100%) rename {misc => ai}/src/main/java/com/example/snippets/ai/GeminiOverview.kt (100%) rename {misc => ai}/src/main/java/com/example/snippets/ai/GeminiOverviewJava.java (100%) rename {misc => ai}/src/main/java/com/example/snippets/ai/ImagenSnippets.kt (100%) rename {misc => ai}/src/main/java/com/example/snippets/ai/ImagenSnippetsJava.java (100%) rename {misc => ai}/src/main/java/com/example/snippets/ai/VertexAiGeminiApi.kt (100%) rename {misc => ai}/src/main/java/com/example/snippets/ai/VertexAiGeminiApiJava.java (100%) create mode 100644 ai/src/main/java/com/example/snippets/navigation/Destination.kt create mode 100644 ai/src/main/java/com/example/snippets/navigation/LandingScreen.kt create mode 100644 ai/src/main/java/com/example/snippets/ui/theme/Color.kt create mode 100644 ai/src/main/java/com/example/snippets/ui/theme/Theme.kt create mode 100644 ai/src/main/java/com/example/snippets/ui/theme/Type.kt create mode 100644 ai/src/main/res/drawable/ic_launcher_background.xml create mode 100644 ai/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 ai/src/main/res/drawable/scones.xml create mode 100644 ai/src/main/res/layout/activity_main.xml create mode 100644 ai/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 ai/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 ai/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 ai/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 ai/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 ai/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 ai/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 ai/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 ai/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 ai/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 ai/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 ai/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 ai/src/main/res/values/colors.xml create mode 100644 ai/src/main/res/values/strings.xml create mode 100644 ai/src/main/res/values/themes.xml create mode 100644 ai/src/main/res/xml/main_split_config.xml diff --git a/CODEOWNERS b/CODEOWNERS index e8b930100..bea8c1cd3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,9 +1,9 @@ * @yrezgui @kkuan2011 -/compose/ @android/devrel-compose +/ai/ @android/devrel-adaptive-apps /car/ @android/devrel-car +/compose/ @android/devrel-compose +/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/ @android/devrel-adaptive-apps /watchface/ @android/devrel-wear /wear/ @android/devrel-wear /wearcompanion/ @android/devrel-wear /xr/ @android/devrel-xr -/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/ @android/devrel-adaptive-apps -/misc/src/main/java/com/example/snippets/ai/ @android/devrel-ai diff --git a/ai/build.gradle.kts b/ai/build.gradle.kts new file mode 100644 index 000000000..71a1f330c --- /dev/null +++ b/ai/build.gradle.kts @@ -0,0 +1,93 @@ + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.ksp) + alias(libs.plugins.hilt) + alias(libs.plugins.compose.compiler) +} + +android { + compileSdk = libs.versions.compileSdk.get().toInt() + namespace = "com.example.snippets" + + defaultConfig { + applicationId = "com.example.snippets" + minSdk = libs.versions.minSdk.get().toInt() + targetSdk = libs.versions.targetSdk.get().toInt() + versionCode = 1 + versionName = "1.0" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + kotlin { + jvmToolchain(17) + } + + buildTypes { + getByName("debug") { + signingConfig = signingConfigs.getByName("debug") + } + + getByName("release") { + isMinifyEnabled = false + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro") + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + buildFeatures { + compose = true + // Disable unused AGP features + viewBinding = true + } + +} +dependencies { + val composeBom = platform(libs.androidx.compose.bom) + implementation(composeBom) + androidTestImplementation(composeBom) + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.activity.compose) + + implementation(libs.androidx.appfunctions) + implementation(libs.androidx.appfunctions.service) + ksp(libs.androidx.appfunctions.compiler) + + implementation(libs.androidx.compose.runtime) + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.compose.foundation.layout) + implementation(libs.androidx.compose.ui.util) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.media3.common) + implementation(libs.androidx.media3.exoplayer) + implementation(libs.androidx.tracing) + implementation(libs.androidx.work.runtime) + + implementation(libs.hilt.android) + implementation(libs.androidx.hilt.navigation.compose) + implementation(libs.kotlinx.serialization.json) + ksp(libs.hilt.compiler) + ksp(libs.kotlinx.metadata.jvm) + + implementation(libs.androidx.constraintlayout) + implementation(libs.androidx.lifecycle.runtime) + implementation(libs.androidx.window) + implementation(libs.androidx.startup.runtime) + implementation(libs.androidx.window.java) + implementation(libs.appcompat) + implementation(platform(libs.firebase.bom)) + implementation(libs.firebase.ai) + implementation(libs.guava.android) + implementation(libs.reactive.streams) + testImplementation(libs.junit) + testImplementation(kotlin("test")) + androidTestImplementation(libs.androidx.test.ext.junit) + androidTestImplementation(libs.junit) + androidTestImplementation(libs.androidx.test.core) + androidTestImplementation(libs.androidx.test.runner) + androidTestImplementation(libs.androidx.test.espresso.core) +} diff --git a/ai/proguard-rules.pro b/ai/proguard-rules.pro new file mode 100644 index 000000000..2f9dc5a47 --- /dev/null +++ b/ai/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle.kts. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/ai/src/androidTest/java/com/example/snippets/DeviceCompatibilityModeTestJavaSnippets.java b/ai/src/androidTest/java/com/example/snippets/DeviceCompatibilityModeTestJavaSnippets.java new file mode 100644 index 000000000..ba249b0e6 --- /dev/null +++ b/ai/src/androidTest/java/com/example/snippets/DeviceCompatibilityModeTestJavaSnippets.java @@ -0,0 +1,51 @@ +/* + * Copyright 2025 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.example.snippets; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.test.core.app.ActivityScenario; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import org.junit.Rule; +import org.junit.Test; +import static org.junit.Assert.assertFalse; + +public class DeviceCompatibilityModeTestJavaSnippets { + + // [START android_device_compatibility_mode_assert_isLetterboxed_java] + @Rule + public ActivityScenarioRule rule = new ActivityScenarioRule<>(MainActivity.class); + + @Test + public void activity_launched_notLetterBoxed() { + try (ActivityScenario scenario = + ActivityScenario.launch(MainActivity.class)) { + scenario.onActivity( activity -> { + assertFalse(activity.isLetterboxed()); + }); + } + } + // [END android_device_compatibility_mode_assert_isLetterboxed_java] + + + // Class used by snippets. + + class MainActivity extends AppCompatActivity { + public boolean isLetterboxed() { + return true; + } + } +} diff --git a/ai/src/androidTest/java/com/example/snippets/DeviceCompatibilityModeTestKotlinSnippets.kt b/ai/src/androidTest/java/com/example/snippets/DeviceCompatibilityModeTestKotlinSnippets.kt new file mode 100644 index 000000000..65f9a7f1f --- /dev/null +++ b/ai/src/androidTest/java/com/example/snippets/DeviceCompatibilityModeTestKotlinSnippets.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2025 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.example.snippets + +import androidx.appcompat.app.AppCompatActivity +import androidx.test.ext.junit.rules.ActivityScenarioRule +import org.junit.Assert.assertFalse +import org.junit.Rule +import org.junit.Test + +class DeviceCompatibilityModeTestKotlinSnippets { + + // [START android_device_compatibility_mode_assert_isLetterboxed_kotlin] + @get:Rule + val activityRule = ActivityScenarioRule(MainActivity::class.java) + + @Test + fun activity_launched_notLetterBoxed() { + activityRule.scenario.onActivity { + assertFalse(it.isLetterboxed()) + } + } + // [END android_device_compatibility_mode_assert_isLetterboxed_kotlin] + + // Class used by snippets. + + class MainActivity : AppCompatActivity() { + fun isLetterboxed(): Boolean { + return true + } + } +} diff --git a/ai/src/main/AndroidManifest.xml b/ai/src/main/AndroidManifest.xml new file mode 100644 index 000000000..10d3b5e39 --- /dev/null +++ b/ai/src/main/AndroidManifest.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ai/src/main/java/com/example/snippets/MainActivity.kt b/ai/src/main/java/com/example/snippets/MainActivity.kt new file mode 100644 index 000000000..0fdfeab64 --- /dev/null +++ b/ai/src/main/java/com/example/snippets/MainActivity.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2024 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.example.snippets + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.ui.Modifier +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.example.snippets.navigation.Destination +import com.example.snippets.navigation.LandingScreen +import com.example.snippets.ui.theme.SnippetsTheme +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class MainActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + SnippetsTheme { + val navController = rememberNavController() + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + NavHost(navController, startDestination = "LandingScreen") { + composable("LandingScreen") { + LandingScreen { navController.navigate(it.route) } + } + } + } + } + } + } +} diff --git a/misc/src/main/java/com/example/snippets/ai/AppFunctionsApiSnippets.kt b/ai/src/main/java/com/example/snippets/ai/AppFunctionsApiSnippets.kt similarity index 100% rename from misc/src/main/java/com/example/snippets/ai/AppFunctionsApiSnippets.kt rename to ai/src/main/java/com/example/snippets/ai/AppFunctionsApiSnippets.kt diff --git a/misc/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippets.kt b/ai/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippets.kt similarity index 100% rename from misc/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippets.kt rename to ai/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippets.kt diff --git a/misc/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippetsJava.java b/ai/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippetsJava.java similarity index 100% rename from misc/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippetsJava.java rename to ai/src/main/java/com/example/snippets/ai/GeminiDeveloperApiSnippetsJava.java diff --git a/misc/src/main/java/com/example/snippets/ai/GeminiOverview.kt b/ai/src/main/java/com/example/snippets/ai/GeminiOverview.kt similarity index 100% rename from misc/src/main/java/com/example/snippets/ai/GeminiOverview.kt rename to ai/src/main/java/com/example/snippets/ai/GeminiOverview.kt diff --git a/misc/src/main/java/com/example/snippets/ai/GeminiOverviewJava.java b/ai/src/main/java/com/example/snippets/ai/GeminiOverviewJava.java similarity index 100% rename from misc/src/main/java/com/example/snippets/ai/GeminiOverviewJava.java rename to ai/src/main/java/com/example/snippets/ai/GeminiOverviewJava.java diff --git a/misc/src/main/java/com/example/snippets/ai/ImagenSnippets.kt b/ai/src/main/java/com/example/snippets/ai/ImagenSnippets.kt similarity index 100% rename from misc/src/main/java/com/example/snippets/ai/ImagenSnippets.kt rename to ai/src/main/java/com/example/snippets/ai/ImagenSnippets.kt diff --git a/misc/src/main/java/com/example/snippets/ai/ImagenSnippetsJava.java b/ai/src/main/java/com/example/snippets/ai/ImagenSnippetsJava.java similarity index 100% rename from misc/src/main/java/com/example/snippets/ai/ImagenSnippetsJava.java rename to ai/src/main/java/com/example/snippets/ai/ImagenSnippetsJava.java diff --git a/misc/src/main/java/com/example/snippets/ai/VertexAiGeminiApi.kt b/ai/src/main/java/com/example/snippets/ai/VertexAiGeminiApi.kt similarity index 100% rename from misc/src/main/java/com/example/snippets/ai/VertexAiGeminiApi.kt rename to ai/src/main/java/com/example/snippets/ai/VertexAiGeminiApi.kt diff --git a/misc/src/main/java/com/example/snippets/ai/VertexAiGeminiApiJava.java b/ai/src/main/java/com/example/snippets/ai/VertexAiGeminiApiJava.java similarity index 100% rename from misc/src/main/java/com/example/snippets/ai/VertexAiGeminiApiJava.java rename to ai/src/main/java/com/example/snippets/ai/VertexAiGeminiApiJava.java diff --git a/ai/src/main/java/com/example/snippets/navigation/Destination.kt b/ai/src/main/java/com/example/snippets/navigation/Destination.kt new file mode 100644 index 000000000..64c44f400 --- /dev/null +++ b/ai/src/main/java/com/example/snippets/navigation/Destination.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 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.example.snippets.navigation + +enum class Destination(val route: String, val title: String) { + // Add your example here +} diff --git a/ai/src/main/java/com/example/snippets/navigation/LandingScreen.kt b/ai/src/main/java/com/example/snippets/navigation/LandingScreen.kt new file mode 100644 index 000000000..f096906dd --- /dev/null +++ b/ai/src/main/java/com/example/snippets/navigation/LandingScreen.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2024 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.example.snippets.navigation + +/* + * 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. + */ + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ListItem +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun LandingScreen( + navigate: (Destination) -> Unit +) { + Scaffold( + topBar = { + TopAppBar(title = { + Text(text = "Android snippets",) + }) + } + ) { padding -> + NavigationItems(modifier = Modifier.padding(padding)) { navigate(it) } + } +} + +@Composable +fun NavigationItems( + modifier: Modifier = Modifier, + navigate: (Destination) -> Unit +) { + LazyColumn( + modifier = modifier + .fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + items(Destination.entries) { destination -> + NavigationItem(destination) { + navigate( + destination + ) + } + } + } +} + +@Composable +fun NavigationItem(destination: Destination, onClick: () -> Unit) { + ListItem( + headlineContent = { + Text(destination.title) + }, + modifier = Modifier + .heightIn(min = 48.dp) + .clickable { + onClick() + } + ) +} diff --git a/ai/src/main/java/com/example/snippets/ui/theme/Color.kt b/ai/src/main/java/com/example/snippets/ui/theme/Color.kt new file mode 100644 index 000000000..662ef48ff --- /dev/null +++ b/ai/src/main/java/com/example/snippets/ui/theme/Color.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2024 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.example.snippets.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) diff --git a/ai/src/main/java/com/example/snippets/ui/theme/Theme.kt b/ai/src/main/java/com/example/snippets/ui/theme/Theme.kt new file mode 100644 index 000000000..4dcf62e85 --- /dev/null +++ b/ai/src/main/java/com/example/snippets/ui/theme/Theme.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2024 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.example.snippets.ui.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun SnippetsTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} diff --git a/ai/src/main/java/com/example/snippets/ui/theme/Type.kt b/ai/src/main/java/com/example/snippets/ui/theme/Type.kt new file mode 100644 index 000000000..db2e63291 --- /dev/null +++ b/ai/src/main/java/com/example/snippets/ui/theme/Type.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2024 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.example.snippets.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) diff --git a/ai/src/main/res/drawable/ic_launcher_background.xml b/ai/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..e6202fbb1 --- /dev/null +++ b/ai/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ai/src/main/res/drawable/ic_launcher_foreground.xml b/ai/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000..8760078c8 --- /dev/null +++ b/ai/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + diff --git a/ai/src/main/res/drawable/scones.xml b/ai/src/main/res/drawable/scones.xml new file mode 100644 index 000000000..2eafb40af --- /dev/null +++ b/ai/src/main/res/drawable/scones.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/ai/src/main/res/layout/activity_main.xml b/ai/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..778d7a011 --- /dev/null +++ b/ai/src/main/res/layout/activity_main.xml @@ -0,0 +1,54 @@ + + + + +