androidkotlinexpandablelistviewexpandablelistadapter

How to get child Count in Header in expandable list view Kotlin


enter image description here

How get the child count same as shown in the picture in the header.

API RESPONSE: -

data class ToDoListResponse(
val message: String = "",
val success: Int = 0,
val todays_task_list: MutableList<TodaysTask>,
val todays_task_total: Int = 0,
val tomorows_task_list: MutableList<TodaysTask>,
val tomorrow_task_total: Int = 0,
val upcomming_task_list: MutableList<TodaysTask>,
val upcomming_task_total: Int = 0)
{
data class TodaysTask(
val created_at: String = "",
val description: String = "",
val due_date: String= "",
val is_completed: String= "",
val is_pinned_task: String= "",
val remind_me: String= "",
val task_id: String= "",
var title: String= "",
val updated_at: String= "",
val user_id: String= ""
)

ADPATER: -

package com.coronation.jackpotplus.adapter

import android.annotation.SuppressLint
import android.app.DatePickerDialog
import android.content.Context
import android.graphics.Typeface
import android.os.Build
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.annotation.RequiresApi
import com.coronation.jackpotplus.R
import com.coronation.jackpotplus.model.CommonResponse
import com.coronation.jackpotplus.model.ToDoListResponse
import com.coronation.jackpotplus.network.ApiClient
import com.coronation.jackpotplus.network.ApiService
import com.coronation.jackpotplus.view.ToDoListActivity
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.textfield.TextInputEditText
import org.jetbrains.anko.layoutInflater
import retrofit2.Call
import retrofit2.Response
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.*


@Suppress("NAME_SHADOWING", "DEPRECATED_IDENTITY_EQUALS")
class CustomExpandableListAdapter(
        context: Context,
        expandableListTitle: ArrayList<String>,
        expandableListDetail: HashMap<String,
                MutableList<ToDoListResponse.TodaysTask>>)
    : BaseExpandableListAdapter()
{
    private val context: Context
    private val expandableListTitle: ArrayList<String>
    private val expandableListDetail: HashMap<String, MutableList<ToDoListResponse.TodaysTask>>
    private lateinit var edtTitle: TextInputEditText
    private lateinit var edtDes: TextInputEditText
    private lateinit var dueDate: TextView
    private lateinit var txtreminddate: TextView
    private lateinit var createAt: String
    private lateinit var taskId: String
    private var ChildCount: String? = null
    private lateinit var dialog: BottomSheetDialog

    override fun getChild(listPosition: Int, expandedListPosition: Int): Any
    {
        return expandableListDetail[expandableListTitle[listPosition]]?.get(expandedListPosition)!!
    }

    override fun getChildId(listPosition: Int, expandedListPosition: Int): Long
    {
        return expandedListPosition.toLong()
    }

    @RequiresApi(Build.VERSION_CODES.O)
    @SuppressLint("InflateParams", "SimpleDateFormat")
    override fun getChildView(listPosition: Int, expandedListPosition: Int, isLastChild: Boolean, convertView: View?, parent: ViewGroup?): View
    {
        var convertView = convertView
        if (convertView == null)
        {
            val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            convertView = layoutInflater.inflate(R.layout.list_item, null)
        }
        val expandedListTextView = convertView?.findViewById(R.id.expandedListItem) as TextView
        val expandedItem = convertView.findViewById(R.id.expandedItem) as LinearLayout
        val txtDelete = convertView.findViewById(R.id.delete) as FrameLayout
        val unpin = convertView.findViewById(R.id.unpin) as FrameLayout
        val pin = convertView.findViewById(R.id.pin) as FrameLayout
        val complete = convertView.findViewById(R.id.complete) as FrameLayout
        val mainPin = convertView.findViewById(R.id.mainPin) as ImageView

        val getset = getChild(listPosition, expandedListPosition) as ToDoListResponse.TodaysTask
        expandedListTextView.text = getset.title
        createAt = getset.created_at
        unpin.visibility = View.GONE
        if (getset.is_pinned_task == "1")
        {
            mainPin.visibility = View.VISIBLE
            unpin.visibility = View.VISIBLE
            pin.visibility = View.GONE
        }
        else
        {
            mainPin.visibility = View.GONE
            pin.visibility = View.VISIBLE
        }

        unpin.setOnClickListener {
            pinnedtask(getset.task_id)
        }

        pin.setOnClickListener {
            pinnedtask(getset.task_id)
        }

        complete.setOnClickListener {
            markascomplete(getset.task_id)
        }

        txtDelete.setOnClickListener {
            deleteTask(getset.task_id)
        }

        expandedItem.setOnClickListener {
            openTaskDetails()
            taskId = getset.task_id
            edtTitle.setText(getset.title)
            edtDes.setText(getset.description)
            dueDate.visibility = View.VISIBLE
            txtreminddate.visibility = View.VISIBLE
            val dueDate1 = getset.due_date
            val sdf = SimpleDateFormat("yyyy-MM-dd")
            val date = Date(dueDate1.toLong() * 1000)
            dueDate.text = sdf.format(date)
            val remindDate = getset.remind_me
            val sdf1 = SimpleDateFormat("yyyy-MM-dd")
            val date1 = Date(remindDate.toLong() * 1000)
            txtreminddate.text = sdf1.format(date1)
        }
        return convertView
    }

    private fun pinnedtask(taskId: String)
    {
        val retIn = ApiClient.client!!.create(ApiService::class.java)
        retIn.pintask(taskId).enqueue(object : retrofit2.Callback<CommonResponse> {
            override fun onResponse(call: Call<CommonResponse>, response: Response<CommonResponse>) {
                showToast(response.body()?.message)
                notifyDataSetChanged()
                if (context is ToDoListActivity) {
                    context.tasklistAPI("1")
                }
            }

            override fun onFailure(call: Call<CommonResponse>, t: Throwable) {
                showToast("Shomwthing wents wrong")
            }
        })
    }

    private fun markascomplete(taskId: String)
    {
        val retIn = ApiClient.client!!.create(ApiService::class.java)
        retIn.markcomplete(taskId).enqueue(object : retrofit2.Callback<CommonResponse> {
            override fun onResponse(call: Call<CommonResponse>, response: Response<CommonResponse>) {
                showToast(response.body()?.message)
                notifyDataSetChanged()
                if (context is ToDoListActivity) {
                    context.tasklistAPI("1")
                }
            }

            override fun onFailure(call: Call<CommonResponse>, t: Throwable) {
                showToast("Shomwthing wents wrong")
            }
        })
    }

    private fun deleteTask(taskId: String)
    {
        val retIn = ApiClient.client!!.create(ApiService::class.java)
        retIn.deteletask(taskId).enqueue(object : retrofit2.Callback<CommonResponse> {
            override fun onResponse(call: Call<CommonResponse>, response: Response<CommonResponse>) {
                showToast(response.body()?.message)
                notifyDataSetChanged()
                if (context is ToDoListActivity) {
                    context.tasklistAPI("1")
                }
            }

            override fun onFailure(call: Call<CommonResponse>, t: Throwable) {
                showToast("Shomwthing wents wrong")
            }

        })
    }

    @RequiresApi(Build.VERSION_CODES.O)
    @SuppressLint("InflateParams")
    private fun openTaskDetails()
    {
        try
        {
            val modalbottomsheet = context.layoutInflater.inflate(R.layout.custom_view_todo, null)
            dialog = BottomSheetDialog(context, R.style.DialogStyle)
            dialog.setContentView(modalbottomsheet)
            edtTitle = dialog.findViewById(R.id.edtTitle)!!
            edtDes = dialog.findViewById(R.id.edtDes)!!
            dueDate = dialog.findViewById(R.id.dueDate)!!
            txtreminddate = dialog.findViewById(R.id.txtreminddate)!!
            val imgDatePicker = dialog.findViewById<ImageView>(R.id.imgDatePicker)
            val imgDatePickerReminder = dialog.findViewById<ImageView>(R.id.imgDatePickerReminder)
            val button = dialog.findViewById<Button>(R.id.Button)

            imgDatePicker?.setOnClickListener {
                showDatePicker(context)
            }
            imgDatePickerReminder?.setOnClickListener {
                showDatePickerForRemind(context)
            }
            button?.setOnClickListener {
                updateTaskAPI()
            }
            dialog.show()
        }
        catch (e: Exception)
        {
            e.printStackTrace()
        }
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private fun updateTaskAPI()
    {
        val l = LocalDate.parse(dueDate.text, DateTimeFormatter.ofPattern("yyyy-MM-dd"))
        val dueDateTimestamp = l.atStartOfDay(ZoneId.systemDefault()).toInstant().epochSecond
        Toast.makeText(context, dueDateTimestamp.toString(), Toast.LENGTH_SHORT).show()

        val l1 = LocalDate.parse(txtreminddate.text, DateTimeFormatter.ofPattern("yyyy-MM-dd"))
        val remindMeTimestamp = l1.atStartOfDay(ZoneId.systemDefault()).toInstant().epochSecond
        Toast.makeText(context, remindMeTimestamp.toString(), Toast.LENGTH_SHORT).show()

        val retIn = ApiClient.client!!.create(ApiService::class.java)
        retIn.taskupdate(
                createAt,
                edtDes.text?.trim().toString(),
                dueDateTimestamp.toString(),
                remindMeTimestamp.toString(),
                taskId, edtTitle.text?.trim().toString(),
                "1").enqueue(object : retrofit2.Callback<CommonResponse>
        {
            override fun onResponse(call: Call<CommonResponse>, response: Response<CommonResponse>)
            {
                if (response.body()!!.success == 1)
                {
                    dialog.dismiss()
                    showToast(response.body()?.message)
                }
            }

            override fun onFailure(call: Call<CommonResponse>, t: Throwable)
            {
                showToast("Something not right, Please try again.")
            }
        }
        )
    }

    @SuppressLint("InflateParams")
    fun showToast(msg: String?)
    {
        try
        {
            val inflater = context.layoutInflater
            val layout = inflater.inflate(R.layout.custom_toast, null)
            val text = layout.findViewById<View>(R.id.text) as TextView
            text.text = msg
            val toast = Toast(context)
            toast.duration = Toast.LENGTH_SHORT
            toast.view = layout
            if (toast.view.isShown)
            {
                toast.cancel()
            }
            else
            {
                toast.show()
            }
        }
        catch (e: Exception)
        {
            e.printStackTrace()
        }
    }

    private fun showDatePickerForRemind(context: Context)
    {
        val cal = Calendar.getInstance()
        val dateSetListener =
                DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
                    cal.set(Calendar.YEAR, year)
                    cal.set(Calendar.MONTH, monthOfYear)
                    cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
                    val myFormat = "yyyy-MM-dd" // mention the format you need
                    val sdf = SimpleDateFormat(myFormat, Locale.US)
                    txtreminddate.visibility = View.VISIBLE
                    txtreminddate.text = sdf.format(cal.time)
                }

        var datepicker: DatePickerDialog? = null
        if (txtreminddate.text.isNotBlank())
        {
            try
            {
                val date: String = txtreminddate.text.trim().toString()
                val datearr = date.split("-").toTypedArray()
                val yearint = datearr[2].toInt()
                val monthint = datearr[1].toInt()
                val dateint = datearr[0].toInt()
                datepicker = DatePickerDialog(
                        context,
                        dateSetListener,
                        dateint,
                        monthint - 1,
                        yearint
                )
            }
            catch (e: Exception)
            {
                e.printStackTrace()
            }
        }
        else
        {
            try
            {
                val calendar = Calendar.getInstance()
                val dd = calendar[Calendar.DAY_OF_MONTH]
                val mm = calendar[Calendar.MONTH]
                val yy = calendar[Calendar.YEAR]
                datepicker = DatePickerDialog(context, dateSetListener, dd, mm, yy)
            }
            catch (e: Exception)
            {
                e.printStackTrace()
            }
        }
        datepicker!!.show()
    }

    private fun showDatePicker(context: Context)
    {
        val cal = Calendar.getInstance()
        val dateSetListener =
                DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
                    cal.set(Calendar.YEAR, year)
                    cal.set(Calendar.MONTH, monthOfYear)
                    cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
                    val myFormat = "yyyy-MM-dd" // mention the format you need
                    val sdf = SimpleDateFormat(myFormat, Locale.US)
                    dueDate.visibility = View.VISIBLE
                    dueDate.text = sdf.format(cal.time)
                }

        var datepicker: DatePickerDialog? = null
        if (dueDate.text.isNotBlank())
        {
            try
            {
                val date: String = dueDate.text.toString()
                val datearr = date.split("-").toTypedArray()
                val dateint = datearr[0].toInt()
                val monthint = datearr[1].toInt()
                val yearint = datearr[2].toInt()
                datepicker = DatePickerDialog(
                        context,
                        dateSetListener,
                        yearint,
                        monthint - 1,
                        dateint
                )
            }
            catch (e: java.lang.Exception)
            {
                e.printStackTrace()
            }
        }
        else
        {
            try
            {
                val calendar = Calendar.getInstance()
                val yy = calendar[Calendar.YEAR]
                val mm = calendar[Calendar.MONTH]
                val dd = calendar[Calendar.DAY_OF_MONTH]
                datepicker = DatePickerDialog(context, dateSetListener, yy, mm, dd)
            }
            catch (e: java.lang.Exception)
            {
                e.printStackTrace()
            }
        }
        datepicker!!.show()
    }

    override fun getChildrenCount(listPosition: Int): Int
    {
        ChildCount = expandableListDetail[expandableListTitle[listPosition]]?.size.toString()
        Log.e("TAG",ChildCount)
        return expandableListDetail[expandableListTitle[listPosition]]?.size!!
    }

    override fun getGroup(listPosition: Int): Any
    {
        return expandableListTitle[listPosition]
    }

    override fun getGroupCount(): Int
    {
        return expandableListTitle.size
    }

    override fun getGroupId(listPosition: Int): Long
    {
        return listPosition.toLong()
    }

    @SuppressLint("InflateParams")
    override fun getGroupView(listPosition: Int, isExpanded: Boolean, convertView: View?, parent: ViewGroup?): View
    {
        var convertView: View? = convertView
        val listTitle = getGroup(listPosition) as String

        if (convertView == null)
        {
            val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            convertView = layoutInflater.inflate(R.layout.list_group, null)
        }
        val listTitleTextView = convertView?.findViewById(R.id.listTitle) as TextView
        val listCount = convertView.findViewById(R.id.listCount) as TextView
        val arrowicon = convertView.findViewById(R.id.arrowicon) as ImageView
        listTitleTextView.setTypeface(null, Typeface.BOLD)
        listTitleTextView.text = listTitle
        listCount.text = "($ChildCount)"

        if (getChildrenCount(listPosition) === 0)
        {
            arrowicon.visibility = View.INVISIBLE
        }
        else
        {
            arrowicon.visibility = View.VISIBLE
            arrowicon.setImageResource(if (isExpanded) R.drawable.ic_arrow_up else R.drawable.ic_arrow_down)
        }
        return convertView
    }

    override fun hasStableIds(): Boolean
    {
        return false
    }

    override fun isChildSelectable(listPosition: Int, expandedListPosition: Int): Boolean
    {
        return true
    }

    init
    {
        this.context = context
        this.expandableListTitle = expandableListTitle
        this.expandableListDetail = expandableListDetail
    }
}

ACTIVITY: -

  fun tasklistAPI(userId: String)
    {
        if (isOnline())
        {
            llNoInternet.gone()
            llLoading.visible()
            apiService.todotasklist(userId).enqueue(object :
                    Callback<ToDoListResponse>
            {
                override fun onFailure(call: Call<ToDoListResponse>, t: Throwable)
                {
                    llLoading.gone()
                }

                override fun onResponse(call: Call<ToDoListResponse>, response: Response<ToDoListResponse>)
                {
                    if (response.isSuccessful)
                    {
                        if (response.body()!!.success == 1)
                        {
                            try
                            {

                                llLoading.gone()
                                expandableListDetail = HashMap()

                                val todaytask = response.body()!!.todays_task_list

                                expandableListTitle = ArrayList()
                                todaystitle = ArrayList()
                                todayslist = ArrayList()
                                Log.e("<>list", todaystitle.toString())

                                for (i in todaytask.indices)
                                {
                                    todaystitle.add(todaytask[i])
                                }

                                val tommrowtask = response.body()!!.tomorows_task_list
                                val tommorowtitle: MutableList<ToDoListResponse.TodaysTask> = ArrayList()

                                for (i in tommrowtask.indices)
                                {
                                    tommorowtitle.add(tommrowtask[i])
                                }

                                val upcomingtask = response.body()!!.upcomming_task_list
                                val upcomingtitle: MutableList<ToDoListResponse.TodaysTask> = ArrayList()

                                for (i in upcomingtask.indices)
                                {
                                    upcomingtitle.add(upcomingtask[i])
                                }

                                expandableListTitle.add("Today's Task")
                                expandableListTitle.add("Tommorow's Task")
                                expandableListTitle.add("Upcoming Task")
                                expandableListDetail.put(expandableListTitle[0], todaystitle)
                                expandableListDetail.put(expandableListTitle[1], tommrowtask)
                                expandableListDetail.put(expandableListTitle[2], upcomingtask)
                                Log.e("task", expandableListTitle.get(0) + " = " + expandableListDetail.put(expandableListTitle.get(0), todaystitle))
                                Log.e("task", expandableListTitle.get(1) + " = " + expandableListDetail.put(expandableListTitle.get(1), tommrowtask))
                                Log.e("task", expandableListTitle.get(2) + " = " + expandableListDetail.put(expandableListTitle.get(2), upcomingtask))
                                expandableListAdapter = CustomExpandableListAdapter(activity, expandableListTitle, expandableListDetail)
                                expandableListView!!.setAdapter(expandableListAdapter)
                            }
                            catch (e: Exception)
                            {
                                e.printStackTrace()
                            }
                        }
                    }
                    else
                    {
                        llLoading.gone()
                    }
                }
            })
        }
        else
        {
            llNoInternet.visible()
        }
    }

Here is the code that show that how can i add add data into hashmap and the expandable list view. as u see there is an hashmap for expandable list view and and in the adaoter i put the title from api respose but the header for listview parent is static and the data in the child re dynamic so you can see the diffrance


Solution

  • You've added a lot of code but I think this is the only one which is important for your question :-

    expandableListTitle.add("Today's Task")
    expandableListTitle.add("Tommorow's Task")
    expandableListTitle.add("Upcoming Task")
    expandableListDetail.put(expandableListTitle[0], todaystitle)
    expandableListDetail.put(expandableListTitle[1], tommrowtask)
    expandableListDetail.put(expandableListTitle[2], upcomingtask)
    Log.e("task", expandableListTitle.get(0) + " = " + expandableListDetail.put(expandableListTitle.get(0), todaystitle))
    Log.e("task", expandableListTitle.get(1) + " = " + expandableListDetail.put(expandableListTitle.get(1), tommrowtask))
    Log.e("task", expandableListTitle.get(2) + " = " + expandableListDetail.put(expandableListTitle.get(2), upcomingtask))
    expandableListAdapter = CustomExpandableListAdapter(activity, expandableListTitle, expandableListDetail)
    
    expandableListView!!.setAdapter(expandableListAdapter)
    

    So As much as I have understood from the image you have added in the link what you need is you need to show the number of elements present in the child in your header right.

    What you can do is simply add the total number of elements present in your list like this :-

    expandableListTitle.add("Today's Task (${todaystitle.count()})") //.count() gives the total number of elements present in list 
    

    It will add title as Today's Task (10) \\ here 10 would be the number of elements present in your list. Now you can simply format in any way you want