Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion api/src/main/java/app/nexd/android/api/UsersApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import app.nexd.android.api.model.UpdateUserDto;
import app.nexd.android.api.model.User;
import io.reactivex.Observable;
import io.reactivex.Single;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.PUT;
Expand Down Expand Up @@ -66,7 +67,7 @@ Observable<User> userControllerUpdate(
"Content-Type:application/json"
})
@PUT("users/me")
Observable<User> userControllerUpdateMyself(
Single<User> userControllerUpdateMyself(
@retrofit2.http.Body UpdateUserDto updateUserDto
);

Expand Down
22 changes: 11 additions & 11 deletions api/src/main/java/app/nexd/android/api/model/UpdateUserDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ public class UpdateUserDto {
@SerializedName(SERIALIZED_NAME_ZIP_CODE)
private String zipCode;

public static final String SERIALIZED_NAME_CITY = "city";
@SerializedName(SERIALIZED_NAME_CITY)
private String city;
public static final String SERIALIZED_NAME_LOCALITY = "city";
@SerializedName(SERIALIZED_NAME_LOCALITY)
private String locality;

/**
* Gets or Sets role
Expand Down Expand Up @@ -228,7 +228,7 @@ public void setZipCode(String zipCode) {

public UpdateUserDto city(String city) {

this.city = city;
this.locality = city;
return this;
}

Expand All @@ -239,13 +239,13 @@ public UpdateUserDto city(String city) {
@javax.annotation.Nullable
@ApiModelProperty(value = "")

public String getCity() {
return city;
public String getLocality() {
return locality;
}


public void setCity(String city) {
this.city = city;
public void setLocality(String locality) {
this.locality = locality;
}


Expand Down Expand Up @@ -309,14 +309,14 @@ public boolean equals(java.lang.Object o) {
Objects.equals(this.street, updateUserDto.street) &&
Objects.equals(this.number, updateUserDto.number) &&
Objects.equals(this.zipCode, updateUserDto.zipCode) &&
Objects.equals(this.city, updateUserDto.city) &&
Objects.equals(this.locality, updateUserDto.locality) &&
Objects.equals(this.role, updateUserDto.role) &&
Objects.equals(this.phoneNumber, updateUserDto.phoneNumber);
}

@Override
public int hashCode() {
return Objects.hash(firstName, lastName, street, number, zipCode, city, role, phoneNumber);
return Objects.hash(firstName, lastName, street, number, zipCode, locality, role, phoneNumber);
}


Expand All @@ -329,7 +329,7 @@ public String toString() {
sb.append(" street: ").append(toIndentedString(street)).append("\n");
sb.append(" number: ").append(toIndentedString(number)).append("\n");
sb.append(" zipCode: ").append(toIndentedString(zipCode)).append("\n");
sb.append(" city: ").append(toIndentedString(city)).append("\n");
sb.append(" city: ").append(toIndentedString(locality)).append("\n");
sb.append(" role: ").append(toIndentedString(role)).append("\n");
sb.append(" phoneNumber: ").append(toIndentedString(phoneNumber)).append("\n");
sb.append("}");
Expand Down
8 changes: 7 additions & 1 deletion app/src/main/java/app/nexd/android/di/Modules.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import app.nexd.android.Api
import app.nexd.android.Preferences
import app.nexd.android.ui.MainViewModel
import app.nexd.android.ui.auth.login.LoginViewModel
import app.nexd.android.ui.auth.register.ErrorTranslator
import app.nexd.android.ui.auth.register.InputValidator
import app.nexd.android.ui.auth.register.RegisterDetailedViewModel
import app.nexd.android.ui.auth.register.RegisterViewModel
import app.nexd.android.ui.helper.checkout.CheckoutViewModel
Expand All @@ -26,13 +28,17 @@ val appModule = module {

single { Api(preferences = get()) }

factory { InputValidator() }

factory { ErrorTranslator() }

viewModel { MainViewModel(get()) }

viewModel { RoleViewModel(get(), get()) }

viewModel { RegisterViewModel(get(), get()) }

viewModel { RegisterDetailedViewModel(get(), get()) }
viewModel { RegisterDetailedViewModel(get(), get(), get(), get()) }

viewModel { LoginViewModel(get(), get()) }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package app.nexd.android.ui.auth.register

import app.nexd.android.R
import app.nexd.android.api.model.BackendErrorEntry
import app.nexd.android.network.BackendError
import app.nexd.android.ui.auth.register.model.Effect
import app.nexd.android.ui.auth.register.model.ErrorState
import app.nexd.android.ui.auth.register.model.ValidationError
import app.nexd.android.ui.utils.Either

class ErrorTranslator {

fun translate(error: Throwable): Either<Effect.ShowErrorMessage, ErrorState> {
return when (error) {
is BackendError -> translateBackendError(error)
else -> Either.Left(Effect.ShowErrorMessage(R.string.unknow_error))
}
}

private fun translateBackendError(error: BackendError): Either<Effect.ShowErrorMessage, ErrorState> {
val validationErrors = error.errorCodes.map { errorCode ->
when (errorCode) {
BackendErrorEntry.ErrorCodeEnum.VALIDATION_PHONENUMBER_INVALID -> {
ValidationError.PhoneNumber
}
else -> ValidationError.Unknown
}
}
return Either.Right(ErrorState.FormValidationErrors(validationErrors))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package app.nexd.android.ui.auth.register

import app.nexd.android.ui.auth.register.model.Event
import app.nexd.android.ui.auth.register.model.ValidationError

class InputValidator() {

fun validate(
event: Event.UserRegistrationEvent
): List<ValidationError> {
val errors = mutableListOf<ValidationError>()
if (event.locality.isEmpty()) {
errors.add(ValidationError.Locality)
}
if(event.phone.isEmpty()) {
errors.add(ValidationError.PhoneNumber)
}
if(event.zip.isEmpty()) {
errors.add(ValidationError.Zip)
}
if(event.houseNumber.isEmpty()) {
errors.add(ValidationError.HouseNumber)
}
if(event.street.isEmpty()) {
errors.add(ValidationError.Street)
}
return errors
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,90 +3,142 @@ package app.nexd.android.ui.auth.register
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.observe
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import app.nexd.android.R
import app.nexd.android.databinding.FragmentRegisterDetailedBinding
import app.nexd.android.ui.auth.register.RegisterDetailedViewModel.Progress.*
import app.nexd.android.ui.auth.register.model.Effect
import app.nexd.android.ui.auth.register.model.ErrorState
import app.nexd.android.ui.auth.register.model.Event
import app.nexd.android.ui.auth.register.model.Loading
import app.nexd.android.ui.auth.register.model.ValidationError
import app.nexd.android.ui.auth.register.model.ViewState
import app.nexd.android.ui.common.Constants
import app.nexd.android.ui.common.DefaultSnackbar
import app.nexd.android.ui.utils.setDoneListener
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_register_detailed.*
import org.koin.androidx.viewmodel.ext.android.viewModel

class RegisterDetailedFragment : Fragment() {
class RegisterDetailedFragment : Fragment(R.layout.fragment_register_detailed) {

private val vm: RegisterDetailedViewModel by viewModel()
private val viewModel: RegisterDetailedViewModel by viewModel()

private lateinit var binding: FragmentRegisterDetailedBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupNavController()
setupListener()
viewModel.viewState.observe(viewLifecycleOwner, ::renderViewState)
viewModel.effects.observe(viewLifecycleOwner, ::handleEffects)
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentRegisterDetailedBinding.inflate(inflater, container, false)
binding.viewModel = vm
binding.lifecycleOwner = viewLifecycleOwner
return binding.root
private fun handleEffects(effect: Effect) {
when (effect) {
is Effect.NavigateToRoleView -> navigateToRoleFragment()
is Effect.ShowErrorMessage -> showSnackBar(effect.message)
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
private fun setupListener() {
editText_locality.setDoneListener(::tryRegister)
button_register.setOnClickListener { tryRegister() }
button_dataProtection_detail_registration.setOnClickListener { showPrivacyPolicy() }
}

private fun setupNavController() {
with(findNavController()) {
val appBarConfiguration = AppBarConfiguration(setOf(R.id.registerDetailedFragment))
register_detailed_toolbar.setupWithNavController(this, appBarConfiguration)
}
}

editText_city.setOnEditorActionListener { _, i, _ ->
if (i == EditorInfo.IME_ACTION_DONE) {
vm.setUserDetails()
}
false
private fun navigateToRoleFragment() {
findNavController().navigate(RegisterDetailedFragmentDirections.toRoleFragment())
}

private fun showSnackBar(message: Int) {
view?.let { DefaultSnackbar(it, getString(message), Snackbar.LENGTH_SHORT) }
}

private fun renderViewState(viewState: ViewState) {
renderLoading(viewState.loading)
renderError(viewState.errorState)
}

private fun renderLoading(loading: Loading) {
when (loading) {
Loading.IsLoading -> showLoading()
Loading.NotLoading -> hideLoading()
}
}

private fun hideLoading() {
progressBar.visibility = View.GONE
editText_phoneNumber.isEnabled = true
editText_street.isEnabled = true
editText_houseNr.isEnabled = true
editText_zipCode.isEnabled = true
editText_locality.isEnabled = true
}

private fun showLoading() {
progressBar.visibility = View.VISIBLE
editText_phoneNumber.isEnabled = false
editText_street.isEnabled = false
editText_houseNr.isEnabled = false
editText_zipCode.isEnabled = false
editText_locality.isEnabled = false
}

private fun renderError(errorState: ErrorState) {
when(errorState) {
is ErrorState.NoError -> hideValidationErrors()
is ErrorState.FormValidationErrors -> renderValidationErrors(errorState.validationErrors)
}
}

vm.progress.observe(viewLifecycleOwner, Observer { progress ->
progressBar.visibility = View.GONE
editText_phoneNumber.isEnabled = true
editText_street.isEnabled = true
editText_houseNr.isEnabled = true
editText_zipCode.isEnabled = true
editText_city.isEnabled = true

when (progress) {
is Idle -> { /* do nothing in idle */ }
is Loading -> {
progressBar.visibility = View.VISIBLE
editText_phoneNumber.isEnabled = false
editText_street.isEnabled = false
editText_houseNr.isEnabled = false
editText_zipCode.isEnabled = false
editText_city.isEnabled = false
}
is Error -> {
progress.message?.let {
DefaultSnackbar(view, it, Snackbar.LENGTH_SHORT)
}
}
is Finished -> {
findNavController().navigate(RegisterDetailedFragmentDirections.toRoleFragment())
}
}
})
private fun hideValidationErrors() {
editText_phoneNumber.error = null
editText_houseNr.error = null
editText_zipCode.error = null
editText_locality.text = null
editText_street.text = null
}

button_dataProtection_detail_registration.setOnClickListener {
showPrivacyPolicy()
private fun renderValidationErrors(validationErrors: List<ValidationError>) {
hideValidationErrors()
validationErrors.forEach { error ->
when (error) {
is ValidationError.PhoneNumber -> showValidationError(editText_phoneNumber, error.message)
is ValidationError.HouseNumber -> showValidationError(editText_houseNr, error.message)
is ValidationError.Zip -> showValidationError(editText_zipCode, error.message)
is ValidationError.Locality -> showValidationError(editText_locality, error.message)
is ValidationError.Street -> showValidationError(editText_street, error.message)
}
}
}

private fun showValidationError(editText: EditText, @StringRes message: Int) {
editText.error = getString(message)
}

private fun tryRegister() {
viewModel.event(
Event.UserRegistrationEvent(
phone = editText_phoneNumber.text.toString(),
zip = editText_zipCode.text.toString(),
houseNumber = editText_houseNr.text.toString(),
locality = editText_locality.text.toString(),
street = editText_street.text.toString()
)
)
}

private fun showPrivacyPolicy() {
startActivity(
Intent(
Expand Down
Loading