Using now Otalia Studios Autocomplete for Bank Autocomplete list in AddAccountDialog as it's way more performant than Android's AutoCompleteTextView

This commit is contained in:
dankito 2020-04-23 16:54:34 +02:00
parent 5ce48322a1
commit a8ae3e9006
8 changed files with 111 additions and 73 deletions

View File

@ -5,6 +5,7 @@ ext {
appVersionCode = 1 appVersionCode = 1
kotlinVersion = '1.3.72' kotlinVersion = '1.3.72'
kotlinCoroutinesVersion = "1.3.5"
javaUtilsVersion = '1.0.16-SNAPSHOT' javaUtilsVersion = '1.0.16-SNAPSHOT'
@ -20,6 +21,8 @@ ext {
clansFloatingActionButtonVersion = '1.6.4' clansFloatingActionButtonVersion = '1.6.4'
autocompleteVersion = "1.1.0"
multiDexVersion = "2.0.1" multiDexVersion = "2.0.1"
appCompatVersion = "1.1.0" appCompatVersion = "1.1.0"

View File

@ -58,7 +58,10 @@ dependencies {
implementation "com.github.clans:fab:$clansFloatingActionButtonVersion" implementation "com.github.clans:fab:$clansFloatingActionButtonVersion"
implementation "com.otaliastudios:autocomplete:$autocompleteVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion"
implementation "net.dankito.utils:android-utils:$androidUtilsVersion", { implementation "net.dankito.utils:android-utils:$androidUtilsVersion", {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7' exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'

View File

@ -1,53 +1,39 @@
package net.dankito.banking.fints4java.android.ui.adapter package net.dankito.banking.fints4java.android.ui.adapter
import android.content.Context.LAYOUT_INFLATER_SERVICE
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
import kotlinx.android.synthetic.main.list_item_bank_info.view.*
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.banking.ui.presenter.BankingPresenter import net.dankito.banking.fints4java.android.ui.adapter.viewholder.BankInfoViewHolder
import net.dankito.banking.fints4java.android.ui.adapter.filter.BankInfoFilter
import net.dankito.fints.model.BankInfo import net.dankito.fints.model.BankInfo
import net.dankito.utils.android.extensions.setTintColor import net.dankito.utils.android.extensions.setTintColor
import net.dankito.utils.android.ui.adapter.ListAdapter import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter
open class BankListAdapter(protected val presenter: BankingPresenter) : ListAdapter<BankInfo>(), Filterable { open class BankListAdapter(protected val itemClicked: ((BankInfo) -> Unit)? = null) : ListRecyclerAdapter<BankInfo, BankInfoViewHolder>() {
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? { override fun getListItemLayoutId() = R.layout.list_item_bank_info
val item = getItem(position) override fun createViewHolder(itemView: View): BankInfoViewHolder {
return BankInfoViewHolder(itemView)
}
val inflater = parent?.context?.getSystemService(LAYOUT_INFLATER_SERVICE) as? LayoutInflater override fun bindItemToView(viewHolder: BankInfoViewHolder, item: BankInfo) {
val view = convertView ?: inflater?.inflate(R.layout.list_item_bank_info, parent, false)
view?.let {
if (item.supportsFinTs3_0) { if (item.supportsFinTs3_0) {
view.imgSupportsFints30.setImageResource(R.drawable.ic_check_circle_white_48dp) viewHolder.imgSupportsFints30.setImageResource(R.drawable.ic_check_circle_white_48dp)
view.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_supported) viewHolder.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_supported)
} }
else { else {
view.imgSupportsFints30.setImageResource(R.drawable.ic_clear_white_48dp) viewHolder.imgSupportsFints30.setImageResource(R.drawable.ic_clear_white_48dp)
view.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_not_supported) viewHolder.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_not_supported)
} }
view.txtvwBankName.text = item.name viewHolder.txtvwBankName.text = item.name
view.txtvwBankCode.text = item.bankCode viewHolder.txtvwBankCode.text = item.bankCode
view.txtvwBankAddress.text = item.postalCode + " " + item.city viewHolder.txtvwBankAddress.text = item.postalCode + " " + item.city
}
return view viewHolder.itemView.setOnClickListener {
} itemClicked?.invoke(item)
override fun getFilter(): Filter {
return BankInfoFilter(presenter) {
this.setItems(it)
} }
} }

View File

@ -1,25 +0,0 @@
package net.dankito.banking.fints4java.android.ui.adapter.filter
import android.widget.Filter
import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.fints.model.BankInfo
open class BankInfoFilter(protected val presenter: BankingPresenter,
protected val publishResultsCallback: (List<BankInfo>) -> Unit) : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredBanks = presenter.searchBanksByNameBankCodeOrCity(constraint?.toString())
val results = FilterResults()
results.values = filteredBanks
return results
}
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
publishResultsCallback(results.values as List<BankInfo>)
}
}

View File

@ -0,0 +1,35 @@
package net.dankito.banking.fints4java.android.ui.adapter.presenter
import android.content.Context
import androidx.recyclerview.widget.RecyclerView
import com.otaliastudios.autocomplete.RecyclerViewPresenter
import kotlinx.coroutines.*
import net.dankito.banking.fints4java.android.ui.adapter.BankListAdapter
import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.fints.model.BankInfo
open class BankInfoPresenter(protected val presenter: BankingPresenter, context: Context) : RecyclerViewPresenter<BankInfo>(context) {
protected val adapter = BankListAdapter { dispatchClick(it) }
protected var lastSearchBanksJob: Job? = null
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
return adapter
}
override fun onQuery(query: CharSequence?) {
lastSearchBanksJob?.cancel()
lastSearchBanksJob = GlobalScope.launch(Dispatchers.IO) {
val filteredBanks = presenter.searchBanksByNameBankCodeOrCity(query?.toString())
withContext(Dispatchers.Main) {
adapter.items = filteredBanks
}
}
}
}

View File

@ -0,0 +1,20 @@
package net.dankito.banking.fints4java.android.ui.adapter.viewholder
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.list_item_bank_info.view.*
open class BankInfoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imgSupportsFints30: ImageView = itemView.imgSupportsFints30
val txtvwBankName: TextView = itemView.txtvwBankName
val txtvwBankCode: TextView = itemView.txtvwBankCode
val txtvwBankAddress: TextView = itemView.txtvwBankAddress
}

View File

@ -2,6 +2,8 @@ package net.dankito.banking.fints4java.android.ui.dialogs
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
@ -12,10 +14,12 @@ import android.widget.TextView
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.otaliastudios.autocomplete.Autocomplete
import com.otaliastudios.autocomplete.AutocompleteCallback
import kotlinx.android.synthetic.main.dialog_add_account.* import kotlinx.android.synthetic.main.dialog_add_account.*
import kotlinx.android.synthetic.main.dialog_add_account.view.* import kotlinx.android.synthetic.main.dialog_add_account.view.*
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.ui.adapter.BankListAdapter import net.dankito.banking.fints4java.android.ui.adapter.presenter.BankInfoPresenter
import net.dankito.banking.ui.model.responses.AddAccountResponse import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.presenter.BankingPresenter import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.fints.model.BankInfo import net.dankito.fints.model.BankInfo
@ -31,8 +35,6 @@ open class AddAccountDialog : DialogFragment() {
protected lateinit var presenter: BankingPresenter protected lateinit var presenter: BankingPresenter
protected lateinit var adapter: BankListAdapter
protected var selectedBank: BankInfo? = null protected var selectedBank: BankInfo? = null
@ -40,7 +42,6 @@ open class AddAccountDialog : DialogFragment() {
this.presenter = presenter this.presenter = presenter
presenter.preloadBanksAsync() presenter.preloadBanksAsync()
this.adapter = BankListAdapter(presenter)
val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog
setStyle(STYLE_NORMAL, style) setStyle(STYLE_NORMAL, style)
@ -60,10 +61,7 @@ open class AddAccountDialog : DialogFragment() {
} }
protected open fun setupUI(rootView: View) { protected open fun setupUI(rootView: View) {
rootView.edtxtBankCode.threshold = 1 // will start working from first character initBankListAutocompletion(rootView)
rootView.edtxtBankCode.setAdapter(adapter)
rootView.edtxtBankCode.setOnItemClickListener { _, _, position, _ -> bankSelected(adapter.getItem(position)) }
rootView.edtxtCustomerId.addTextChangedListener(otherEditTextChangedWatcher) rootView.edtxtCustomerId.addTextChangedListener(otherEditTextChangedWatcher)
rootView.edtxtPin.addTextChangedListener(otherEditTextChangedWatcher) rootView.edtxtPin.addTextChangedListener(otherEditTextChangedWatcher)
@ -72,6 +70,26 @@ open class AddAccountDialog : DialogFragment() {
rootView.btnCancel.setOnClickListener { dismiss() } rootView.btnCancel.setOnClickListener { dismiss() }
} }
private fun initBankListAutocompletion(rootView: View) {
val autocompleteCallback = object : AutocompleteCallback<BankInfo> {
override fun onPopupItemClicked(editable: Editable, item: BankInfo): Boolean {
bankSelected(item)
return true
}
override fun onPopupVisibilityChanged(shown: Boolean) {}
}
Autocomplete.on<BankInfo>(rootView.edtxtBankCode)
.with(6f)
.with(ColorDrawable(Color.WHITE))
.with(autocompleteCallback)
.with(BankInfoPresenter(presenter, rootView.context))
.build()
}
protected open fun addAccount() { protected open fun addAccount() {
selectedBank?.let { selectedBank -> // should always be non-null at this stage selectedBank?.let { selectedBank -> // should always be non-null at this stage
val customerId = edtxtCustomerId.text.toString() val customerId = edtxtCustomerId.text.toString()
@ -156,8 +174,6 @@ open class AddAccountDialog : DialogFragment() {
edtxtFinTsServerAddress.setText(bank.pinTanAddress) edtxtFinTsServerAddress.setText(bank.pinTanAddress)
edtxtBankCode.clearListSelection()
checkIfRequiredDataEnteredOnUiThread() checkIfRequiredDataEnteredOnUiThread()
if (bank.supportsFinTs3_0 == false) { if (bank.supportsFinTs3_0 == false) {

View File

@ -13,7 +13,7 @@
android:hint="@string/dialog_add_account_enter_bank_code" android:hint="@string/dialog_add_account_enter_bank_code"
> >
<AutoCompleteTextView <com.google.android.material.textfield.TextInputEditText
android:id="@+id/edtxtBankCode" android:id="@+id/edtxtBankCode"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/dialog_add_account_edit_text_height" android:layout_height="@dimen/dialog_add_account_edit_text_height"