How to do clickable jetpack compose list

How to do clickable jetpack compose list

To do clickable list in jetpack compose or compose list you need to do modifier with cickable in your list item container, like this:

Mutliple choices in a list with compose

Surface(modifier = Modifier.clickable {}

in this case is a Surface, you can use what ever you want, like Row, Box…

you can see the full code in Github

How to do single choice in jetpack compose list

How to do single choice in jetpack compose list

To do a single choice list in jetpack compose,
you have to think that you need a variable:

val selectedOption = mutableStateOf(0)

And then in your item list you need to check the variable with the current item.

RadioButton(selected = (text == selectedValue),

When user click the item you need to save the new value

onClick = {selectedOption.value = selected})

Your item list can be like this

RadioButton(selected = (text == selectedValue),
            onClick = {selectedOption.value = selected})

You can check the full example in Github
or in here:

import android.annotation.SuppressLint
import android.content.Context
import android.widget.Toast
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.selection.selectable
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.a.jetpackcomposelists.R

@Composable
fun SingleScreen(
    viewModel: SingleViewModel,
    context: Context
) {
    Column(modifier = Modifier.fillMaxHeight()) {
        NameList(viewModel, context, Modifier.weight(1f))
    }
}

@SuppressLint("UnrememberedMutableState")
@Composable
fun NameList(
    viewModel: SingleViewModel,
    context: Context,
    modifier: Modifier
) {
    val selectedOption = mutableStateOf(0)
    val optionsList = viewModel.getInitial(context)
    Scaffold(modifier = Modifier.fillMaxWidth(), topBar = {
        TopAppBar(title = {
            Text(text = stringResource(id = R.string.app_name))
        }, actions = {})
    }) {
        LazyColumn(modifier = modifier.fillMaxSize()) {
            itemsIndexed(items = optionsList) { selected: Int, item: String ->
                ElementSelected(text = item,
                    selectedValue = optionsList[selectedOption.value],
                    onClickListener = {
                        selectedOption.value = selected
                        Toast.makeText(context, item, Toast.LENGTH_SHORT).show()
                    })
                TabRowDefaults.Divider(color = Color.LightGray)
            }
        }
    }
}


@Composable
fun ElementSelected(
    text: String,
    selectedValue: String,
    onClickListener: (String) -> Unit
) {
    Box(
        Modifier
            .height(90.dp)
            .fillMaxWidth()
            .selectable(
                selected = (text == selectedValue),
                onClick = {
                    onClickListener(text)
                })
    ) {
        RadioButton(
            modifier = Modifier
                .align(Alignment.CenterStart)
                .padding(10.dp),
            selected = (text == selectedValue),
            onClick = {
                onClickListener(text)
            })
        Text(
            text = text,
            fontSize = 30.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier
                .padding(start = 16.dp)
                .align(Alignment.Center)
        )
    }
}

to choice a only choice in compose list
You can check the full example in Github

Multiple choices in a list with compose

Multiple choices in a list with compose

Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

Mutliple choices in a list with compose

you have a list with compose it is easier and if you want to do multiple choices in a list with compose you have to use rememberSaveable.

When you use compose you have to set up the gradl like this:

kotlinOptions {
jvmTarget = ‘1.8’
useIR = true
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion “1.0.0-beta08”
}
}

dependencies {

implementation ‘androidx.core:core-ktx:1.5.0’
implementation ‘androidx.appcompat:appcompat:1.3.0’
implementation ‘com.google.android.material:material:1.3.0’
implementation ‘androidx.constraintlayout:constraintlayout:2.0.4’
testImplementation ‘junit:junit:4.13.2’
androidTestImplementation ‘androidx.test.ext:junit:1.1.2’
androidTestImplementation ‘androidx.test.espresso:espresso-core:3.3.0’

// Compose
implementation “org.jetbrains.kotlin:kotlin-stdlib:1.0.0-beta08”
implementation “androidx.activity:activity-compose:1.3.0-beta01”
implementation “androidx.compose.runtime:runtime:1.0.0-beta08”
implementation “androidx.compose.ui:ui:1.0.0-beta08”
implementation “androidx.compose.foundation:foundation:1.0.0-beta08”
implementation “androidx.compose.foundation:foundation-layout:1.0.0-beta08”
implementation “androidx.compose.material:material:1.0.0-beta08”
implementation “androidx.compose.runtime:runtime-livedata:1.0.0-beta08”
implementation “androidx.compose.ui:ui-tooling:1.0.0-beta08”
implementation “com.google.android.material:compose-theme-adapter:1.0.0-beta08”
}
Share

While remember helps you retain state across recompositions, the state is not retained across configuration changes. For this, you must use rememberSaveable. rememberSaveable automatically saves any value that can be saved in a Bundle. For other values, you can pass in a custom saver object.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.Surface
import androidx.compose.material.TabRowDefaults.Divider
import androidx.compose.material.Text
import androidx.compose.material.Checkbox
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApp {
                MyScreenContent()
            }
        }
    }
}

@Composable
fun MyApp(content: @Composable () -> Unit) {
    Surface(color = Color.White) {
        content()
    }
}

@Composable
fun MyScreenContent(
    names: List<String> = List(15) { "Item #$it" },
    completed: MutableList<Boolean> = MutableList(15) { false }
) {
    Column(modifier = Modifier.fillMaxHeight()) {
        NameList(names, Modifier.weight(1f), completed)
    }
}

@Composable
fun NameList(names: List<String>, modifier: Modifier, completed: MutableList<Boolean>) {
    LazyColumn(modifier = modifier) {
        itemsIndexed(items = names) { index: Int, item: String ->
            Greeting(name = item, completed, index)
            Divider(color = Color.Black)
        }
    }
}

@Composable
fun Greeting(name: String, completedList: MutableList<Boolean>, index: Int) {
    var isSelected by rememberSaveable { mutableStateOf(completedList[index]) }
    val backgroundColor by animateColorAsState(if (isSelected) Color.Blue else Color.Transparent)

    Row {
        Text(
            text = "Hello $name!",
            modifier = Modifier
                .padding(24.dp)
        )
        Checkbox(
                checked = isSelected,
                onCheckedChange = {
                    isSelected = !isSelected
                    completedList[index] = !isSelected
                },
                modifier = Modifier
                    .background(color = backgroundColor)
            )
        }
    }


@Preview("MyScreen preview")
@Composable
fun DefaultPreview() {
    MyApp {
        MyScreenContent()
    }
}

you can download in Github

How to use GraphQL with Retrofit on Android?

How to use GraphQL with Retrofit on Android?

Have you use GraphQL on Android?

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

Apollo Android is a GraphQL client that generates Java and Kotlin models from GraphQL queries. These models give you a type-safe API to work with GraphQL servers. Apollo helps you keep your GraphQL query statements together, organized, and easy to access.

You can choose to use Apollo in android when you query is static. But what happen when the query is dynamic query?

We recommend you to use GraphQL with retrofit.

In your manifest to add

<uses-permission android:name="android.permission.INTERNET"/>

Your dependencies

// Kotlin Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.4'

//OkHttp
implementation ("com.squareup.okhttp3:okhttp:3.12.12"){
  force = true //API 19 support
}
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.12'

//retrofit
implementation "com.squareup.retrofit2:retrofit:2.7.1"
implementation "com.squareup.retrofit2:converter-scalars:$2.7.1"

Also Java 8 compatibility

android {

    ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }
}

With the service

import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST

interface GraphQLService {

@Headers("Content-Type: application/json")
@POST("/")
suspend fun postDynamicQuery(@Body body: String): Response
}

you can create a object

import retrofit2.Retrofit
import retrofit2.converter.scalars.ScalarsConverterFactory

object GraphQLInstance {

    private const val BASE_URL: String = "http://192.155.1.55:2000/"

    val graphQLService: GraphQLService by lazy {
        Retrofit
            .Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(ScalarsConverterFactory.create())
            .build().create(GraphQLService::class.java)
    }
}

In the activity you can create this method

private fun post(userId: String){
    val retrofit = GraphQLInstance.graphQLService
    val paramObject = JSONObject()
    paramObject.put("query", "query {users(userid:$userId){username}}")
    GlobalScope.launch {
        try {
            val response = retrofit.postDynamicQuery(paramObject.toString())
            Log.e("response", response.body().toString())
        }catch (e: java.lang.Exception){
            e.printStackTrace()
        }
    }
}

You can check GraphQL with Retrofit on Android in the example in GitHub
GraphQL with Retrofit on Android?

Dagger in kotlin

Dagger in Kotlin

In object oriented design, the dependency inversion principle is a specific form of decoupling software modules.
Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.
The idea behind points A and B of this principle is that when designing the interaction between a high-level module and a low-level one, the interaction should be thought of as an abstract interaction between them. This not only has implications on the design of the high-level module, but also on the low-level one: the low-level one should be designed with the interaction in mind and it may be necessary to change its usage interface.

Dagger in kotlin
In Android we have Dagger is tool to do dependency inversion.

You can see a example in GitHub

We learn with a simple dagger example in Kotlin:

We have a car

class Car() {

    lateinit var engine: Engine
    lateinit var wheels: Wheels

    @Inject
    constructor(
        engine: Engine,
        wheels: Wheels
    ) : this() {
        this.engine = engine
        this.wheels = wheels

    }

    fun drive():String {
        return "driving..."
    }
}

We can build this car with engine

class Engine @Inject
internal constructor()

and wheels

class Wheels@Inject
internal constructor()

With this to object We can create a object of car. To create a object in Dagger we have to create a interface component:

@Component
interface CarComponent {

    var car:Car
}

And now in our MainActivity, We can use our object:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val carComponent:CarComponent = DaggerCarComponent.create()

        text_view.text = carComponent.car.drive()

    }
}

You can see a example in GitHub