Como Criar a Tela de Recuperação de Acesso - Android M-Commerce

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes! Você receberá um email de confirmação. Somente depois de confirma-lo é que eu poderei lhe enviar os conteúdos semanais exclusivos. Os artigos em PDF são entregues somente para os inscritos na lista.

Email inválido.
Blog /Android /Como Criar a Tela de Recuperação de Acesso - Android M-Commerce

Como Criar a Tela de Recuperação de Acesso - Android M-Commerce

Vinícius Thiengo
(3046) (2)
Go-ahead
"O método consciente de tentativa e erro é mais bem-sucedido que o planejamento de um gênio isolado."
Peter Skillman
Prototipagem Android
Capa do curso Prototipagem Profissional de Aplicativos
TítuloAndroid: Prototipagem Profissional de Aplicativos
CategoriasAndroid, Design, Protótipo
AutorVinícius Thiengo
Vídeo aulas186
Tempo15 horas
ExercíciosSim
CertificadoSim
Acessar Curso
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Lendo
TítuloTest-Driven Development: Teste e Design no Mundo Real
CategoriaEngenharia de Software
Autor(es)Mauricio Aniche
EditoraCasa do Código
Edição1
Ano2012
Páginas194
Conteúdo Exclusivo
Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba gratuitamente conteúdos Android sem precedentes!
Email inválido

Tudo bem?

Neste artigo daremos continuidade a construção do aplicativo Android de mobile-commerce, o app BlueShoes.

Aqui vamos desenvolver uma das telas indispensáveis quando temos como requisitos de projeto a possibilidade de cadastro e de login de usuário. Estou falando da tela de recuperação de senha:

Animação de acesso a área de recuperação de acesso do app Android de mobile-commerce

Note que devido à refatoração aplicada na última aula do projeto até aqui, devido a isso o desenvolvimento da tela de recuperação de senha será bem simples, como também tende a ser o desenvolvimento de todas as outras telas com formulários.

Antes de prosseguir, não esqueça de se inscrever 📩 na lista de emails do Blog para ter acesso exclusivo às novas aulas do projeto e a outros conteúdos sobre o desenvolvimento Android.

A seguir os tópicos do artigo:

Estou iniciando agora no mobile-commerce

Apesar de este ser um projeto novo aqui do Blog e canal, está já é a oitava aula, sendo assim, se você chegou aqui somente agora, não deixe de primeiro estudar as aulas anteriores:

Surgindo dúvidas, pode deixar nos comentários dos artigos das aulas.

Estratégia para a tela de recuperação de senha

Se você já estudou a sétima aula do projeto, notou que alguns métodos ficaram ainda na atividade de login. Alguns possivelmente seriam movidos para outro lugar com o desenvolvimento de novas telas com formulários.

Com o desenvolvimento da tela de recuperação de acesso foi identificada a oportunidade de evitar ainda mais repetição de códigos, sendo assim nossa estratégia para está aula será:

  • Primeiro refatorar os pequenos códigos que serão também utilizados na atividade de recuperação de acesso, códigos estáticos e dinâmicos;
  • Construir a atividade de recuperação de acesso.

Em ambos os itens acima estaremos sempre seguindo o caminho fácil primeiro, ou seja, primeiramente o trabalho com dados estáticos e então o trabalho com dados dinâmicos.

Antes de seguir com a nova aula, saiba que o projeto BlueShoes esta por completo no GitHub dele em: https://github.com/viniciusthiengo/blueshoes-kotlin-android.

Protótipo estático

Abaixo o protótipo estático da tela de recuperação de senha:

Recuperação de senha

Recuperação de senha

Tentativa de recuperação

Tentativa de recuperação

Erro na recuperação

Erro na recuperação

Iniciada a recuperação

Iniciada a recuperação

 

É "Recuperação de senha" ou "Recuperação de acesso"?

Na verdade, aqui neste projeto, ambos os termos, "Recuperação de senha" e "Recuperação de acesso", serão tratados como sinônimos.

O aplicativo BlueShoes somente permitirá a recuperação de acesso por meio da definição de uma nova senha, ou seja, se o usuário esquecer o e-mail de login ele terá de criar uma outra conta.

Vamos seguir assim, pois as possibilidades de alguém acessar a conta que não é dele é ainda menor e também porque este roteiro de recuperação de acesso é o mais comum em aplicativos que têm área de autenticação.

Melhorando códigos antes da ForgotPasswordActivity

Como informado anteriormente: para evitar a repetição de trechos de códigos estáticos e dinâmicos, vamos primeiro mover e atualizar alguns pontos do projeto antes de prosseguir com a criação da atividade de recuperação de acesso.

Atualizando o estilo ButtonForm

O estilo ButtonForm está sendo aplicado em dois botões do projeto, até o momento. O botão de login presente no cabeçalho de menu gaveta de usuário não conectado:

Botão de login no cabeçalho do menu gaveta

E no botão "Entrar" da tela de login de usuário:

Botão Entrar da tela de login

Na tela de recuperação de senha haverá um botão similar ao da tela de login, até mesmo os espaçamentos internos laterais serão os mesmos, exatamente o ponto onde há diferença em relação ao botão de login do menu gaveta.

Sendo assim, os atributos android:paddingLeft="38dp"android:paddingRight="38dp" serão removidos do botão da tela de login:

...
<Button
android:id="@+id/bt_login"
style="@style/ButtonForm"
android:layout_marginTop="12dp"
android:paddingLeft="38dp"
android:paddingRight="38dp"
app:layout_constraintTop_toBottomOf="@+id/ll_container_fields"
app:layout_constraintRight_toRightOf="@+id/ll_container_fields"
android:onClick="mainAction"
android:text="@string/sign_in"/>
...

 

E colocados no estilo ButtonForm, presente em /res/values/styles.xml, como a seguir:

<resources>
...

<style name="ButtonForm">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:paddingLeft">38dp</item>
<item name="android:paddingRight">38dp</item>
<item name="android:background">@drawable/bt_nav_header_login_bg</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:textAllCaps">false</item>
</style>
</resources>

 

Como a configuração de espaçamento lateral interno do botão de login do cabeçalho de menu gaveta é diferente do agora comum 38dp, este botão permanecerá como está atualmente.

Encapsulando o bloco de informação

O bloco de informação de topo utilizado no fragmento de contato tem exatamente o mesmo estilo do bloco de topo da tela de recuperação de acesso:

Bloco de informação da tela de contato

Agora a versão da tela de recuperação de acesso:

Bloco de informação da tela de recuperação de senha

Para não repetir este código estático em layout, vamos encapsula-lo.

Em /res/layout crie um novo layout com o rótulo info_block.xml e com o código XML abaixo:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll_info_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorLightYellowBox"
android:padding="12dp"
android:orientation="horizontal">

<ImageView
style="@style/ImageViewLink"
android:layout_marginBottom="0dp"
android:layout_marginRight="12dp"
android:layout_marginEnd="12dp"
android:tint="@color/colorText"
android:contentDescription="@string/ic_info_desc"
android:src="@drawable/ic_information_black_18dp"/>

<TextView
android:id="@+id/tv_info_block"
style="@style/TextViewLink"
android:textColor="@color/colorText"
android:text="@string/forgot_password_info"/>
</LinearLayout>

 

Para criar o layout acima você pode seguir o processo padrão, já apresentado em outras aulas. Ou o mais simples e rápido: Ctrl + C e Ctrl + V em qualquer um dos layouts em /res/layout. Se você estiver em um sistema Apple será Command no lugar de Ctrl.

Eu particularmente prefiro a segunda opção.

A seguir o diagrama do novo layout info_block.xml:

Diagrama do layout info_block.xml

Atualizando o fragmento de contato

Para o fragmento de contato a nossa primeira atualização será no layout dele. Coloque em /res/layout/fragment_contact.xml o trecho em destaque:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
tools:context=".view.ContactFragment">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">

<!-- Informação principal -->
<include
layout="@layout/info_block"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="38dp"/>

<!-- Telefones -->
<TextView
android:id="@+id/tv_phones_title"
style="@style/TextViewContentTitle"
android:layout_below="@+id/ll_info_container"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="18dp"
android:text="@string/contact_frag_phones_title"/>

<ImageView
android:id="@+id/iv_phone_cities"
style="@style/ImageViewLink"
android:layout_below="@+id/tv_phones_title"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="14dp"
android:contentDescription="@string/ic_phone_desc"
android:src="@drawable/ic_phone_black_18dp"/>
<TextView
android:id="@+id/tv_phone_cities"
style="@style/TextViewLink"
android:layout_alignTop="@+id/iv_phone_cities"
android:layout_toEndOf="@+id/iv_phone_cities"
android:layout_toRightOf="@+id/iv_phone_cities"
android:text="@string/contact_frag_phone_cities"/>
<TextView
android:id="@+id/tv_phone_cities_info"
style="@style/TextViewOrangeInfo"
android:layout_alignTop="@+id/tv_phone_cities"
android:layout_toEndOf="@+id/tv_phone_cities"
android:layout_toRightOf="@+id/tv_phone_cities"
android:text="@string/contact_frag_phone_cities_info"/>

<ImageView
android:id="@+id/iv_phone_other_regions"
style="@style/ImageViewLink"
android:layout_marginBottom="38dp"
android:layout_below="@+id/iv_phone_cities"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:contentDescription="@string/ic_phone_desc"
android:src="@drawable/ic_phone_black_18dp"/>
<TextView
android:id="@+id/tv_phone_other_regions"
style="@style/TextViewLink"
android:layout_alignTop="@+id/iv_phone_other_regions"
android:layout_toEndOf="@+id/iv_phone_other_regions"
android:layout_toRightOf="@+id/iv_phone_other_regions"
android:text="@string/contact_frag_phone_other_regions"/>
<TextView
android:id="@+id/tv_phone_other_regions_info"
style="@style/TextViewOrangeInfo"
android:layout_alignTop="@+id/tv_phone_other_regions"
android:layout_toEndOf="@+id/tv_phone_other_regions"
android:layout_toRightOf="@+id/tv_phone_other_regions"
android:text="@string/contact_frag_phone_other_regions_info"/>

<!-- E-mails -->
<TextView
android:id="@+id/tv_emails_title"
style="@style/TextViewContentTitle"
android:layout_below="@+id/iv_phone_other_regions"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="18dp"
android:text="@string/contact_frag_emails_title"/>

<ImageView
android:id="@+id/iv_email_orders"
style="@style/ImageViewLink"
android:layout_below="@+id/tv_emails_title"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="14dp"
android:contentDescription="@string/ic_email_desc"
android:src="@drawable/ic_email_outline_black_18dp"/>
<TextView
android:id="@+id/tv_email_orders"
style="@style/TextViewLink"
android:layout_alignTop="@+id/iv_email_orders"
android:layout_toEndOf="@+id/iv_email_orders"
android:layout_toRightOf="@+id/iv_email_orders"
android:text="@string/contact_frag_email_orders"/>
<TextView
android:id="@+id/tv_email_orders_info"
style="@style/TextViewOrangeInfo"
android:layout_alignTop="@+id/tv_email_orders"
android:layout_toEndOf="@+id/tv_email_orders"
android:layout_toRightOf="@+id/tv_email_orders"
android:text="@string/contact_frag_email_orders_info"/>

<ImageView
android:id="@+id/iv_email_attendance"
style="@style/ImageViewLink"
android:layout_marginBottom="38dp"
android:layout_below="@+id/iv_email_orders"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:contentDescription="@string/ic_email_desc"
android:src="@drawable/ic_email_outline_black_18dp"/>
<TextView
android:id="@+id/tv_email_attendance"
style="@style/TextViewLink"
android:layout_alignTop="@+id/iv_email_attendance"
android:layout_toEndOf="@+id/iv_email_attendance"
android:layout_toRightOf="@+id/iv_email_attendance"
android:text="@string/contact_frag_email_attendance"/>
<TextView
android:id="@+id/tv_email_attendance_info"
style="@style/TextViewOrangeInfo"
android:layout_alignTop="@+id/tv_email_attendance"
android:layout_toEndOf="@+id/tv_email_attendance"
android:layout_toRightOf="@+id/tv_email_attendance"
android:text="@string/contact_frag_email_attendance_info"/>

<!-- Endereço -->
<TextView
android:id="@+id/tv_address_title"
style="@style/TextViewContentTitle"
android:layout_below="@+id/iv_email_attendance"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="18dp"
android:text="@string/contact_frag_address_title"/>

<ImageView
android:id="@+id/iv_address"
style="@style/ImageViewLink"
android:layout_below="@+id/tv_address_title"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:contentDescription="@string/ic_map_marker_desc"
android:src="@drawable/ic_map_marker_black_18dp"/>
<TextView
android:id="@+id/tv_address"
style="@style/TextViewLink"
android:layout_alignTop="@+id/iv_address"
android:layout_toEndOf="@+id/iv_address"
android:layout_toRightOf="@+id/iv_address"
android:text="@string/contact_frag_address"/>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>

 

Note que todos os atributos de posicionamento dentro de um RelativeLayout foram adicionados ao <include>, incluindo o atributo de margem de fundo.

E como o elemento pai é um RelativeLayout, também foi necessária a adição dos atributos android:layout_width e android:layout_height, isso para respeitar a regras de negócio do Android.

A seguir o novo diagrama de fragment_contact.xml:

Novo diagrama do layout fragment_contact.xml

Por fim ainda temos de atualizar o código em ContactFragment, pois em algum lugar a informação de topo específica desta tela tem de ser colocado no TextView de ID tv_info_block, o TextView de info_block.xml.

No método onActivityCreated() deste fragmento adicione o código em destaque:

...
override fun onActivityCreated( ... ) {
...

tv_info_block.text = getString( R.string.contact_frag_info )
}
...

 

O import para este TextView será:

...
import kotlinx.android.synthetic.main.info_block.*
...

Movendo o ouvidor de ActionDone

Você lembra do código do listener da tecla "Concluído" do teclado virtual? Vamos recapitula-lo na LoginActivity (códigos em destaque):

class LoginActivity :
FormActivity(),
TextView.OnEditorActionListener,
KeyboardUtils.OnSoftInputChangedListener {

override fun onCreate( ... ) {
...

et_password.setOnEditorActionListener( this )
}
...

/*
* Caso o usuário toque no botão "Done" do teclado virtual
* ao invés de tocar no botão "Entrar". Mesmo assim temos
* de processar o formulário.
* */
override fun onEditorAction(
view: TextView,
actionId: Int,
event: KeyEvent? ): Boolean {

mainAction()
return false
}
...
}

 

Então, na atividade de recuperação de acesso teremos quase o mesmo código. A única diferença será no trecho da View vinculada ao listener.

Ou seja, com exceção da linha:

...
et_password.setOnEditorActionListener( this )
...

 

Mova todo o código do listener de ActionDone para a FormActivity, como a seguir:

abstract class FormActivity :
AppCompatActivity(),
TextView.OnEditorActionListener {
...

/*
* Caso o usuário toque no botão "Done" do teclado virtual
* ao invés de tocar no botão "Entrar". Mesmo assim temos
* de processar o formulário.
* */
override fun onEditorAction(
view: TextView,
actionId: Int,
event: KeyEvent? ): Boolean {

mainAction()
return false
}
...
}

 

Coloquei o onEditorAction() logo abaixo do onOptionsItemSelected() da configuração já existente em FormActivity, você pode fazer o mesmo em sua versão de projeto.

Fique tranquilo, pois o código et_password.setOnEditorActionListener( this ) no onCreate() da LoginActivity continuará funcionando sem problemas.

Movendo o método backEndFakeDelay()

Mesmo sabendo que o método backEndFakeDelay() será removido até o final do projeto, não faz sentido ficar com o código dele espalhado pelas várias atividades e fragmentos que contêm formulário.

Sendo assim vamos também move-lo para a FormActivity:

abstract class FormActivity :
... {
...

/*
* Fake method - Somente para testes temporários em atividades
* e fragmentos que contêm formulários.
* */
protected fun backEndFakeDelay(
statusAction: Boolean,
feedbackMessage: String
){

Thread{
kotlin.run {
/*
* Simulando um delay de latência de
* 1 segundo.
* */
SystemClock.sleep( 1000 )

runOnUiThread {
blockFields( false )
isMainButtonSending( false )
showProxy( false )

snackBarFeedback(
fl_form_container,
statusAction,
feedbackMessage
)
}
}
}.start()
}
}

 

Note que a assinatura do método mudou, agora temos dois parâmetros além da nova definição de escopo: protected fun backEndFakeDelay( statusAction: Boolean, feedbackMessage: String ).

Com estes novos dois parâmetros nós teremos total liberdade de modificação de status da mensagem "fake" de feedback nos testes dos diversos formulários do projeto.

Ainda temos de atualizar a LoginActivity, mais precisamente o método mainAction() desta atividade. Coloque-o como a seguir:

...
override fun mainAction( view: View? ){
blockFields( true )
isMainButtonSending( true )
showProxy( true )

backEndFakeDelay(
false,
getString( R.string.invalid_login )
)
}
...

 

Não esqueça de remover o método backEndFakeDelay() da LoginActivity, pois somente o da FormActivity é que será utilizado.

Atualizando os imports em LoginActivity

Para que você não tenha dor de cabeça com os imports, principalmente de Views, da LoginActivity, agora em nosso projeto os imports desta atividade estão como a seguir:

...
import android.content.Intent
import android.os.Bundle
import android.support.constraint.ConstraintLayout
import android.support.constraint.ConstraintSet
import android.view.View
import android.widget.Toast
import com.blankj.utilcode.util.KeyboardUtils
import com.blankj.utilcode.util.ScreenUtils
import kotlinx.android.synthetic.main.content_form.*
import kotlinx.android.synthetic.main.content_login.*
import kotlinx.android.synthetic.main.text_view_privacy_policy_login.*
import thiengo.com.br.blueshoes.R
import thiengo.com.br.blueshoes.util.isValidEmail
import thiengo.com.br.blueshoes.util.isValidPassword
import thiengo.com.br.blueshoes.util.validate
...

 

Assim podemos partir para a construção da principal atividade desta aula.

Trabalhando a atividade de recuperação de acesso

Com os códigos encapsulados, agora é fazer o simples:

  • Criar a atividade de recuperação de senha;
  • E atualizar as entidades necessárias para o correto acesso à nova atividade criada.

Arquivo de Strings

No arquivo /res/values/strings.xml adicione os trechos abaixo em destaque:

<resources>
...

<!-- ForgotPasswordActivity -->
<string name="title_activity_forgot_password">
Recuperação de senha
</string>

<string name="forgot_password_info">
Informe abaixo o seu e-mail de login e em seguida acesse
o e-mail para prosseguir com o passo a passo de recuperação
de acesso.
</string>
<string name="hint_login_email">E-mail de login</string>
<string name="recover_password">Recuperar senha</string>
<string name="recover_password_going">Enviando&#8230;</string>
<string name="invalid_login_email">
E-mail não encontrado em nossa base de dados.
</string>
</resources>

Drawables para formulários de campos separados

Agora os arquivos drawable que darão ao campo único de e-mail do formulário de recuperação de acesso o design como a seguir:

Campo de e-mail do formulário de recuperação de senha

Primeiro os dois arquivos base, responsáveis respectivamente pelos estados "normal" e "em foco" do campo de e-mail.

Em /res/drawable crie um novo arquivo (pode ser utilizando "Copiar" e "Colar" de algum outro arquivo drawable) com o rótulo bg_form_field_corners.xml e com o código a seguir:

<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<!--
Definindo a cor de background - branca.
-->
<solid android:color="@android:color/white" />

<!--
Definindo bordas de 1dp de espessura e na cor
cinza.
-->
<stroke
android:color="@color/colorViewLine"
android:width="1dp" />

<!--
Definindo bordas arredondadas na View
retangular.
-->
<corners
android:radius="5dp" />
</shape>

 

Note que os arquivos *top e *bottom criados na aula da tela de login não são úteis aqui, pois desta vez precisamos, em um mesmo campo, de todos os cantos arredondados.

Ainda em /res/drawable crie o arquivo drawable de foco, bg_form_field_corners_focused.xml, com o código XML a seguir:

<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<!--
Definindo a cor de background - azul claro.
-->
<solid android:color="@color/colorFieldFocused" />

<!--
Definindo bordas de 1dp de espessura e na cor
cinza.
-->
<stroke
android:color="@color/colorViewLine"
android:width="1dp" />

<!--
Definindo bordas arredondadas na View
retangular.
-->
<corners
android:radius="5dp" />
</shape>

 

Por fim o arquivo que será referenciado diretamente pelo EditText de e-mail. Em /res/drawable crie o arquivo bg_form_field.xml com o código XML a seguir:

<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">

<!--
Drawable utilizado quando a View alvo está com
foco.
-->
<item
android:state_focused="true"
android:drawable="@drawable/bg_form_field_corners_focused" />

<!--
Drawable utilizado quando a View alvo não está
com foco.
-->
<item
android:drawable="@drawable/bg_form_field_corners" />
</selector>

 

Assim podemos partir para o layout de formulário.

Layout de formulário

O trecho principal do layout da ForgotPasswordActivity é em parte similar ao trecho principal do layout da LoginActivity.

Logo, com um "Copiar" e "Colar" do arquivo content_login.xml que está em /res/layout, renomeie o novo arquivo para content_forgot_password.xml e nele coloque o código XML a seguir:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent">

<!-- Informação principal -->
<include
layout="@layout/info_block"
app:layout_constraintTop_toTopOf="parent"/>

<EditText
android:id="@+id/et_email"
style="@style/EditTextFormField"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:background="@drawable/bg_form_field"
android:inputType="textEmailAddress"
android:imeOptions="actionDone"
android:hint="@string/hint_login_email"/>

<Button
android:id="@+id/bt_recover_password"
style="@style/ButtonForm"
android:layout_marginTop="12dp"
android:paddingLeft="38dp"
android:paddingRight="38dp"
app:layout_constraintTop_toBottomOf="@+id/et_email"
app:layout_constraintRight_toRightOf="@+id/et_email"
android:onClick="mainAction"
android:text="@string/recover_password"/>

</android.support.constraint.ConstraintLayout>

 

Note a simplicidade da estrutura do formulário, tendo em mente que todos os outros códigos do layout de ForgotPasswordActivity estão vindo de FormActivity.

E, diferente das regras de negócio para quando a View ancestral é um RelativeLayout, com o ConstraintLayout não há necessidade de fornecermos também as dimensões da View filha via tag <include>.

A seguir o diagrama deste trecho principal do layout de formulário:

Diagrama do layout content_forgot_password.xml

Criando a ForgotPasswordActivity

Como fizemos para o trecho principal do layout da atividade de recuperação de acesso, aqui faremos o mesmo para está atividade em si.

"Copie" e "Cole", no mesmo pacote, /view, a LoginActivity, porém com o rótulo ForgotPasswordActivity e com o código Kotlin a seguir:

class ForgotPasswordActivity :
FormActivity() {

override fun onCreate( savedInstanceState: Bundle? ) {
super.onCreate( savedInstanceState )

/*
* Colocando a View de um arquivo XML como View filha
* do item indicado no terceiro argumento.
* */
View.inflate(
this,
R.layout.content_forgot_password,
fl_form
)

/*
* Colocando configuração de validação de campo de email
* para enquanto o usuário informa o conteúdo deste campo.
* */
et_email.validate(
{
it.isValidEmail()
},
getString( R.string.invalid_email )
)

et_email.setOnEditorActionListener( this )


tv_info_block.text = getString( R.string.forgot_password_info )
}

override fun mainAction( view: View? ){
blockFields( true )
isMainButtonSending( true )
showProxy( true )

backEndFakeDelay(
false,
getString( R.string.invalid_login_email )
)
}

override fun blockFields( status: Boolean ){
et_email.isEnabled = !status
bt_recover_password.isEnabled = !status
}

override fun isMainButtonSending( status: Boolean ){
bt_recover_password.text =
if( status )
getString( R.string.recover_password_going )
else
getString( R.string.recover_password )
}
}

 

Pode acreditar, está é uma atividade com menos de 100 linhas. Isso, pois ainda há comentários e quebras extras de linhas em branco.

Atualizando o AndroidManifest

Ainda é preciso adicionar essa nova atividade ao AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest
...>

<application
...>
...

<activity
android:name=".view.ForgotPasswordActivity"
android:label="@string/title_activity_forgot_password"
android:theme="@style/AppTheme.NoActionBar"/>
</application>
</manifest>

Atualizando o método callForgotPasswordActivity() da LoginActivity

E por fim a atualização do método callForgotPasswordActivity() da LoginActivity, método responsável por ter o algoritmo de invocação da tela de recuperação de acesso:

...
fun callForgotPasswordActivity( view: View ){
val intent = Intent(
this,
ForgotPasswordActivity::class.java
)

startActivity( intent )
}
...

 

Assim podemos partir para os testes.

Testes e resultados

Abra o Android Studio, no menu de topo acesse "Build", em seguida clique em "Rebuid project". Ao final do rebuild execute o aplicativo em seu aparelho ou emulador Android de testes.

Não esqueça de colocar em teste o usuário com o status "não conectado", objeto presente na MainActivity:

...
val user = User(
"Thiengo Vinícius",
R.drawable.user,
false /* Não conectado. */
)
...

 

Acessando a área de recuperação de acesso e trabalhando com o campo único de e-mail, temos:

Animação do trabalho com o campo de e-mail da área de recuperação de senha

Com isso finalizamos, na oitava aula do projeto Android mobile-commerce, a UI da área de recuperação de acesso.

Antes de prosseguir, não esqueça de se inscrever na 📩 lista de emails do Blog para receber todas as aulas do app Android de mobile-commerce.

Se inscreva também no canal do Blog em: YouTube Thiengo.

Vídeos

A seguir os vídeos com o passo a passo da construção da tela de recuperação de senha:

O projeto também pode ser acessado pelo GitHub dele em: https://github.com/viniciusthiengo/blueshoes-kotlin-android.

Conclusão

Note como foi possível observar o impacto da primeira refatoração do projeto. A interface gráfica da área de recuperação de acesso foi construída rapidamente e com poucas linhas de código.

Está área do app é realmente simples, pois como definido em fase de projeto: a recuperação de acesso em si se dará via e-mail e área Web, a principio.

Ou seja, o "crítico" do código ficará todo no lado Web.

Caso você tenha dicas ou dúvidas para este projeto Android de mobile-commerce, deixe logo abaixo nos comentários ou envie direto ao e-mail oficial do Blog e canal.

Curtiu o conteúdo? Não esqueça de compartilha-lo. E, por fim, não deixe de se inscrever na 📩 lista de emails, respondo às suas dúvidas também por lá.

Abraço.

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes!
Email inválido

Relacionado

PhotoView Android Para a Completa Implementação de ZoomPhotoView Android Para a Completa Implementação de ZoomAndroid
Data Binding Para Vinculo de Dados na UI AndroidData Binding Para Vinculo de Dados na UI AndroidAndroid
5 livros que não são de TI, mas que um desenvolvedor deveria ler5 livros que não são de TI, mas que um desenvolvedor deveria lerEmpreendedorismo
Android Mobile-Commerce, Apresentação e Protótipo do ProjetoAndroid Mobile-Commerce, Apresentação e Protótipo do ProjetoAndroid

Compartilhar

Comentários Facebook

Comentários Blog (2)

Para código / script, coloque entre [code] e [/code] para receber marcação especifica.
Forneça seu nome válido.
Forneça seu email válido.
Forneça o comentário.
Enviando, aguarde...
Robson (1) (0)
18/06/2019
Olá Thiengo boa tarde,
Cara estou com um problema no bloco de informação ele não fica alinhado o icone com o texto, o texto sempre aparece abaixo ( como se houvesse uma linha )

uma outra coisa que noto, este não é um "problema" é o seguinte faço o login e o processo ocorre com sucesso então mando uma mensagem na snackBar só que é muito rápido logo parte para a outra atividade no meu caso é a MainActivity e eu gostaria que o usuário pudesse ler poderia dar uma ajuda nestes dois casos? Seria correto então mostrar a mensagem de boas vindas na MainActivity? estou quase certo que sim.
Agradeço e segue o meu código abaixo para um melhor entendimento.

@Override
    public void taskCompleted(String results) {
        Log.i(TAG, "taskCompleted(" + results + ")");
        blockFields(false);
        showProxy(false);

        try {
            JSONObject jsonObject = new JSONObject(results);

            if (jsonObject.getJSONArray("errors").length() == 0) {
                if (jsonObject.getJSONArray("results").length() > 0) {

                    String json = jsonObject.getJSONArray("results")
                            .getJSONObject(0)
                            .toString();
                    User user = new Gson().fromJson(json, User.class);
                    snackBarFeedBack(frameLayoutContainer, true, "Olá " + user.getNome() + "seja bem vindo.");

                    gravarRegistro(user);
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);
                } else {
                    snackBarFeedBack(frameLayoutContainer, false, "Houve uma falha");
                }
Responder
Vinícius Thiengo (1) (0)
16/08/2019
Robson, tudo bem?

Para o primeiro problema relatado, sobre o posicionamento do texto e do ícone, vou pedir que você revise o "XML de layout de informe" desenvolvido, pois toda a configuração para ter o layout como especificado em projeto esta na parte XML dele:

-> info_block.xml: https://github.com/viniciusthiengo/blueshoes-kotlin-android/blob/master/app/src/main/res/layout/info_block.xml

Sobre a mensagem de Boas-vindas / Ok na tela de login, confesso que não é comum isso ocorrer.

Se os dados de login estão corretos, então nenhuma mensagem é apresentada nesta tela, o que ocorre é o carregamento da tela principal, aqui a MainActivity, porém com o usuário já conectado.

O que é comum, quando é o primeiro login do usuário, é a apresentação de uma mensagem de boas-vindas na tela principal e um tutorial de como proceder nesta tela.

Robson, veja a possibilidade de manter este comportamento padrão: apresentar mensagens de boas-vindas e tutoriais de navegação na tela principal do aplicativo quando com o usuário conectado.

A mensagem apresentada na tela de login é a mensagem de que os dados informados estão incorretos.

Abraço.
Responder