diff --git a/.idea/other.xml b/.idea/other.xml new file mode 100644 index 0000000..4604c44 --- /dev/null +++ b/.idea/other.xml @@ -0,0 +1,252 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 5cf5e0d..c6c2d08 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,24 @@ -# Compose Sample -This simple app shows how to create a chat screen in compose this repo is bases on compose basic in official android page +# Compose Code Examples +In this repository you can find multiple basic compose codelab app samples all +samples are divided into corresponding branches. -### Note 👀 +### code-along-demo -**This App doesn't focus on Building Modern Material Ui the UI looks clean** \ No newline at end of file +**In this branch we build very simple ```Scrollable List using LazyColumn with animation``` in compose Link to +official [Compose Tutorial](https://developer.android.com/develop/ui/compose/tutorial)** + +![List](Screenshots/scrollable_list.png) + +### compose-layout + +**In this branch we will learn how to build a ```complex layouts``` in compose +Link to official [codelab](https://developer.android.com/codelabs/jetpack-compose-layouts)** + +![Compose Layouts](Screenshots/compose_layout.png) + +### compose-state + +**In this branch we will digger deeper into ```compose state``` Link to +official [codelab](https://developer.android.com/codelabs/jetpack-compose-state)** + +![Compose State](Screenshots/state_in_compose.png) \ No newline at end of file diff --git a/Screenshots/compose_layout.png b/Screenshots/compose_layout.png new file mode 100644 index 0000000..8d34d99 Binary files /dev/null and b/Screenshots/compose_layout.png differ diff --git a/Screenshots/scrollable_list.png b/Screenshots/scrollable_list.png new file mode 100644 index 0000000..4402dd9 Binary files /dev/null and b/Screenshots/scrollable_list.png differ diff --git a/Screenshots/state_in_compose.png b/Screenshots/state_in_compose.png new file mode 100644 index 0000000..139fc55 Binary files /dev/null and b/Screenshots/state_in_compose.png differ diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 76eeaf8..3ee86a0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { - id("com.android.application") - id("org.jetbrains.kotlin.android") + alias(libs.plugins.android.application) + alias(libs.plugins.jetbrains.kotlin.android) + alias(libs.plugins.kotlin.serialization) } android { @@ -9,7 +10,7 @@ android { defaultConfig { applicationId = "com.example.composeexample" - minSdk = 24 + minSdk = 21 targetSdk = 34 versionCode = 1 versionName = "1.0" @@ -51,19 +52,34 @@ android { dependencies { - implementation("androidx.core:core-ktx:1.12.0") - implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0") - implementation("androidx.activity:activity-compose:1.8.2") - implementation(platform("androidx.compose:compose-bom:2023.08.00")) - implementation("androidx.compose.ui:ui") - implementation("androidx.compose.ui:ui-graphics") - implementation("androidx.compose.ui:ui-tooling-preview") - implementation("androidx.compose.material3:material3") - testImplementation("junit:junit:4.13.2") - androidTestImplementation("androidx.test.ext:junit:1.1.5") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") - androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00")) - androidTestImplementation("androidx.compose.ui:ui-test-junit4") - debugImplementation("androidx.compose.ui:ui-tooling") - debugImplementation("androidx.compose.ui:ui-test-manifest") -} \ No newline at end of file + // Core UI + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + + // Unit Test + testImplementation(libs.junit) + + // Compose Navigation + implementation(libs.androidx.navigation.compose) + + // Kotlinx-Serialization + implementation(libs.kotlinx.serialization.json) + + // Material Icon extended + implementation(libs.androidx.material.icons.extended) + + // Instrumental Test + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.ui.test.junit4) + + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} diff --git a/app/src/main/java/com/example/composeexample/MainActivity.kt b/app/src/main/java/com/example/composeexample/MainActivity.kt index 0e40311..e7cedb7 100644 --- a/app/src/main/java/com/example/composeexample/MainActivity.kt +++ b/app/src/main/java/com/example/composeexample/MainActivity.kt @@ -1,143 +1,64 @@ package com.example.composeexample -import android.content.res.Configuration import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.animation.animateColorAsState -import androidx.compose.animation.animateContentSize -import androidx.compose.foundation.Image -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text 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.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.example.composeexample.data.SampleData +import androidx.compose.ui.unit.sp import com.example.composeexample.ui.theme.ComposeExampleTheme +/** CompositionLocal allows you to create tree-scoped named objects that can be used as an implicit way of passing data to the composable UI tree + * rather than passing data explicitly to those composable that want data by using composable function + * parameters */ + class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableEdgeToEdge() setContent { ComposeExampleTheme { - Surface( - Modifier.fillMaxSize() - ) { - // MessageCard(message = Message("Mbyt", "developer")) - Conversation(message = SampleData.conversationSample) - } - } - } - } -} - -data class Message(val author: String, val body: String) - -@Composable -fun MessageCard(message: Message) { - - Row(Modifier.padding(all = 8.dp)) { - Image( - painter = painterResource(id = R.drawable.nature_pic), - contentDescription = "userImage", - modifier = Modifier - .size(60.dp) - .clip(CircleShape) - .border( - 1.5.dp, - MaterialTheme.colorScheme.inversePrimary, - MaterialTheme.shapes.medium - ), - contentScale = ContentScale.FillWidth, - - ) - - var isExpanded by remember { mutableStateOf(false) } - // surfaceColor will be updated gradually from one color to the other - val surfaceColor by animateColorAsState( - if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface, - ) + val system = if (isSystemInDarkTheme()) { + System("Dark Theme") + } else System("Light Theme") // conditionally change the value of the System - Spacer(modifier = Modifier.size(12.dp)) - - Column(Modifier.clickable { isExpanded = !isExpanded }){ // column place the child item in horizontal - Text( - text = message.author, - color = MaterialTheme.colorScheme.primary, - style = MaterialTheme.typography.titleSmall - ) + Scaffold { + CompositionLocalProvider(LocalSystem provides system) { // provides the conditionally changing (system) value to the key of the compositionLocal + SystemDetail(modifier = Modifier.padding(it)) + } + } - Surface( - shape = MaterialTheme.shapes.medium, - shadowElevation = 1.dp, - // surfaceColor color will be changing gradually from primary to surface - color = surfaceColor, - // animateContentSize will change the Surface size gradually - modifier = Modifier - .animateContentSize() - .padding(1.dp) - ) { - Text( - text = message.body, - maxLines = if (isExpanded) Int.MAX_VALUE else 1, - modifier = Modifier.padding(4.dp), - style = MaterialTheme.typography.bodyMedium - ) } - - } - } -} - -@Preview("Light Mode") -@Preview( - uiMode = Configuration.UI_MODE_NIGHT_YES, - showBackground = true, - name = "Night mode" -) -@Composable -fun PrevCard() { - ComposeExampleTheme { - Surface { - MessageCard(message = Message("Mb", "Developer")) } - } } @Composable -fun Conversation(message: List) { - LazyColumn { - items(message) { - MessageCard(message = it) - } +fun SystemDetail(modifier: Modifier = Modifier) { + Column( + modifier = modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = LocalSystem.current.theme, fontSize = 20.sp) } } -@Preview +@Preview(showBackground = true) @Composable -fun PreviewConversation() { - Surface { - Conversation(message = SampleData.conversationSample) +private fun UserDetailPreview() { + ComposeExampleTheme { + SystemDetail() } } \ No newline at end of file diff --git a/app/src/main/java/com/example/composeexample/System.kt b/app/src/main/java/com/example/composeexample/System.kt new file mode 100644 index 0000000..38260d0 --- /dev/null +++ b/app/src/main/java/com/example/composeexample/System.kt @@ -0,0 +1,12 @@ +package com.example.composeexample + +import androidx.compose.runtime.compositionLocalOf + +data class System(val theme: String = "Light") + +val LocalSystem = compositionLocalOf { System() } // must be declared in top level of the class/file so the composable can access it and also +// providing default value is good practise that helps us to showing previews in the IDE and creating a test + +// TODO: here we using [compositionLocalOf] Changing the value here (isSystemInDarkTheme) invalidates only the content that reads its current value here the [Text composable]. +// TODO: by using [staticCompositionLocalOf] the reads are not tracked by composable, By changing in the value here conditionally (isSystemInDarkTheme) the entire content lambda in a CompositionLocalProvider] +// will be recomposed instead of current value reads in a [compositionLocalOf] \ No newline at end of file diff --git a/app/src/main/java/com/example/composeexample/data/SampleData.kt b/app/src/main/java/com/example/composeexample/data/SampleData.kt deleted file mode 100644 index 3447738..0000000 --- a/app/src/main/java/com/example/composeexample/data/SampleData.kt +++ /dev/null @@ -1,129 +0,0 @@ -package com.example.composeexample.data - -import com.example.composeexample.Message - -/** - * SampleData for Jetpack Compose Tutorial - */ -object SampleData { - // Sample conversation data - val conversationSample = listOf( - Message( - "Lexi", - "Test...Test...Test..." - ), - Message( - "Lexi", - """List of Android versions: - |Android KitKat (API 19) - |Android Lollipop (API 21) - |Android Marshmallow (API 23) - |Android Nougat (API 24) - |Android Oreo (API 26) - |Android Pie (API 28) - |Android 10 (API 29) - |Android 11 (API 30) - |Android 12 (API 31)""".trim() - ), - Message( - "Lexi", - """I think Kotlin is my favorite programming language. - |It's so much fun!""".trim() - ), - Message( - "Lexi", - "Searching for alternatives to XML layouts..." - ), - Message( - "Lexi", - """Hey, take a look at Jetpack Compose, it's great! - |It's the Android's modern toolkit for building native UI. - |It simplifies and accelerates UI development on Android. - |Less code, powerful tools, and intuitive Kotlin APIs :)""".trim() - ), - Message( - "Lexi", - "It's available from API 21+ :)" - ), - Message( - "Lexi", - "Writing Kotlin for UI seems so natural, Compose where have you been all my life?" - ), - Message( - "Lexi", - "Android Studio next version's name is Arctic Fox" - ), - Message( - "Lexi", - "Android Studio Arctic Fox tooling for Compose is top notch ^_^" - ), - Message( - "Lexi", - "I didn't know you can now run the emulator directly from Android Studio" - ), - Message( - "Lexi", - "Compose Previews are great to check quickly how a composable layout looks like" - ), - Message( - "Lexi", - "Previews are also interactive after enabling the experimental setting" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Have you tried writing build.gradle with KTS?" - ), - Message( - "Lexi", - "Kapt is deprecated" - ), - Message( - "Android", - "Have you tried writing build.gradle with KTS?" - ), - ) -} diff --git a/app/src/main/java/com/example/composeexample/ui/theme/Theme.kt b/app/src/main/java/com/example/composeexample/ui/theme/Theme.kt index 9e28e0b..9844874 100644 --- a/app/src/main/java/com/example/composeexample/ui/theme/Theme.kt +++ b/app/src/main/java/com/example/composeexample/ui/theme/Theme.kt @@ -26,15 +26,15 @@ private val LightColorScheme = lightColorScheme( secondary = PurpleGrey40, tertiary = Pink40 - /* Other default colors to override + /* // 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), - */ + onSurface = Color(0xFF1C1B1F),*/ + ) @Composable diff --git a/app/src/main/res/drawable/nature_pic.jpg b/app/src/main/res/drawable/nature_pic.jpg deleted file mode 100644 index 091797a..0000000 Binary files a/app/src/main/res/drawable/nature_pic.jpg and /dev/null differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0edc2d4..7415591 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,14 @@ Compose Example + Show more + Show less + IOS Platform + Platform Independent + Programmer\'s Best friend + Game Development + JVM language + Data Science + Superset set of JS + Top languages + Most Popular \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 4645626..f74b04b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.2.2" apply false - id("org.jetbrains.kotlin.android") version "1.9.0" apply false + alias(libs.plugins.android.application) apply false + alias(libs.plugins.jetbrains.kotlin.android) apply false } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..ea7eb38 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,37 @@ +[versions] +agp = "8.4.0" +kotlin = "1.9.0" +coreKtx = "1.13.1" +junit = "4.13.2" +junitVersion = "1.1.5" +espressoCore = "3.5.1" +serializationVersion = "1.6.3" +lifecycleRuntimeKtx = "2.8.0" +activityCompose = "1.9.0" +composeBom = "2023.08.00" +navigationCompose = "2.8.0-beta02" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" } +androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serializationVersion" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 135bd5f..7a0226b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon Feb 05 14:11:33 IST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists