[fenix] For https://github.com/mozilla-mobile/fenix/issues/24849 - Add an address editor screen
parent
c177ad7a76
commit
358e475609
@ -0,0 +1,52 @@
|
||||
/* 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
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.SecureFragment
|
||||
import org.mozilla.fenix.databinding.FragmentAddressEditorBinding
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.showToolbar
|
||||
import org.mozilla.fenix.settings.address.controller.DefaultAddressEditorController
|
||||
import org.mozilla.fenix.settings.address.interactor.AddressEditorInteractor
|
||||
import org.mozilla.fenix.settings.address.interactor.DefaultAddressEditorInteractor
|
||||
import org.mozilla.fenix.settings.address.view.AddressEditorView
|
||||
|
||||
/**
|
||||
* Displays an address editor for adding and editing an address.
|
||||
*/
|
||||
class AddressEditorFragment : SecureFragment(R.layout.fragment_address_editor) {
|
||||
|
||||
private lateinit var addressEditorView: AddressEditorView
|
||||
private lateinit var interactor: AddressEditorInteractor
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val storage = requireContext().components.core.autofillStorage
|
||||
|
||||
interactor = DefaultAddressEditorInteractor(
|
||||
controller = DefaultAddressEditorController(
|
||||
storage = storage,
|
||||
lifecycleScope = lifecycleScope,
|
||||
navController = findNavController()
|
||||
)
|
||||
)
|
||||
|
||||
val binding = FragmentAddressEditorBinding.bind(view)
|
||||
|
||||
addressEditorView = AddressEditorView(binding, interactor)
|
||||
addressEditorView.bind()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
showToolbar(getString(R.string.addresses_add_address))
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/* 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.controller
|
||||
|
||||
import androidx.navigation.NavController
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.concept.storage.UpdatableAddressFields
|
||||
import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage
|
||||
import org.mozilla.fenix.settings.address.AddressEditorFragment
|
||||
import org.mozilla.fenix.settings.address.interactor.AddressEditorInteractor
|
||||
|
||||
/**
|
||||
* [AddressEditorFragment] controller. An interface that handles the view manipulation of the
|
||||
* credit card editor.
|
||||
*/
|
||||
interface AddressEditorController {
|
||||
|
||||
/**
|
||||
* @see [AddressEditorInteractor.onCancelButtonClicked]
|
||||
*/
|
||||
fun handleCancelButtonClicked()
|
||||
|
||||
/**
|
||||
* @see [AddressEditorInteractor.onSaveAddress]
|
||||
*/
|
||||
fun handleSaveAddress(addressFields: UpdatableAddressFields)
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation of [AddressEditorController].
|
||||
*
|
||||
* @param storage An instance of the [AutofillCreditCardsAddressesStorage] for adding and retrieving
|
||||
* addresses.
|
||||
* @param lifecycleScope [CoroutineScope] scope to launch coroutines.
|
||||
* @param navController [NavController] used for navigation.
|
||||
*/
|
||||
class DefaultAddressEditorController(
|
||||
private val storage: AutofillCreditCardsAddressesStorage,
|
||||
private val lifecycleScope: CoroutineScope,
|
||||
private val navController: NavController,
|
||||
) : AddressEditorController {
|
||||
|
||||
override fun handleCancelButtonClicked() {
|
||||
navController.popBackStack()
|
||||
}
|
||||
|
||||
override fun handleSaveAddress(addressFields: UpdatableAddressFields) {
|
||||
lifecycleScope.launch {
|
||||
storage.addAddress(addressFields)
|
||||
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/* 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.interactor
|
||||
|
||||
import mozilla.components.concept.storage.UpdatableAddressFields
|
||||
import org.mozilla.fenix.settings.address.controller.AddressEditorController
|
||||
|
||||
/**
|
||||
* Interface for the address editor interactor.
|
||||
*/
|
||||
interface AddressEditorInteractor {
|
||||
|
||||
/**
|
||||
* Navigates back to the autofill preference settings. Called when a user taps on the
|
||||
* "Cancel" button.
|
||||
*/
|
||||
fun onCancelButtonClicked()
|
||||
|
||||
/**
|
||||
* Saves the provided address field into the autofill storage. Called when a user
|
||||
* taps on the save menu item or "Save" button.
|
||||
*
|
||||
* @param addressFields A [UpdatableAddressFields] record to add.
|
||||
*/
|
||||
fun onSaveAddress(addressFields: UpdatableAddressFields)
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation of [AddressEditorInteractor].
|
||||
*
|
||||
* @param controller An instance of [AddressEditorController] which will be delegated for all
|
||||
* user interactions.
|
||||
*/
|
||||
class DefaultAddressEditorInteractor(
|
||||
private val controller: AddressEditorController
|
||||
) : AddressEditorInteractor {
|
||||
|
||||
override fun onCancelButtonClicked() {
|
||||
controller.handleCancelButtonClicked()
|
||||
}
|
||||
|
||||
override fun onSaveAddress(addressFields: UpdatableAddressFields) {
|
||||
controller.handleSaveAddress(addressFields)
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/* 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 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.databinding.FragmentAddressEditorBinding
|
||||
import org.mozilla.fenix.ext.placeCursorAtEnd
|
||||
import org.mozilla.fenix.settings.address.interactor.AddressEditorInteractor
|
||||
|
||||
/**
|
||||
* Shows an address editor for adding or updating an address.
|
||||
*/
|
||||
class AddressEditorView(
|
||||
private val binding: FragmentAddressEditorBinding,
|
||||
private val interactor: AddressEditorInteractor
|
||||
) {
|
||||
|
||||
/**
|
||||
* Binds the view.
|
||||
*/
|
||||
fun bind() {
|
||||
binding.fullNameInput.apply {
|
||||
requestFocus()
|
||||
placeCursorAtEnd()
|
||||
showKeyboard()
|
||||
}
|
||||
|
||||
binding.cancelButton.setOnClickListener {
|
||||
interactor.onCancelButtonClicked()
|
||||
}
|
||||
|
||||
binding.saveButton.setOnClickListener {
|
||||
saveAddress()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun saveAddress() {
|
||||
binding.root.hideKeyboard()
|
||||
|
||||
interactor.onSaveAddress(
|
||||
UpdatableAddressFields(
|
||||
givenName = binding.fullNameInput.text.toString(),
|
||||
additionalName = "",
|
||||
familyName = "",
|
||||
organization = "",
|
||||
streetAddress = binding.streetAddressInput.text.toString(),
|
||||
addressLevel3 = "",
|
||||
addressLevel2 = "",
|
||||
addressLevel1 = "",
|
||||
postalCode = binding.zipInput.text.toString(),
|
||||
country = "",
|
||||
tel = binding.phoneInput.toString(),
|
||||
email = binding.emailInput.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,371 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp">
|
||||
|
||||
<!-- Full Name -->
|
||||
<TextView
|
||||
android:id="@+id/full_name_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:letterSpacing="0.05"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:text="@string/addresses_full_name"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="12sp"
|
||||
android:labelFor="@id/card_number_input"
|
||||
app:fontFamily="@font/metropolis_semibold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/full_name_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/textPrimary"
|
||||
app:errorEnabled="true"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/full_name_title">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/full_name_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:letterSpacing="0.01"
|
||||
android:lineSpacingExtra="8sp"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- Street Address -->
|
||||
<TextView
|
||||
android:id="@+id/street_address_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:letterSpacing="0.05"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:text="@string/addresses_street_address"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="12sp"
|
||||
android:labelFor="@id/street_address_input"
|
||||
app:fontFamily="@font/metropolis_semibold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/full_name_layout" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/street_address_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/textPrimary"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/street_address_title">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/street_address_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:letterSpacing="0.01"
|
||||
android:lineSpacingExtra="8sp"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- City -->
|
||||
<TextView
|
||||
android:id="@+id/city_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:letterSpacing="0.05"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:text="@string/addresses_city"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="12sp"
|
||||
android:labelFor="@id/city_input"
|
||||
app:fontFamily="@font/metropolis_semibold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/street_address_layout" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/city_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/textPrimary"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/city_title">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/city_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:letterSpacing="0.01"
|
||||
android:lineSpacingExtra="8sp"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- State -->
|
||||
<TextView
|
||||
android:id="@+id/state_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:letterSpacing="0.05"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:text="@string/addresses_state"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="12sp"
|
||||
android:labelFor="@id/state_input"
|
||||
app:fontFamily="@font/metropolis_semibold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/city_layout" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/state_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/textPrimary"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintHorizontal_bias="0.8"
|
||||
app:layout_constraintEnd_toStartOf="@+id/zip_layout"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/state_title">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/state_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:letterSpacing="0.01"
|
||||
android:lineSpacingExtra="8sp"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- Zip -->
|
||||
<TextView
|
||||
android:id="@+id/zip_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:letterSpacing="0.05"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:text="@string/addresses_zip"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="12sp"
|
||||
android:labelFor="@id/zip_input"
|
||||
app:fontFamily="@font/metropolis_semibold"
|
||||
app:layout_constraintStart_toStartOf="@+id/zip_layout"
|
||||
app:layout_constraintTop_toBottomOf="@+id/city_layout" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/zip_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:textColor="?attr/textPrimary"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/state_layout"
|
||||
app:layout_constraintTop_toBottomOf="@+id/zip_title">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/zip_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:letterSpacing="0.01"
|
||||
android:lineSpacingExtra="8sp"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- Phone -->
|
||||
<TextView
|
||||
android:id="@+id/phone_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:letterSpacing="0.05"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:text="@string/addresses_phone"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="12sp"
|
||||
android:labelFor="@id/phone_input"
|
||||
app:fontFamily="@font/metropolis_semibold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/state_layout" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/phone_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/textPrimary"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/phone_title">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/phone_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:letterSpacing="0.01"
|
||||
android:lineSpacingExtra="8sp"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- Email -->
|
||||
<TextView
|
||||
android:id="@+id/email_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:letterSpacing="0.05"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:text="@string/addresses_email"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="12sp"
|
||||
android:labelFor="@id/city_input"
|
||||
app:fontFamily="@font/metropolis_semibold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/phone_layout" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/email_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/textPrimary"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/email_title">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/email_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:letterSpacing="0.01"
|
||||
android:lineSpacingExtra="8sp"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/delete_button"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:letterSpacing="0"
|
||||
android:padding="10dp"
|
||||
android:text="@string/addressess_delete_address_button"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/fx_mobile_text_color_warning"
|
||||
android:visibility="gone"
|
||||
app:fontFamily="@font/metropolis_semibold"
|
||||
app:layout_constraintTop_toBottomOf="@+id/email_layout"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/cancel_button"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:letterSpacing="0"
|
||||
android:padding="10dp"
|
||||
android:text="@string/addresses_cancel_button"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="?attr/textPrimary"
|
||||
android:textStyle="bold"
|
||||
app:fontFamily="@font/metropolis_semibold"
|
||||
app:layout_constraintTop_toBottomOf="@+id/email_layout"
|
||||
app:layout_constraintEnd_toStartOf="@id/save_button" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/save_button"
|
||||
style="@style/NeutralButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:text="@string/addresses_save_button"
|
||||
app:layout_constraintTop_toTopOf="@+id/cancel_button"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/cancel_button"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
@ -0,0 +1,47 @@
|
||||
/* 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
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.databinding.FragmentAddressEditorBinding
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.settings.address.interactor.AddressEditorInteractor
|
||||
import org.mozilla.fenix.settings.address.view.AddressEditorView
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class AddressEditorViewTest {
|
||||
|
||||
private lateinit var view: View
|
||||
private lateinit var interactor: AddressEditorInteractor
|
||||
private lateinit var addressEditorView: AddressEditorView
|
||||
private lateinit var binding: FragmentAddressEditorBinding
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
view = LayoutInflater.from(testContext).inflate(R.layout.fragment_address_editor, null)
|
||||
binding = FragmentAddressEditorBinding.bind(view)
|
||||
interactor = mockk(relaxed = true)
|
||||
|
||||
addressEditorView = spyk(AddressEditorView(binding, interactor))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN the cancel button is clicked THEN interactor is called`() {
|
||||
addressEditorView.bind()
|
||||
|
||||
binding.cancelButton.performClick()
|
||||
|
||||
verify { interactor.onCancelButtonClicked() }
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/* 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.controller
|
||||
|
||||
import androidx.navigation.NavController
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.test.TestCoroutineScope
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import mozilla.components.concept.storage.UpdatableAddressFields
|
||||
import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage
|
||||
import mozilla.components.support.test.rule.MainCoroutineRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class DefaultAddressEditorControllerTest {
|
||||
|
||||
private val storage: AutofillCreditCardsAddressesStorage = mockk(relaxed = true)
|
||||
private val navController: NavController = mockk(relaxed = true)
|
||||
|
||||
@get:Rule
|
||||
val coroutinesTestRule = MainCoroutineRule()
|
||||
private val testCoroutineScope = TestCoroutineScope()
|
||||
|
||||
private lateinit var controller: DefaultAddressEditorController
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
controller = spyk(
|
||||
DefaultAddressEditorController(
|
||||
storage = storage,
|
||||
lifecycleScope = testCoroutineScope,
|
||||
navController = navController,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN cancel button is clicked THEN pop the NavController back stack`() {
|
||||
controller.handleCancelButtonClicked()
|
||||
|
||||
verify {
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN a new address record WHEN save address is called THEN save the new address record to storage`() = testCoroutineScope.runBlockingTest {
|
||||
val addressFields = UpdatableAddressFields(
|
||||
givenName = "John",
|
||||
additionalName = "",
|
||||
familyName = "Smith",
|
||||
organization = "Mozilla",
|
||||
streetAddress = "123 Sesame Street",
|
||||
addressLevel3 = "",
|
||||
addressLevel2 = "",
|
||||
addressLevel1 = "",
|
||||
postalCode = "90210",
|
||||
country = "US",
|
||||
tel = "+1 519 555-5555",
|
||||
email = "foo@bar.com"
|
||||
)
|
||||
|
||||
controller.handleSaveAddress(addressFields)
|
||||
|
||||
coVerify {
|
||||
storage.addAddress(addressFields)
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/* 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.interactor
|
||||
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.concept.storage.UpdatableAddressFields
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.settings.address.controller.AddressEditorController
|
||||
|
||||
class DefaultAddressEditorInteractorTest {
|
||||
|
||||
private val controller: AddressEditorController = mockk(relaxed = true)
|
||||
|
||||
private lateinit var interactor: AddressEditorInteractor
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
interactor = DefaultAddressEditorInteractor(controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN cancel button is clicked THEN forward to controller handler`() {
|
||||
interactor.onCancelButtonClicked()
|
||||
verify { controller.handleCancelButtonClicked() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN save button is clicked THEN forward to controller handler`() {
|
||||
val addressFields = UpdatableAddressFields(
|
||||
givenName = "John",
|
||||
additionalName = "",
|
||||
familyName = "Smith",
|
||||
organization = "Mozilla",
|
||||
streetAddress = "123 Sesame Street",
|
||||
addressLevel3 = "",
|
||||
addressLevel2 = "",
|
||||
addressLevel1 = "",
|
||||
postalCode = "90210",
|
||||
country = "US",
|
||||
tel = "+1 519 555-5555",
|
||||
email = "foo@bar.com"
|
||||
)
|
||||
|
||||
interactor.onSaveAddress(addressFields)
|
||||
|
||||
verify { controller.handleSaveAddress(addressFields) }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue