Skip to content

Instantly share code, notes, and snippets.

@ioannisa
Last active June 14, 2024 08:43
Show Gist options
  • Save ioannisa/2f674098e20da5f0ef0747b529b129a6 to your computer and use it in GitHub Desktop.
Save ioannisa/2f674098e20da5f0ef0747b529b129a6 to your computer and use it in GitHub Desktop.
Jetpack Navigation passing Parcelables through backstack's savedState handle (old way)
package eu.anifantakis.composeapp
import android.os.Bundle
import android.os.Parcelable
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import coil.compose.rememberAsyncImagePainter
import eu.anifantakis.composeapp.ui.theme.ComposeAppTheme
import kotlinx.parcelize.Parcelize
import java.net.URLDecoder
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
// =========================[ NOTE ]=========================
// add Coil for Jetpack Compose at your app dependencies
// implementation("io.coil-kt:coil-compose:2.6.0")
//
// Add Parcelize plugin at app module's build.gradle
// id("kotlin-parcelize")
// ==========================================================
// define a simple data class to hold Person information
@Parcelize
data class Person(
val id: Int,
val section: Int,
val name: String,
val imageUrl: String,
val landingPage: String
): Parcelable
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val persons = arrayListOf<Person>() // create an array list of persons
var section = 1
for (i in 1..200){ // create 200 Person instances in that list
if (i%15 == 0){
section++
}
persons.add(
Person(
id = i,
section = section, // all persons are assigned section
name = "Ioannis Anifantakis",
imageUrl = URLEncoder.encode("https://anifantakis.eu/wp-content/uploads/2021/05/ioannis-anifantakis-firebase-small.jpg", StandardCharsets.UTF_8.toString()),
landingPage = URLEncoder.encode("https://anifantakis.eu", StandardCharsets.UTF_8.toString())
)
)
}
setContent {
ComposeAppTheme {
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colorScheme.background) {
Navigation(persons)
}
}
}
}
}
@Composable
fun Navigation(persons: List<Person>) {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "main_screen" ) {
composable("main_screen") { MainScreen(persons, navController) }
composable("detail_screen") {
val person = navController.previousBackStackEntry?.savedStateHandle?.get<Person>("person")
person?.let {
DetailScreen(navController, it)
}
}
}
}
@Composable
fun ImageLoader(imageUrl: String){
Image(
painter = rememberAsyncImagePainter(imageUrl),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.size(120.dp)
)
}
@Composable
fun ListItem(person: Person, navController: NavController){
Card(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
.clickable {
navController.currentBackStackEntry?.savedStateHandle?.set("person", person)
navController.navigate("detail_screen")
},
elevation = CardDefaults.cardElevation(),
) {
Row{
ImageLoader(URLDecoder.decode(person.imageUrl, StandardCharsets.UTF_8.toString()))
Spacer(modifier = Modifier.width(8.dp))
Text(
person.name+' '+person.id,
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.padding(8.dp)
)
}
}
}
@Composable
fun DetailScreen(navController: NavController, person: Person) {
Card (
modifier = Modifier.padding(12.dp),
elevation = CardDefaults.cardElevation(),
){
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
) {
Text("section ${person.section}", style = MaterialTheme.typography.headlineMedium)
Text("${person.name} ${person.id}", style = MaterialTheme.typography.headlineSmall)
Spacer(modifier = Modifier.height(8.dp))
ImageLoader(person.imageUrl)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = { navController.popBackStack() }) {
Text("Go Back")
}
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MainScreen(persons: List<Person>, navController: NavController){
val grouped = persons.groupBy{it.section}
LazyColumn(){
grouped.forEach { (section, sectionPersons) ->
stickyHeader {
Text(
text = "SECTION: $section",
color = Color.White,
modifier = Modifier
.background(color = Color.Black)
.padding(8.dp)
.fillMaxWidth()
)
}
items(
items = sectionPersons,
itemContent = {
ListItem(it, navController)
}
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment