Search code examples
androidkotlindesign-patterns

Android app design recomendations for a alert dialog showing list


So I was doing an implementation in an app, and I wanted to show in the PlateScanner, the plates that the user has scanned.

Now it works, but the design is a bit, "off" hahaha I´m not a very good designer so I was asking if i can in this platform, for some recomendations, not only here, but in general about the apps, and how you would do it!

Right now is a table inside a scrollview inside a AlertDialog

    private fun showFleetInfoPopup() {
        val builder = AlertDialog.Builder(requireContext())
        builder.setTitle("Matriculas leídas")
        viewLifecycleOwner.lifecycleScope.launch(dispatcherIO) {
            val matriculasList = db.MatriculaDao().getAllDistinct()
            withContext(dispatcherMain) {
                val scrollView = ScrollView(requireContext()).apply {
                    val padding = resources.getDimensionPixelSize(R.dimen.common_margin_min)
                    setPadding(padding, padding, padding, padding)
                }

                val tableLayout = TableLayout(requireContext()).apply {
                    val padding = resources.getDimensionPixelSize(R.dimen.common_margin_min)
                    setPadding(padding, padding, padding, padding)
                }

                matriculasList.forEach { matriculaEntity ->
                    val tableRow = TableRow(requireContext()).apply {
                        val margin = 8
                        layoutParams = TableLayout.LayoutParams(
                            TableLayout.LayoutParams.WRAP_CONTENT,
                            TableLayout.LayoutParams.WRAP_CONTENT
                        ).apply {
                            setMargins(margin, margin, margin, margin)
                        }
                    }

                    val textView = TextView(requireContext()).apply {
                        text = matriculaEntity.matricula
                        textSize = resources.getDimension(R.dimen.text_tiny_body)
                    }
                    tableRow.addView(textView)
                    tableLayout.addView(tableRow)
                }

                scrollView.addView(tableLayout)
                builder.setView(scrollView)
                builder.setPositiveButton("OK") { dialog, _ -> dialog.dismiss() }
                builder.show()
            }
        }
    }

Thanks in advance for any help!

enter image description here


Solution

  • I think you're making things too complex by creating a dynamic table. The AlertDialog supports adding a list, which can simplify your implementation significantly. You can provide the list of matricula as a parameter to the showFleetInfoPopup function and handle the complexity outside the function, even in onCreate. Here's a simplified version of your code:

    private fun showFleetInfoPopup(matriculasList: Array<String>, context: Context) {
        val builder: AlertDialog.Builder = AlertDialog.Builder(context)
        builder
            .setTitle("Matriculas leídas")
            .setPositiveButton("OK") { dialog, _ -> dialog.dismiss() }
            .setItems(matriculasList) { _, _ -> }
    
        val dialog: AlertDialog = builder.create()
        dialog.show()
    }
    

    In the example below, I will display the dialog when the user clicks on the "show" button:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            val data = queryDb()
            showFleetInfoPopup(data, this)
        }
    }
    
    private fun queryDb(): Array<String> {
        // Query the database here
        // For this example, I will just hard-code the list
        return arrayOf("1234 ABCD", "5678 EFGH", "9101 IJKL")
    }
    

    To improve this solution further, consider using a ViewModel to handle the database query. This separates the data handling from the UI logic, making your code more modular and easier to maintain. Here's how you can do it:

    class MatriculaViewModel : ViewModel() {
        //...
        private val matriculaDao = db.MatriculaDao()
    
        fun fetchMatriculas() : List<String> {
            return matriculaDao.getAllDistinct()
        }
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
    
        val button = findViewById<Button>(R.id.button)
    
        button.setOnClickListener {
            
            // use this dependency to be able to do that
            // implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.4"
            val matriculaViewModel by viewModels<MatriculaViewModel>()
    
            val data = matriculaViewModel.fetchMatriculas()
    
            showFleetInfoPopup(data.toTypedArray(), this)
        }
    }
    

    If you want to do thing asynchronously, you can do something like this:

    class MatriculaViewModel : ViewModel() {
    
        private val matriculaDao = db.MatriculaDao()
    
        private val _matriculasList = MutableLiveData<List<String>>()
        val matriculasList: LiveData<List<String>> get() = _matriculasList
    
    
        fun fetchMatriculas() {
            viewModelScope.launch {
                _matriculasList.postValue(matriculaDao.getAllDistinct())
            }
        }
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
    
        val button = findViewById<Button>(R.id.button)
    
        button.setOnClickListener {
    
            val matriculaViewModel by viewModels<MatriculaViewModel>()
    
            matriculaViewModel.matriculasList.observe(this) { data ->
                showFleetInfoPopup(data.toTypedArray(), this)
            }
    
        }
    }
    

    Demo:

    Demo