/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.fenix.settings.address.view import android.content.Context import android.content.DialogInterface import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import mozilla.components.browser.state.search.RegionState import mozilla.components.concept.storage.Address import mozilla.components.concept.storage.UpdatableAddressFields import mozilla.components.support.ktx.android.view.hideKeyboard import mozilla.components.support.ktx.android.view.showKeyboard import org.mozilla.fenix.GleanMetrics.Addresses import org.mozilla.fenix.R import org.mozilla.fenix.databinding.FragmentAddressEditorBinding import org.mozilla.fenix.ext.placeCursorAtEnd import org.mozilla.fenix.settings.address.AddressEditorFragment import org.mozilla.fenix.settings.address.AddressUtils.countries import org.mozilla.fenix.settings.address.Country import org.mozilla.fenix.settings.address.DEFAULT_COUNTRY import org.mozilla.fenix.settings.address.interactor.AddressEditorInteractor import org.mozilla.fenix.settings.address.toCountryCode /** * An address editor for adding or updating an address. * * @param binding The binding used to display the view. * @param interactor [AddressEditorInteractor] used to respond to any user interactions. * @param region If the [RegionState] is available, it will be used to set the country when adding a new address. * @param address An [Address] to edit. */ class AddressEditorView( private val binding: FragmentAddressEditorBinding, private val interactor: AddressEditorInteractor, private val region: RegionState? = RegionState.Default, private val address: Address? = null, ) { /** * Binds the view in the [AddressEditorFragment], using the current [Address] if available. */ fun bind() { binding.firstNameInput.apply { requestFocus() placeCursorAtEnd() showKeyboard() } binding.cancelButton.setOnClickListener { interactor.onCancelButtonClicked() } binding.saveButton.setOnClickListener { saveAddress() } address?.let { address -> binding.emailInput.setText(address.email) binding.phoneInput.setText(address.tel) binding.firstNameInput.setText(address.givenName) binding.middleNameInput.setText(address.additionalName) binding.lastNameInput.setText(address.familyName) binding.streetAddressInput.setText(address.streetAddress) binding.cityInput.setText(address.addressLevel2) binding.zipInput.setText(address.postalCode) binding.deleteButton.apply { isVisible = true setOnClickListener { view -> showConfirmDeleteAddressDialog(view.context, address.guid) } } } bindDropdowns() } internal fun saveAddress() { binding.root.hideKeyboard() val addressFields = UpdatableAddressFields( givenName = binding.firstNameInput.text.toString(), additionalName = binding.middleNameInput.text.toString(), familyName = binding.lastNameInput.text.toString(), organization = "", streetAddress = binding.streetAddressInput.text.toString(), addressLevel3 = "", addressLevel2 = binding.cityInput.text.toString(), addressLevel1 = binding.subregionDropDown.selectedItem.toString(), postalCode = binding.zipInput.text.toString(), country = binding.countryDropDown.selectedItem.toString().toCountryCode(), tel = binding.phoneInput.text.toString(), email = binding.emailInput.text.toString(), ) if (address != null) { interactor.onUpdateAddress(address.guid, addressFields) Addresses.updated.add() } else { interactor.onSaveAddress(addressFields) Addresses.saved.add() } } internal fun showConfirmDeleteAddressDialog(context: Context, guid: String) { AlertDialog.Builder(context).apply { setMessage(R.string.addressess_confirm_dialog_message) setNegativeButton(R.string.addressess_confirm_dialog_cancel_button) { dialog: DialogInterface, _ -> dialog.cancel() } setPositiveButton(R.string.addressess_confirm_dialog_ok_button) { _, _ -> interactor.onDeleteAddress(guid) Addresses.deleted.add() } create() }.show() } private fun bindDropdowns() { val adapter = ArrayAdapter( binding.root.context, android.R.layout.simple_spinner_dropdown_item, countries.values.map { it.displayName }, ) val selectedCountryKey = (address?.country ?: region?.home).takeIf { it in countries.keys } ?: DEFAULT_COUNTRY val selectedPosition = countries.values .indexOfFirst { it.countryCode == selectedCountryKey } .takeIf { it > 0 } ?: 0 binding.countryDropDown.adapter = adapter binding.countryDropDown.setSelection(selectedPosition) binding.countryDropDown.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected( parent: AdapterView<*>?, view: View?, position: Int, id: Long, ) { val newCountryKey = binding.countryDropDown.selectedItem.toString().toCountryCode() countries[newCountryKey]?.let { country -> bindSubregionDropdown(country) } } override fun onNothingSelected(p0: AdapterView<*>?) = Unit } countries[selectedCountryKey]?.let { country -> bindSubregionDropdown(country) } } private fun bindSubregionDropdown(country: Country) { val subregions = country.subregions val selectedSubregion = address?.addressLevel1?.takeIf { it in subregions } ?: subregions.first() val adapter = ArrayAdapter( binding.root.context, android.R.layout.simple_spinner_dropdown_item, country.subregions, ) val selectedPosition = subregions.indexOf(selectedSubregion).takeIf { it > 0 } ?: 0 binding.subregionDropDown.adapter = adapter binding.subregionDropDown.setSelection(selectedPosition) binding.subregionTitle.setText(country.subregionTitleResource) } }