diff --git a/README.md b/README.md new file mode 100644 index 0000000..e97a475 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ + +# Video +https://github.com/KaushalVasava/JetPackCompose_Basic/assets/49050597/3dae189f-f616-49dd-95fc-14a63d56d1fa + diff --git a/app/build.gradle b/app/build.gradle index 75677b5..269b35a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,12 +5,12 @@ plugins { android { namespace 'com.lahsuak.apps.jetpackcomposebasic' - compileSdk 33 + compileSdk 34 defaultConfig { applicationId "com.lahsuak.apps.jetpackcomposebasic" minSdk 23 - targetSdk 33 + targetSdk 34 versionCode 1 versionName "1.0" @@ -27,17 +27,17 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '17' } buildFeatures { compose true } composeOptions { - kotlinCompilerExtensionVersion '1.1.1' + kotlinCompilerExtensionVersion '1.5.4' } packagingOptions { resources { @@ -48,16 +48,23 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.9.0' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' - implementation 'androidx.activity:activity-compose:1.6.1' - implementation "androidx.compose.ui:ui:$compose_version" - implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" - implementation 'androidx.compose.material3:material3:1.1.0-alpha03' + 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:2024.03.00")) + implementation "androidx.compose.ui:ui" + 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.4' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' - androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" - debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" - debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation "androidx.compose.ui:ui-test-junit4" + debugImplementation "androidx.compose.ui:ui-tooling" + debugImplementation "androidx.compose.ui:ui-test-manifest" + + + implementation "androidx.navigation:navigation-compose:2.7.7" + implementation("androidx.compose.animation:animation:1.7.0-SNAPSHOT") } \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt index 187ee32..bb65757 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt @@ -1,15 +1,56 @@ +@file:OptIn(ExperimentalSharedTransitionApi::class) + package com.lahsuak.apps.jetpackcomposebasic +import android.annotation.SuppressLint import android.os.Bundle +import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.ExperimentalSharedTransitionApi +import androidx.compose.animation.SharedTransitionLayout +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +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.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar 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.tooling.preview.Preview +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument import com.lahsuak.apps.jetpackcomposebasic.ui.theme.JetPackComposeBasicTheme class MainActivity : ComponentActivity() { @@ -17,34 +58,257 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { JetPackComposeBasicTheme { - // A surface container using the 'background' color from the theme Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - Greeting("Android") + ListToDetailsDemo() +// AppNavHost(rememberNavController()) } } } } } -/*** -Composable functions : -A composable function is a regular function annotated with @Composable. -This enables your function to call other @Composable functions within it. -You can see how the Greeting function is marked as @Composable. -This function will produce a piece of UI hierarchy displaying the given input, -String. Text is a composable function provided by the library. -***/ +sealed class Screen { + data object List : Screen() + class Details(val item: Int) : Screen() +} + +@OptIn(ExperimentalMaterial3Api::class) @Composable -fun Greeting(name: String) { - Text(text = "Hello $name!") +fun ListToDetailsDemo(modifier: Modifier = Modifier) { + var state: Screen by remember { + mutableStateOf(Screen.List) + } + val images = listOf( + R.drawable.s_1, + R.drawable.s_2, + R.drawable.s_3, + R.drawable.s_6, + R.drawable.s_7, + R.drawable.s_8 + ) + SharedTransitionLayout(modifier = modifier.fillMaxSize()) { + AnimatedContent( + state, + label = "", + contentKey = { it.javaClass }, + transitionSpec = { + if (initialState == Screen.List) { + slideInHorizontally { -it } + fadeIn() togetherWith slideOutHorizontally { it } + fadeOut() + } else { + slideInHorizontally { it } + fadeIn() togetherWith slideOutHorizontally { -it } + fadeOut() + } + }, + ) { + when (it) { + Screen.List -> { + LazyColumn { + items(50) { item -> + Row( + modifier = Modifier + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + ) { + state = Screen.Details(item) + } + .fillMaxWidth(), + ) { + Image( + painter = painterResource(images[item % 6]), + modifier = Modifier + .size(100.dp) + .then( + Modifier.sharedElement( + rememberSharedContentState( + key = "item-image$item", + ), + this@AnimatedContent, + ) + ), + contentScale = ContentScale.Crop, + contentDescription = null, + ) + Spacer(Modifier.size(15.dp)) + Text("Item $item") + } + } + } + } + + is Screen.Details -> { + val item = it.item + Column( + modifier = Modifier + .fillMaxSize() + ) { + Row { + TopAppBar(title = { Text("Item $item") }, navigationIcon = { + IconButton(onClick = { state = Screen.List }) { + Icon(Icons.Default.ArrowBack, "back") + } + }) + } + Image( + painter = painterResource(images[item % 6]), + modifier = Modifier + .then( + Modifier.sharedElement( + rememberSharedContentState(key = "item-image$item"), + this@AnimatedContent, + ), + ) + .fillMaxWidth(), + contentScale = ContentScale.Crop, + contentDescription = null, + ) + Text( + "Item $item", + fontSize = 23.sp, + ) + } + } + } + } + } } -@Preview(showBackground = true) +// THIS Code using Navigation API but currently it does not animate + @Composable -fun DefaultPreview() { - JetPackComposeBasicTheme { - Greeting("Android") +fun AppNavHost(navHostController: NavHostController) { + NavHost(navController = navHostController, startDestination = "home") { + composable("home") { + HomeScreen(navHostController) + } + composable("details/{id}", + arguments = listOf( + navArgument("id") { + type = NavType.IntType + } + )) { + val id = it.arguments?.getInt("id") + if (id != null) { + DetailScreen(navController = navHostController, item = id) + } + } } -} \ No newline at end of file +} + +@SuppressLint("UnusedContentLambdaTargetStateParameter") +@Composable +fun HomeScreen(navController: NavHostController) { + val navBackStackEntry by navController.currentBackStackEntryAsState() + val images = listOf( + R.drawable.s_1, + R.drawable.s_2, + R.drawable.s_3, + R.drawable.s_6, + R.drawable.s_7, + R.drawable.s_8 + ) + SharedTransitionLayout(modifier = Modifier.fillMaxSize()) { + AnimatedContent( + if (navBackStackEntry != null) { + navBackStackEntry?.destination?.route == "home" + } else { + true + }, + label = "", + contentKey = { it.javaClass }, + transitionSpec = { + slideInHorizontally { -it } + fadeIn() togetherWith slideOutHorizontally { it } + fadeOut() + } + ) { + LazyColumn { + items(50) { item -> + Row( + modifier = Modifier + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + ) { + navController.navigate("details/$item") + Screen.Details(item) + } + .fillMaxWidth(), + ) { + Image( + painter = painterResource(images[item % 6]), + modifier = Modifier + .size(100.dp) + .then( + Modifier.sharedElement( + rememberSharedContentState( + key = "item-image$item", + ), + this@AnimatedContent, + ) + ), + contentScale = ContentScale.Crop, + contentDescription = null, + ) + Spacer(Modifier.size(15.dp)) + Text("Item $item") + } + } + } + } + } +} + +@SuppressLint("UnusedContentLambdaTargetStateParameter") +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DetailScreen(navController: NavHostController, item: Int) { + val images = listOf( + R.drawable.s_1, + R.drawable.s_2, + R.drawable.s_3, + R.drawable.s_6, + R.drawable.s_7, + R.drawable.s_8 + ) + Log.d("TAG", "DetailScreen: ${navController.currentBackStackEntry?.destination?.route}") + SharedTransitionLayout(modifier = Modifier.fillMaxSize()) { + AnimatedContent( + navController.currentBackStackEntry?.destination?.route == "details/{id}", + label = "", + contentKey = { it.javaClass }, + transitionSpec = { + slideInHorizontally { it } + fadeIn() togetherWith slideOutHorizontally { -it } + fadeOut() + } + ) { + Column( + modifier = Modifier + .fillMaxSize() + ) { + Row { + TopAppBar(title = { Text("Item $item") }, navigationIcon = { + IconButton(onClick = { navController.popBackStack() }) { + Icon(Icons.Default.ArrowBack, "back") + } + }) + } + Image( + painter = painterResource(images[item % 6]), + modifier = Modifier + .then( + Modifier.sharedElement( + rememberSharedContentState(key = "item-image$item"), + this@AnimatedContent, + ), + ) + .fillMaxWidth(), + contentScale = ContentScale.Crop, + contentDescription = null, + ) + Text( + "Item $item", + fontSize = 23.sp, + ) + } + } + } +} diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/NavigationItem.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/NavigationItem.kt new file mode 100644 index 0000000..db0615c --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/NavigationItem.kt @@ -0,0 +1,2 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.screen + diff --git a/app/src/main/res/drawable/s_1.png b/app/src/main/res/drawable/s_1.png new file mode 100644 index 0000000..6c8e502 Binary files /dev/null and b/app/src/main/res/drawable/s_1.png differ diff --git a/app/src/main/res/drawable/s_2.png b/app/src/main/res/drawable/s_2.png new file mode 100644 index 0000000..9bd590f Binary files /dev/null and b/app/src/main/res/drawable/s_2.png differ diff --git a/app/src/main/res/drawable/s_3.png b/app/src/main/res/drawable/s_3.png new file mode 100644 index 0000000..9f82c0b Binary files /dev/null and b/app/src/main/res/drawable/s_3.png differ diff --git a/app/src/main/res/drawable/s_6.png b/app/src/main/res/drawable/s_6.png new file mode 100644 index 0000000..c81dad8 Binary files /dev/null and b/app/src/main/res/drawable/s_6.png differ diff --git a/app/src/main/res/drawable/s_7.png b/app/src/main/res/drawable/s_7.png new file mode 100644 index 0000000..a853d5c Binary files /dev/null and b/app/src/main/res/drawable/s_7.png differ diff --git a/app/src/main/res/drawable/s_8.png b/app/src/main/res/drawable/s_8.png new file mode 100644 index 0000000..b3626d6 Binary files /dev/null and b/app/src/main/res/drawable/s_8.png differ diff --git a/build.gradle b/build.gradle index e868fc8..1208330 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,10 @@ buildscript { ext { - compose_version = '1.3.2' + compose_version = '1.5.4' } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '7.3.0' apply false - id 'com.android.library' version '7.3.0' apply false - id 'org.jetbrains.kotlin.android' version '1.6.10' apply false + id 'com.android.application' version '8.1.0' apply false + id 'com.android.library' version '8.1.0' apply false + id 'org.jetbrains.kotlin.android' version '1.9.20' apply false } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index d9ed244..70f08ac 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,6 +10,9 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url = uri("https://androidx.dev/snapshots/builds/11670047/artifacts/repository/") } + maven {url = "https://plugins.gradle.org/m2/" } + maven { url = "https://maven.pkg.jetbrains.space/public/p/compose/dev" } } } rootProject.name = "JetPackCompose Basic"