> For the complete documentation index, see [llms.txt](https://pawelwlodarski.gitbook.io/android/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pawelwlodarski.gitbook.io/android/compose-workshop/compose-gui.md).

# Compose - GUI

a**New Application with defined application composable**

```
@Composable
fun SomeGuiApplication(){
    ComposeWorkshopsTheme {
            UserList()
        }
    }
}

@Composable
fun UserList(){
//at this point user repository is hardcoded
    val users=UsersRepository.select() 
    users.forEach{
        Text("User ${it.name} ")
    }
}
```

**change background with surface**

```
ComposeWorkshopsTheme {
        Surface(color = Color.Yellow) {
            UserList()
        }
    }
```

**format user list with column**

```
 Column(
        verticalArrangement = Arrangement.Center // just check possibilities in the code
    ) {
        users.forEach {
            Text(
                text = "User : ${it.name} ",
                modifier = Modifier.padding(1.dp),
            )
        }
    }
```

**make text clickable**

```
Modifier
                    .padding(1.dp)
                    .clickable { Toast.makeText(context, "user clicked ${it.name}",Toast.LENGTH_LONG).show() }
```

**modifiers order**

show difference between&#x20;

```
Modifier
                    .padding(30.dp)
                    .clickable { Toast.makeText(context, "user clicked ${it.name}",Toast.LENGTH_LONG).show() }
```

and:

```
     Modifier
                    .clickable { Toast.makeText(context, "user clicked ${it.name}",Toast.LENGTH_LONG).show() }
                    .padding(30.dp)
```

## Scaffold

**First attempt**

```
@Composable
fun SomeGuiApplication() {
    ComposeWorkshopsTheme {
        Surface(color = Color.Yellow) {
            AppBody()
        }
    }
}

@Composable
fun AppBody(){
    Scaffold {
        UserList()
    }
}
```

**Better composition structure**

```
@Composable
fun SomeGuiApplication() {
    ComposeWorkshopsTheme {
        Scaffold {
            AppBody()
        }
    }
}

@Composable
fun AppBody(){
    Surface(color = Color.Yellow) {
        UserList()
    }
}
```

**Top Bar**

```
@Composable
fun SomeGuiApplication() {
    ComposeWorkshopsTheme {
        Scaffold(
            topBar = { topBar() } // waith for kotlin 1.6
        ) {
            AppBody()
        }
    }
}
```

**Top Bar Compsable - first variant**&#x20;

```
@Composable
fun topBar(){
    TopAppBar() {
        Text(
            text = "Some AppTitle",
            style = MaterialTheme.typography.h3
        )
    }
}
```

**Top Bar Composable - Second variant**

* There is a second variant of *TopAppBar* function and you can not use function syntax with it!
* to make code more readable you may want to extract some function definitions
  * remember about @Composable annotation before function definitions
  * (to me: during workshops explain topBarActions syntax)

```
@Composable
fun topBar(){
    val appTitle= @Composable {
        Text(
            text = "Some AppTitle",
            style = MaterialTheme.typography.h3
        )
    }

    val topBarActions: @Composable RowScope.() -> Unit ={
            IconButton(onClick = { /* doSomething() */ }) {
                Icon(Icons.Filled.Email, contentDescription = null)
            }
    }

    TopAppBar(
        actions = topBarActions,
        title = appTitle
    )
}
```

**Floating Button**&#x20;

```
   val fap =@Composable {
        FloatingActionButton(onClick = { /* ... */ }) {
            Icon(Icons.Filled.AccountBox, contentDescription = null)
        }
    }
    ...
    Scaffold(
                topBar = { topBar() }, // waith for kotlin 1.6
                floatingActionButton = fap
        ) {
            AppBody()
        }
```

## Users List

Extract layout for single user

```
@Composable
private fun DisplayUser(context: Context,user: User) {
    Text(
        text = "User : ${user.name} ",
        modifier =
        Modifier
            .clickable {
                Toast
                    .makeText(context, "user clicked ${user.name}", Toast.LENGTH_LONG)
                    .show()
            }
            .padding(30.dp)
    )
}
```

**Bonus : FP and currying**

```
private fun displayUser(context: Context): @Composable (User) -> Unit = { user ->
...
}

val context = LocalContext.current
        val userComposable= displayUser(context)
        users.forEach{userComposable(it)}
```

**Change data source in "our very sophisticated DI framework"**

```
object DI{
//    val usersRepository:UsersRepository = InMemoryUsersRepository
    val usersRepository:UsersRepository = InMemorySourceOfALotOfUsersy
}
```

**Lazy Column - First attempt**

```
   LazyColumn(
        verticalArrangement = Arrangement.Center // just chek in the code
    ) {
        val context = LocalContext.current //we are not in Composable anymore!!!asdasdLa Column - second attemptzy
        val userComposable= displayUser(context)
        users.forEach{userComposable(it)}

    }
```

**Lazy Column - Second attempt**

```
LazyColumn(
            verticalArrangement = Arrangement.Center // just chek in the code
    ) {

        //srogie rozwiązanie - import androidx.compose.foundation.lazy.items
        items(users.toList()) {
            userComposable(it)
        }

    }
```

**Add state to View**

```
 //remember about : import androidx.compose.runtime.*
 var userClickedState:String? by remember {
        mutableStateOf(null)
    }
    if(userClickedState!=null) {
        Text(text = "clicked user $userClickedState")
    }

    val userOnClick:(User)->Unit={  //currying once again!!!
        userClickedState=it.name
        Toast
                .makeText(context, "user clicked ${it.name}", Toast.LENGTH_LONG)
                .show()
    }

  ....
      val userComposable = displayUser(userOnClick)
  ...
  private fun displayUser(onClick:(User)->Unit): @Composable (User) -> Unit = { user ->
    Text(
            text = "User : ${user.name} ",
            modifier =
            Modifier
                    .clickable {
                        onClick(user)
                    }
                    .padding(30.dp)
    )
}
```

(but it doesnt match theory)

{% embed url="<https://developer.android.com/codelabs/jetpack-compose-layouts?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fcompose%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fjetpack-compose-layouts#5>" %}
in theory scroll state should be stored
{% endembed %}

**Refactor state**

```
class UsersPageState {
    private var userClickedState: String? by mutableStateOf(null)

    val userInfo:String
        get() = userClickedState ?: throw RuntimeException("users state was reset")

   val updateClickedState: (User) -> Unit = {
        if (userClicked())
            userClickedState = "$userClickedState:${it.name}"
        else
            userClickedState = it.name
    }

    fun userClicked() = userClickedState != null
}

@Composable
fun UserList(usersPage: UsersPageState = UsersPageState(), usersRepository: UsersRepository = DI.usersRepository) {
    val users = usersRepository.select().toList()
    val userComposable = displayUser(onClick = usersPage.updateClickedState)
....
}


fun displayUser(onClick: (User) -> Unit): @Composable (User) -> Unit = { user ->

```

**Puzzler - when state is created?**

```
@Composable
fun UserList(usersPage: UsersPageState= UsersPageState(), usersRepository: UsersRepository = DI.usersRepository) {

    println("****************************RECOMPOSE*******************************")
    val users = usersRepository.select().toList()
    val userComposable = displayUser(onClick = usersPage.updateClickedState)
    
class UsersPageState {

    init {
        println("**************USER PAGE STATE INITIALIZED***************")
    }
```

still working

```
@Composable
fun AppBody() {
    Surface(color = Color.Yellow) {
        val state=UsersPageState()
        UserList(state)
    }
}
```

so compose actually saves stores default parameters outside "particular method compose"!

Following will not work:

```
@Composable
fun UserList(usersRepository: UsersRepository = DI.usersRepository) {
    println("****************************RECOMPOSE*******************************")
    val usersPage=UsersPageState()
```

**Survive Rotation**

First add saver

* saver doesnt play well with null values!!!!!

```
  companion object {
        private val stateKey: String = "StateKey"

        val saver = mapSaver(
                save = {
                    val value = it.userClickedState ?: ""
                    mapOf(stateKey to value)
                },
                restore = { storedMap ->
                    val stored=storedMap[stateKey] as String
                    val value=if(stored=="") null else stored
                    UsersPageState().apply { userClickedState =  value }
                }
        )
    }
```

then use it in Composable function

* remember that param name is stateSaver!!!!

```
@Composable
fun AppBody() {
    Surface(color = Color.Yellow) {
        val usersPageState by rememberSaveable(stateSaver = UsersPageState.saver) {
            mutableStateOf(UsersPageState())
        }

        UserList(usersPageState)
    }
}
```

**Fixing Width**

```
  modifier = Modifier.width(IntrinsicSize.Max),
  
  gives 
  
  Process: com.wlodar.jug.compose, PID: 7170
    java.lang.IllegalStateException: Asking for intrinsic measurements of SubcomposeLayout layouts is not supported. This includes components that are built on top of SubcomposeLayout, such as lazy lists, BoxWithConstraints, TabRow, etc. To mitigate this:
    - if intrinsic measurements are used to achieve 'match parent' sizing,, consider replacing the parent of the component with a custom layout which controls the order in which children are measured, making intrinsic measurement not needed
```

but following is ok:

```
@Composable
fun UserList(usersPage: UsersPageState, usersRepository: UsersRepository = DI.usersRepository) {

    @Composable
    fun displayHeaders(usersPage: UsersPageState) {
       ...
    }

    @Composable
    fun displayUsersColumn() {
       ...
    }

    Column(
        modifier = Modifier.fillMaxWidth()
    ) {
        displayHeaders(usersPage)
        displayUsersColumn()
    }
}
```

**User "Animation"**

This is an example of "a state" which can be stored in composable - view state!

```
fun displayUser(onClick: (User) -> Unit): @Composable (User) -> Unit = { user ->
    var isExpanded by remember { mutableStateOf(false) } // our animation state

    val paddingValue by animateDpAsState( //animation "logic"
            if (isExpanded) 48.dp else 20.dp
    )

    Surface(
            color = Color.Blue,
            modifier = Modifier.padding(vertical = 1.dp)
    ) {
        Text(
                text = "User : ${user.name} ",
                color=Color.White,
                modifier = Modifier
                        .clickable {
                            isExpanded = !isExpanded
                            onClick(user)
                        }
                        .padding(paddingValue)  //animation styling
        )
    }

}
```

**Column manual navigation**

```
@Composable
fun displayColumnNavigation(scrollState: LazyListState, numberOfUsers: Int) {
    //coroutine scope 
    val coroutineScope = rememberCoroutineScope()

//for better readability declare "clicks" function outside composable definitions
    val scrolUp: () -> Unit = {
        coroutineScope.launch {
            scrollState.animateScrollToItem(0)
        }
    }
    val scrolDown: () -> Unit = {
        coroutineScope.launch {
        //scroll state is described below
            scrollState.animateScrollToItem(numberOfUsers)
        }
    }


    Row(
            modifier = Modifier.padding(vertical = 10.dp),
    )
    {
        Button(onClick = scrolUp, modifier = Modifier.padding(end=5.dp)){
            Text("Scroll Up")
        }
        Button(onClick = scrolDown){
            Text("Scroll Down")
        }
    }
}
```

To make it work we need to have control over lazy list scroll state

```
 Column(
            modifier = Modifier.fillMaxWidth()
    ) {
        val users = usersRepository.select().toList()
        val scrollState = rememberLazyListState()
        displayColumnNavigation(scrollState,users.size)
        displayHeaders(usersPage)
        displayUsersColumn(scrollState,users)
    }
    
    ....
    
      @Composable
    fun displayUsersColumn(scrollState: LazyListState, users: List<User>) {
     ......
        LazyColumn(
                state = scrollState,  //<---HERE
                verticalArrangement = Arrangement.Center // just chek in the code
        ) {
        ...
```

## Application theme

Lets return to this one:

```
@Composable
fun SomeGuiApplication() {
    ....
ComposeWorkshopsTheme {  /// <- This

(...)

//it was auto generated
@Composable
fun ComposeWorkshopsTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable() () -> Unit) {
    val colors = if (darkTheme) {
        DarkColorPalette
    } else {
        LightColorPalette
    }

    MaterialTheme(
```

at the top of this file you have color pallete definitionns:&#x20;

```
private val LightColorPalette = lightColors(
    primary = Purple500,
    primaryVariant = Purple700,
    secondary = Teal200

)
```

and aprticular colors are defined in Color.kt

```
import androidx.compose.ui.graphics.Color

val Purple200 = Color(0xFFBB86FC)
val Purple500 = Color(0xFF6200EE)
val Purple700 = Color(0xFF3700B3)
val Teal200 = Color(0xFF03DAC5)
```

now using site such like this one : <https://www.w3schools.com/colors/colors_palettes.asp>&#x20;

we can define here some general colors

```
//remember top add FF at the begining which is (most likely) transparency value FF- visible
val backgroundColor = Color(0xFFFEB236)
val controlsColor = Color(0xFF6b5b95)
```

now you can define second "preview annotation" and define colors inside pallette

```
val yellow = Color(0xFFFEB236)
val purple = Color(0xFF6b5b95)
val pink = Color(0xFFd64161)
val orange = Color(0xFFff7b25)

private val LightColorPalette = lightColors(
    primary = yellow,
    primaryVariant = orange,
    secondary = purple
    )
```

and use those colors directly in the composables

```
Surface(
            color=MaterialTheme.colors.primary,
            modifier = Modifier.padding(vertical = 1.dp)
    ) 
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pawelwlodarski.gitbook.io/android/compose-workshop/compose-gui.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
