Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Como fazer para a dialog não fechar após apertar em

Quando vocês fizeram o try/catch do valor para retornar zero quando desse erro, além disso, montei uma estrutura para ele não permitir inserir uma transação com valor zero e mostrar um Toast alertando. Ver uso do método isValid abaixo

Porém, neste caso, não quero que o dialog feche. Quero que os outros dados que a pessoa já preencheu continuem disponíveis, apenas no aguardo de o preenchimento completo ser feito.

Como fazer isso? Mesmo que minha solução tenha que ser completamente redesenhada...

Segue abaixo meu código atual:

class TransactionsListActivity : AppCompatActivity() {

    private var transactions: MutableList<Transaction> = mutableListOf()

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

        updateTotals()
        configFabAddTransaction()
    }

    private fun configFabAddTransaction() {
        transactions_add_revenue.setOnClickListener {
            callTransactionDialog(Type.REVENUE)
        }
        transactions_add_expense.setOnClickListener {
            callTransactionDialog(Type.EXPENSE)
        }
    }

    private fun callTransactionDialog(type: Type) {
        TransactionDialog(window.decorView as ViewGroup, this)
                .show(type, object : TransactionDelegate {
                    override fun delegate(transaction: Transaction) {
                        add(transaction)
                    }
                })
    }

    private fun updateTotals() {
        ViewAbstract(this, window.decorView, transactions).updateTotals()
        transactions_listview.adapter = TransactionsListAdapter(transactions,this)
    }

    private fun add(transaction: Transaction) {
        if(isValid(transaction)) {
            transactions.add(transaction)
            updateTotals()
            transactions_add_menu.close(true)
        }
    }

    private fun isValid(transaction: Transaction): Boolean{
        val errorMessages = mutableListOf<String>()
        if(transaction.value.efEqualsIgnoreScale(BigDecimal.ZERO)){
            errorMessages.add(this@TransactionsListActivity.getString(R.string.required_value))
        }
        if(transaction.value < BigDecimal.ZERO){
            errorMessages.add(this@TransactionsListActivity.getString(R.string.negative_value))
        }

        if(errorMessages.size > 0) {
            var fullMessage = ""
            if(errorMessages.size == 1) {
                fullMessage = errorMessages[0]
            }else{
                for(message in errorMessages){
                    fullMessage += "- $message\n"
                }
            }
            Toast.makeText(this@TransactionsListActivity,fullMessage.trim(),Toast.LENGTH_LONG).show()
            return false
        }
        return true
    }
}

configuraForm da classe Dialog da transação:

    private fun configForm(type: Type, delegate: TransactionDelegate) {
        val title = titleByType(type)

        AlertDialog.Builder(context)
                .setTitle(title)
                .setView(dialog)
                .setPositiveButton(R.string.add, { _, _ ->
                    val value = value.text.toString().efParseBigDecimal()
                    val date = date.text.toString().efParseCalendar(context)
                    val category = category.selectedItem.toString()
                    val transaction = Transaction(
                            type = type,
                            value = value,
                            date = date,
                            category = category)

                    delegate.delegate(transaction)
                })
                .setNegativeButton(R.string.cancel, null)
                .show()
    }

Edit: a comparação direta com == do BigDecimal com Kotlin compila para um .equals() e não para um .compareTo(), então ele consideraria valores matematicamente iguais com escalas diferentes como sendo diferentes. Portanto, criei uma extension function que ignora a escala antes de realizar a comparação.

4 respostas

Opa Guilherme, blz?

Para atender a sua necessidade é necessário sobrescrever o comportamento do botão do Dialog. Para isso, logo depois que você chamar o show() você pode a referência do dialog e busca o botão que quer sobrescrever da seguinte forma:

val button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);

Repare que essa amostra busca o botão positivo.

Então você pode aplicar o listener desejado. Sobre a parte de manter as informações, aí vai depender muito do contexto que você espera.

Do jeito que sugeri, ele vai manter as informações enquanto a entidade estiver viva, ou seja, qualquer ação que resulte em destroir uma activity ou fragment que está mantendo o dialog, será necessário salvar as informações que estão no dialog e recuperá-las.

Para isso, uma das soluções comuns envolve salvar os estados da tela, deixo a referência caso não conheça.

[]s

Oi, Alex

Refiro-me apenas a primeira parte de tua resposta. A segunda parte, deixarei para mais tarde. Se me lembro bem, essa segunda parte é para resolver problemas como o Android perder dados digitados não salvos da tela quando tu viras o telefone de lado, né?

Eu não deveria implementar isso de alguma forma no setPositiveButton()? Eu estava pensando em retornar um booleano no delegate() e/ou no add() para decidir se devo ou não fechar a dialog.

De qualquer forma, não consegui encontrar o método getButton(). Esse dialog que colocaste ali é a minha propriedade dialog da classe dialog da transação?

Se quiseres analisar com mais detalhes como está minha solução até o momento, segue o link do projeto no meu GitHub.

Obrigado!

Isso, a segunda parte envolve a instabilidade das entidades do Android que são facilmente destruídas...

Para pegar a referência do Dialog a partir do AlertDialog.Builder(), basta apena você usar o create():

val dialog = AlertDialog.Builder(context)
                .setTitle(title)
                .setView(dialog)
                .setPositiveButton(R.string.add, { _, _ ->
                    val value = value.text.toString().efParseBigDecimal()
                    val date = date.text.toString().efParseCalendar(context)
                    val category = category.selectedItem.toString()
                    val transaction = Transaction(
                            type = type,
                            value = value,
                            date = date,
                            category = category)

                    delegate.delegate(transaction)
                })
                .setNegativeButton(R.string.cancel, null)
                .create()
        dialog.show()
        val button = dialog.getButton(AlertDialog.BUTTON_POSITIVE)

Infelizmente não tem como modificar o comportamento pelo setPositiveButton(), pois já mantém o comportamento de fechar o dialog encapsulado.

[]s

solução!

Oi, Alex

Descobri onde estava a minha confusão. Por dialog, estavas te referindo ao AlertDialog, mas eu havia entendido que era a minha propriedade dialog (aquela que vai dentro do .setView()).

Porém, tive depois alguns outros problemas, pois alterar o evento de click na variável button estava causando NullPointerException, então dei uma pesquisada online e cheguei ao seguinte código alterando o retorno do método delegate() para Boolean (vou alterar o nome dele também porque não está muito claro o que ele faz):

    private fun configForm(type: Type, delegate: TransactionDelegate) {
        val title = titleByType(type)
        val alertDialog = AlertDialog.Builder(context)
                .setTitle(title)
                .setView(dialog)
                .setPositiveButton(R.string.add, null)
                .setNegativeButton(R.string.cancel, null)
                .create()

        alertDialog.setOnShowListener {
            val button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
            button.setOnClickListener {
                val value = value.text.toString().efParseBigDecimal()
                val date = date.text.toString().efParseCalendar(context)
                val category = category.selectedItem.toString()
                val transaction = Transaction(
                        type = type,
                        value = value,
                        date = date,
                        category = category)

                if(delegate.delegate(transaction)){
                    alertDialog.dismiss()
                }
            }
        }
        alertDialog.show()
    }

Obrigado pela ajuda!

Abraço!