Skip to content

#4 state of composable #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: #1_composable_function_info
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 118 additions & 22 deletions app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,144 @@ package com.lahsuak.apps.jetpackcomposebasic
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.lahsuak.apps.jetpackcomposebasic.ui.theme.JetPackComposeBasicTheme

/**
* In Composable functions, state that is read or modified by multiple functions
should live in a common ancestor—this process is called state hoisting.
To hoist means to lift or elevate.

* Making state hoistable avoids duplicating state and introducing bugs,
helps reuse composables, and makes composables substantially easier to test.
Contrarily, state that doesn't need to be controlled by a composable's parent should not be hoisted.
The source of truth belongs to whoever creates and controls that state.
**/

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
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")
}
MyApp(modifier = Modifier.fillMaxSize())
}
}
}
}
/***
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.
***/

@Composable
fun MyApp(modifier: Modifier = Modifier) {
// shouldShowOnboarding is using a by keyword instead of the =.
// This is a property delegate that saves you from typing .value every time.
var shouldShowOnboarding by remember { mutableStateOf(true) }

Surface(modifier) {
if (shouldShowOnboarding) {
OnboardingScreen(onContinueClicked = { shouldShowOnboarding = false })
} else {
Greetings()
}
}
}

/**
* "State" and "MutableState" are interfaces that hold some value
and trigger UI updates (recompositions) whenever that value changes.
However you can't just assign mutableStateOf to a variable inside a composable.
* As explained before, recomposition can happen at any time which would call the composable again,
resetting the state to a new mutable state with a value of false.
* To preserve state across recompositions, remember the mutable state using "remember".
remember is used to guard against recomposition, so the state is not reset.
*/

@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
val expanded = remember { mutableStateOf(false) }

val extraPadding = if (expanded.value) 48.dp else 0.dp

Surface(
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
) {
Row(modifier = Modifier.padding(24.dp)) {
Column(
modifier = Modifier
.weight(1f)
.padding(bottom = extraPadding)
) {
Text(text = "Hello,")
Text(text = name)
}
ElevatedButton(
onClick = { expanded.value = !expanded.value }
) {
Text(if (expanded.value) "Show less" else "Show more")
}
}
}
}

@Composable
private fun Greetings(
modifier: Modifier = Modifier,
names: List<String> = listOf("World", "Kaushal")
) {
Column(modifier = modifier.padding(vertical = 4.dp)) {
for (name in names) {
Greeting(name = name)
}
}
}

@Preview(showBackground = true)
// add new on-boarding screen
@Composable
fun OnboardingScreen(
onContinueClicked: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Welcome to the Basics Codelab!")
Button(
modifier = Modifier.padding(vertical = 24.dp),
onClick = onContinueClicked
) {
Text("Continue")
}
}
}

@Preview(showBackground = true, widthDp = 320)
@Composable
fun DefaultPreview() {
JetPackComposeBasicTheme {
Greeting("Android")
Greetings()
}
}

@Preview(showBackground = true, widthDp = 320, heightDp = 320)
@Composable
fun OnboardingPreview() {
JetPackComposeBasicTheme {
OnboardingScreen(onContinueClicked = {})
}
}

@Preview
@Composable
fun MyAppPreview() {
JetPackComposeBasicTheme {
MyApp(Modifier.fillMaxSize())
}
}