From a8ae3e900620f31a54b5e9f20ae223d264518e71 Mon Sep 17 00:00:00 2001 From: dankito Date: Thu, 23 Apr 2020 16:54:34 +0200 Subject: [PATCH] Using now Otalia Studios Autocomplete for Bank Autocomplete list in AddAccountDialog as it's way more performant than Android's AutoCompleteTextView --- build.gradle | 3 + fints4javaAndroidApp/build.gradle | 3 + .../android/ui/adapter/BankListAdapter.kt | 60 +++++++------------ .../ui/adapter/filter/BankInfoFilter.kt | 25 -------- .../ui/adapter/presenter/BankInfoPresenter.kt | 35 +++++++++++ .../adapter/viewholder/BankInfoViewHolder.kt | 20 +++++++ .../android/ui/dialogs/AddAccountDialog.kt | 36 +++++++---- .../main/res/layout/dialog_add_account.xml | 2 +- 8 files changed, 111 insertions(+), 73 deletions(-) delete mode 100644 fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/filter/BankInfoFilter.kt create mode 100644 fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/presenter/BankInfoPresenter.kt create mode 100644 fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/viewholder/BankInfoViewHolder.kt diff --git a/build.gradle b/build.gradle index adf3707e..2b03dd4f 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,7 @@ ext { appVersionCode = 1 kotlinVersion = '1.3.72' + kotlinCoroutinesVersion = "1.3.5" javaUtilsVersion = '1.0.16-SNAPSHOT' @@ -20,6 +21,8 @@ ext { clansFloatingActionButtonVersion = '1.6.4' + autocompleteVersion = "1.1.0" + multiDexVersion = "2.0.1" appCompatVersion = "1.1.0" diff --git a/fints4javaAndroidApp/build.gradle b/fints4javaAndroidApp/build.gradle index 24ad3316..b9ec94e3 100644 --- a/fints4javaAndroidApp/build.gradle +++ b/fints4javaAndroidApp/build.gradle @@ -58,7 +58,10 @@ dependencies { implementation "com.github.clans:fab:$clansFloatingActionButtonVersion" + implementation "com.otaliastudios:autocomplete:$autocompleteVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion" implementation "net.dankito.utils:android-utils:$androidUtilsVersion", { exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7' diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/BankListAdapter.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/BankListAdapter.kt index 72c3541e..8c468118 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/BankListAdapter.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/BankListAdapter.kt @@ -1,53 +1,39 @@ 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.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.ui.presenter.BankingPresenter -import net.dankito.banking.fints4java.android.ui.adapter.filter.BankInfoFilter +import net.dankito.banking.fints4java.android.ui.adapter.viewholder.BankInfoViewHolder import net.dankito.fints.model.BankInfo 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(), Filterable { +open class BankListAdapter(protected val itemClicked: ((BankInfo) -> Unit)? = null) : ListRecyclerAdapter() { - override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? { + override fun getListItemLayoutId() = R.layout.list_item_bank_info - val item = getItem(position) - - val inflater = parent?.context?.getSystemService(LAYOUT_INFLATER_SERVICE) as? LayoutInflater - val view = convertView ?: inflater?.inflate(R.layout.list_item_bank_info, parent, false) - - view?.let { - if (item.supportsFinTs3_0) { - view.imgSupportsFints30.setImageResource(R.drawable.ic_check_circle_white_48dp) - view.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_supported) - } - else { - view.imgSupportsFints30.setImageResource(R.drawable.ic_clear_white_48dp) - view.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_not_supported) - } - - view.txtvwBankName.text = item.name - - view.txtvwBankCode.text = item.bankCode - - view.txtvwBankAddress.text = item.postalCode + " " + item.city - } - - return view + override fun createViewHolder(itemView: View): BankInfoViewHolder { + return BankInfoViewHolder(itemView) } + override fun bindItemToView(viewHolder: BankInfoViewHolder, item: BankInfo) { + if (item.supportsFinTs3_0) { + viewHolder.imgSupportsFints30.setImageResource(R.drawable.ic_check_circle_white_48dp) + viewHolder.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_supported) + } + else { + viewHolder.imgSupportsFints30.setImageResource(R.drawable.ic_clear_white_48dp) + viewHolder.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_not_supported) + } - override fun getFilter(): Filter { - return BankInfoFilter(presenter) { - this.setItems(it) + viewHolder.txtvwBankName.text = item.name + + viewHolder.txtvwBankCode.text = item.bankCode + + viewHolder.txtvwBankAddress.text = item.postalCode + " " + item.city + + viewHolder.itemView.setOnClickListener { + itemClicked?.invoke(item) } } diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/filter/BankInfoFilter.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/filter/BankInfoFilter.kt deleted file mode 100644 index b4493285..00000000 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/filter/BankInfoFilter.kt +++ /dev/null @@ -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) -> 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) - } - -} \ No newline at end of file diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/presenter/BankInfoPresenter.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/presenter/BankInfoPresenter.kt new file mode 100644 index 00000000..10dfa0ce --- /dev/null +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/presenter/BankInfoPresenter.kt @@ -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(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 + } + } + } + +} \ No newline at end of file diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/viewholder/BankInfoViewHolder.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/viewholder/BankInfoViewHolder.kt new file mode 100644 index 00000000..89a9726d --- /dev/null +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/viewholder/BankInfoViewHolder.kt @@ -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 + +} \ No newline at end of file diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/AddAccountDialog.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/AddAccountDialog.kt index 67bf4de4..c1ed8295 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/AddAccountDialog.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/AddAccountDialog.kt @@ -2,6 +2,8 @@ package net.dankito.banking.fints4java.android.ui.dialogs import android.content.Context import android.content.DialogInterface +import android.graphics.Color +import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.text.Editable import android.text.TextWatcher @@ -12,10 +14,12 @@ import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity 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.view.* 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.presenter.BankingPresenter import net.dankito.fints.model.BankInfo @@ -31,8 +35,6 @@ open class AddAccountDialog : DialogFragment() { protected lateinit var presenter: BankingPresenter - protected lateinit var adapter: BankListAdapter - protected var selectedBank: BankInfo? = null @@ -40,7 +42,6 @@ open class AddAccountDialog : DialogFragment() { this.presenter = presenter presenter.preloadBanksAsync() - this.adapter = BankListAdapter(presenter) val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog setStyle(STYLE_NORMAL, style) @@ -60,10 +61,7 @@ open class AddAccountDialog : DialogFragment() { } protected open fun setupUI(rootView: View) { - rootView.edtxtBankCode.threshold = 1 // will start working from first character - rootView.edtxtBankCode.setAdapter(adapter) - - rootView.edtxtBankCode.setOnItemClickListener { _, _, position, _ -> bankSelected(adapter.getItem(position)) } + initBankListAutocompletion(rootView) rootView.edtxtCustomerId.addTextChangedListener(otherEditTextChangedWatcher) rootView.edtxtPin.addTextChangedListener(otherEditTextChangedWatcher) @@ -72,6 +70,26 @@ open class AddAccountDialog : DialogFragment() { rootView.btnCancel.setOnClickListener { dismiss() } } + private fun initBankListAutocompletion(rootView: View) { + val autocompleteCallback = object : AutocompleteCallback { + + override fun onPopupItemClicked(editable: Editable, item: BankInfo): Boolean { + bankSelected(item) + return true + } + + override fun onPopupVisibilityChanged(shown: Boolean) {} + + } + + Autocomplete.on(rootView.edtxtBankCode) + .with(6f) + .with(ColorDrawable(Color.WHITE)) + .with(autocompleteCallback) + .with(BankInfoPresenter(presenter, rootView.context)) + .build() + } + protected open fun addAccount() { selectedBank?.let { selectedBank -> // should always be non-null at this stage val customerId = edtxtCustomerId.text.toString() @@ -156,8 +174,6 @@ open class AddAccountDialog : DialogFragment() { edtxtFinTsServerAddress.setText(bank.pinTanAddress) - edtxtBankCode.clearListSelection() - checkIfRequiredDataEnteredOnUiThread() if (bank.supportsFinTs3_0 == false) { diff --git a/fints4javaAndroidApp/src/main/res/layout/dialog_add_account.xml b/fints4javaAndroidApp/src/main/res/layout/dialog_add_account.xml index bbc37674..4e02197b 100644 --- a/fints4javaAndroidApp/src/main/res/layout/dialog_add_account.xml +++ b/fints4javaAndroidApp/src/main/res/layout/dialog_add_account.xml @@ -13,7 +13,7 @@ android:hint="@string/dialog_add_account_enter_bank_code" > -