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

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

Kotlin Android Extensions in Adapter

Kotlin Android Extensions in Adapter

Sometimes is difficult to use kotlin android extensions, the best way to use Kotlin synthetic in Adapter or ViewHolder is like this:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = tasks[position]
holder.bind(item, checkTask, deleteTask)
}

No need to write

val tvTask = view.findViewById(R.id.tvTask)
tvTask.text = task.description

Just

 
itemView.task_item_textView.text = task.description

Or in fun bind you can put

 = with(itemView)

All the fun

fun bind(task: Task, checkTask: (Task) -> Unit, deleteTask: 
(Task) -> Unit) = with(itemView){
            task_item_textView.text = task.description
            task_item_done_checkBox.isChecked = task.completed
            task_item_done_checkBox.setOnClickListener{checkTask(task)}
            setOnClickListener { deleteTask(task) }
        }

Example in Git Hub