Alura > Cursos de Mobile > Cursos de iOS > Conteúdos de iOS > Primeiras aulas do curso iOS com SwiftUI: construindo autenticação de usuários em uma aplicação

iOS com SwiftUI: construindo autenticação de usuários em uma aplicação

TextField e Picker - Apresentação

Olá! Me chamo Giovanna Moeller e sou instrutora aqui na Alura.

Audiodescrição: Giovanna Moeller é uma mulher branca, de cabelos loiros, lisos e longos. Veste uma camiseta azul com o logotipo "Alura".

Boas-vindas a mais um curso de SwiftUI, este focado em autenticação de pessoas usuárias.

Se você realizou os outros cursos desta formação, é provável que você já esteja familiarizado com o Voll Med.

O Voll Med é um aplicativo que oferece a capacidade aos pacientes de agendar, reagendar e cancelar consultas médicas de forma conveniente.

Dentro deste aplicativo, encontramos quatro operações fundamentais, a saber: a criação, a atualização, a leitura e a exclusão de dados. Todas essas ações estão interligadas com um serviço externo.

Ao longo deste curso, abordaremos a autenticação de pessoas usuárias, possibilitando que elas se registrem e façam login na nossa aplicação. Assim, vamos analisar esse projeto em ação.

Relembrando o projeto

Emulador iPhone 14 exibindo a tela de login do aplicativo "Voll Med" com um fundo branco. No topo central, encontramos o logotipo "Voll Med". Abaixo, uma mensagem que contém o seguinte texto: "Olá! Preencha para acessar sua conta". Logo abaixo desse texto, temos dois campos para preencher "E-mail" e "Senha". Abaixo, há um botão azul escrito "Entrar". Na sequência, há um texto clicável escrito "Ainda não possui uma conta? Cadastre-se".

A aplicação apresenta uma tela de login com campos para inserção do e-mail e senha. No entanto, caso a pessoa usuária ainda não tenha uma conta, há também a possibilidade de realizar o cadastro na aplicação.

Nessa tela de cadastro, são fornecidos campos de entrada para o nome, e-mail, CPF, número de telefone e senha. Além disso, há a opção de selecionar o plano de saúde desejado.

Caso a pessoa usuária já tenha uma conta, podemos proceder ao início de sessão para demonstrar o funcionamento. Nesse sentido, irei utilizar uma conta à qual tenho acesso, com o endereço de e-mail "lucas@gmail.com" e a respetiva senha correspondente.

Assim, a pessoa usuária ficará autenticada na aplicação e estará apto a realizar diversas operações, tais como agendar uma consulta, remarcar compromissos e até mesmo cancelá-los. Adicionalmente, essa pessoa pode efetuar o logout da aplicação, o que a levará de volta à tela de início de sessão.

Pré-requisitos

Para aproveitar este curso, é necessário ter conhecimento prévio na criação de layouts com o uso do SwiftUI, bem como dominar seus principais elementos. Além disso, é importante possuir experiência em fazer solicitações a serviços externos, ou seja, estar familiarizado com requisições HTTP.

Aguardamos sua participação na primeira aula!

TextField e Picker - Criando a tela de login com TextField

Começaremos construindo a tela de login, que permitirá à pessoa usuária inserir seu e-mail e senha para acessar a aplicação.

Construindo a tela de login

Emulador iPhone 14 exibindo a tela de login do aplicativo "Voll Med" com um fundo branco. No topo central, encontramos o logotipo "Voll Med". Abaixo, uma mensagem que contém o seguinte texto: "Olá! Preencha para acessar sua conta". Logo abaixo desse texto, temos dois campos para preencher "E-mail" e "Senha". Abaixo, há um botão azul escrito "Entrar". Na sequência, há um texto clicável escrito "Ainda não possui uma conta? Cadastre-se".

A tela de login é composta por uma imagem, um texto de saudação "Olá", uma orientação "Preencha para acessar sua conta", campos para inserção de e-mail e senha, além de botões de ação.

Existe também o link "Ainda não possui uma conta? Cadastre-se!" que, ao ser clicado, direciona a pessoa usuária para a tela de cadastro. Na tela de cadastro, temos o inverso: o link "Já possui uma conta? Faça o login." que retorna à tela de login.

Vamos começar!

No Xcode, do lado esquerdo selecionamos com o botão direito na pasta Views e selecionamos "New File" para criar uma nova view.

Será exibida uma janela intitulada "Choose a template for your new file", onde selecionamos a opção "SwiftUI View" e depois clicamos no botão "Next" no canto inferior direito.

Na janela seguinte, temos os campos "Save As", "tags", "where", "group" e "Targets". Abaixo, dois botões "Cancel" e "Create". Em "Save As" digitamos "SigninView".

Seremos redirecionados para o arquivo SigninView com um código padrão:

Arquivo SigninView no repositório do GitHub

import SwiftUI

struct SignInView: View {
var body: some View {
Text("Hello, World!")
}
}
#Preview { 
SignInView()
}

Estilizando a view

Para estilizar essa view, inicialmente removemos o Text("Hello, World!") e criamos uma VStack.

Na VStack, utilizamos alguns parâmetros, como Alignment no modo Leading para alinhar os elementos à esquerda, e um espaçamento Spacing de 16 entre os elementos.

SigninView

import SwiftUI

struct SignInView: View {
var body: some View {
VStack(alignment: .leading, spacing: 16.0) {

}
}
}
#Preview { 
SignInView()
}

O elemento inicial na VStack é uma imagem que importamos do nosso arquivo Asset, utilizando a referência .logo para identificar o arquivo.

Agora, iremos adicionar alguns modificadores de propriedade.

Adicionamos o .resizable() e .scaledToFit() para ajustar o tamanho da imagem.

Do lado direito no emulador, no aplicativo, a logo da Voll Med está centralizada na tela, em um fundo branco.

Também aplicamos o modificador Frame para gerenciar a altura e largura, definindo um valor de maxWidth: .infinity para preencher a largura total do dispositivo, um maxHeight de 36 e um alinhamento alignment: .center para centralizar a imagem.

SigninView

import SwiftUI

struct SignInView: View {
var body: some View {
VStack(alignment: .leading, spacing: 16.0) {
Image(.logo)
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity, maxHeight: 36.0, alignment: .center)
}
}
}

#Preview { 
SignInView()
}

Observem que a logomarca da Voll Med está agora em um tamanho apropriado e centralizada na tela do aplicativo no emulador à direita.

Posteriormente, incluímos os textos com o Text() passando a string "Olá". Logo após, adicionamos alguns modificadores como .font(title2). Além disso, aplicamos a formatação em negrito com o uso do parâmetro bold, e definimos as cores, usando a cor accent.

Para a mensagem de orientação, aplicamos a mesma lógica. No entanto, a fonte será .title3 (para torná-la menor), a cor será .gray, e adicionamos um .padding(.bottom) para criar um espaço abaixo do texto, proporcionando um espaçamento com o próximo elemento.

SigninView

import SwiftUI

struct SignInView: View {
var body: some View {
VStack(alignment: .leading, spacing: 16.0) {
Image(.logo)
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity, maxHeight: 36.0, alignment: .center)

Text("Olá!")
.font(.title2)
.bold()
.foregroundStyle(.accent)

Text("Preencha para acessar sua conta.")
.font(.title3)
.foregroundStyle(.gray)
.padding(.bottom)
}
}
}

#Preview { 
SignInView()
}

Agora, a fim de que a pessoa usuária possa inserir seu e-mail e senha, iremos incluir mais campos de texto, Text(). Logo após, adicionamos os modificadores, como .font() passando title3, depois inserimos um .bold() para colocar em negrito. Por fim, adicionamos o foregroundStyle() passando .accent.

SigninView

// código omitido

Text("Email")
.font(.title3)
.bold()
.foregroundStyle(.accent)

}
}
}

#Preview { 
SignInView()
}

Na tela de cancelamento, fazemos uso do componente TextEditor, que permite que as pessoas usuárias redijam maiores quantidades de texto em várias linhas. No entanto, nesta situação, empregaremos o componente TextField.

Entendendo e aplicando o TextField

O TextField, por padrão, aceita apenas uma linha, o que o torna apropriado para campos com quantidades menores de texto, como nome, e-mail, senha e telefone.

Digitamos TextField() e, em seguida, são exibidas várias opções em um menu suspenso, nas quais selecionamos a opção "TextField(titleKey:text)".

O titleKey será o placeholder, sendo o texto que será exibido enquanto a pessoa usuária ainda não digitou nada: "Insira seu email". No text precisamos passar um binding do tipo string, sendo uma variável de estado para controlar o que a pessoa usuária está digitando.

Para criar a variável de estado, após carregar o arquivo e dentro da estrutura SignInView, inserimos: @State private var password: String = "", sendo as aspas duplas vazias representativas de uma string vazia, pois inicialmente a variável é uma string vazia.

Embora não seja necessário especificar o tipo de dado (pois o Swift permite isso), optamos por manter a padronização nessa View.

Aproveitando, vamos criar outra variável de estado para a nossa senha. Será @State private var password, a qual é do tipo string (sequência de caracteres) e também iniciará vazia.

SigninView

// código omitido

 @State private var email: String = ""
 @State private var password: String = ""

// código omitido

Descendo o arquivo, na hora de passar o binding na linha 37, onde estamos definindo o TextField, vamos usar o $email.

SigninView

// código omitido

Text("Email")
.font(.title3)
.bold()
.foregroundStyle(.accent)

TextField("Insira seu email", text: $email)

// código omitido

Ao executar o simulador, à nossa direita, notamos que foi adicionada a instrução "Insira seu email". Vamos agora adicionar alguns modificadores de propriedade para este TextField.

Primeiramente, adicionamos um padding() (espaçamento) e atribuímos o valor de 14. Também definimos uma cor de fundo através de background(), com color.gray.opacity(0.25). Além disso, configuramos um cornerRadius() (raio de canto) de 14 para dar um aspecto de cantos arredondados.

O TextFields tem alguns modificadores relacionados ao teclado e ao texto. Por exemplo, podemos desabilitar a função de correção automática do texto quando estiver errado, o que, no caso do email, não é muito apropriado. Portanto, utilizamos .autocorrectionDisabled para desativar a autocorreção.

Outro modificador que podemos usar é o keyboardType (tipo de teclado), que definirá o tipo de teclado. Se quisermos um teclado que só contenha números, utilizaremos a opção numberpad no menu de opções exibido.

Mas, neste caso, optamos pela opção email address, pois o símbolo "@" fica mais acessível neste teclado. Abordaremos isso com mais detalhes posteriormente.

Nós também podemos adicionar um modificador chamado textInputAutocapitalization() (autocapitalização da entrada de texto). Definimos este modificador como .never (nunca), o que significa que o teclado nunca colocará automaticamente a primeira letra em maiúscula.

Afinal, em alguns casos, quando estamos digitando algo, a primeira letra é mantida em maiúscula automaticamente. No caso do e-mail, isso não ocorre.

SigninView

// código omitido

Text("Email")
.font(.title3)
.bold()
.foregroundStyle(.accent)

TextField("Insira seu email", text: $email)
.padding(14)
.background(Color.gray.opacity(0.25))
.cornerRadius(14.0)
.autocorrectionDisabled()
.keyboardType(.emailAddress)
.textInputAutocapitalization(.never)

// código omitido

Vamos, então, para a senha. Adicionamos outro text() com a string "senha". Aplicamos os mesmos modificadores do texto de email, copiamos da linha 33 até a 35 e colamos no nosso texto de senha.

Para a senha, não podemos utilizar o TextField, pois as nossas senhas ficariam visíveis. Queremos que os caracteres fiquem ocultos, como é comum quando estamos digitando nossa senha. Por isso, utilizamos o SecureField, que funciona da mesma maneira, porém oculta os caracteres.

Então, escolhemos o SecureField, definindo o texto predefinido como "Insira a nossa senha". No texto, passamos a nossa variável de estado $password.

Adicionamos também os mesmos modificadores presentes no TextField: padding de 14, background com Color.gray.opacity(0.25) e um cornerRadius de 14.

SigninView

// código omitido

Text("Email")
.font(.title3)
.bold()
.foregroundStyle(.accent)

TextField("Insira seu email", text: $email)
.padding(14)
.background(Color.gray.opacity(0.25))
.cornerRadius(14.0)
.autocorrectionDisabled()
.keyboardType(.emailAddress)
.textInputAutocapitalization(.never)

Text("Senha")
.font(.title3)
.bold()
.foregroundStyle(.accent)

SecureField("Insira sua senha", text: $password)
.padding(14)
.background(Color.gray.opacity(0.25))
.cornerRadius(14.0)

// código omitido

Com os modificadores necessários concluídos, vamos ao simulador, à direita, e testamos a digitação da senha.

Se executarmos a aplicação e ela não abrir na tela de login, será necessário adicionar um padding na nossa viewStack para que fique adequada.

SigninView

// código omitido

SecureField("Insira sua senha", text: $password)
.padding(14)
.background(Color.gray.opacity(0.25))
.cornerRadius(14.0)

}
.padding()

// código omitido

Para executarmos essa aplicação, iremos ao arquivo VollmedApp do lado esquerdo e, em vez de ContentView, receberemos SigningView.

Arquivo VollmedApp no repositório do GitHub

import SwiftUI

@main
struct VollmedApp: App {
var body: some Scene {
WindowGroup {
SignInView()

}
}
}

Agora, executamos a aplicação pressionando "R" para abrir o simulador.

Agora, para ativarmos o teclado, vamos ao canto superior, na opção "I/O", em seguida, selecionamos "keyboard" e finalmente marcamos a opção "Toggle Software Keyboard". Agora, temos o teclado visível e, lembram-se do arroba mencionado anteriormente? Nosso acesso a ele fica muito mais fácil neste tipo de teclado.

Ao começarmos a inserir uma senha, as bolas pretas serão representadas pelo SecureField.

Conclusão

Agora que nós já conhecemos o componente TextField e o SecureField, continuaremos a construção dessa tela e também da tela de cadastro.

Espero você no próximo vídeo!

TextField e Picker - Finalizando a tela de login

Agora vamos finalizar a nossa tela de login. Quero tranquilizar vocês quanto aos alertas que o Xcode está apresentando. Não sei exatamente porque isso está acontecendo e, às vezes, pode ser um bug do próprio Xcode. Portanto, não se preocupem com isso.

Finalizando a tela de login

Retornando para o SigningView, vamos completar o que falta, que é o botão "Entrar" e o texto "Ainda não possui uma conta? Cadastre-se.".

Logo após o SecureField, começaremos a definir um botão. Selecionaremos a opção "Action" e "Label". Na Action, incluiremos um comentário vazio, pois ainda não chamaremos nenhuma função. Faremos isso mais tarde.

No Label, chamaremos a nossa ButtonView(), que é o componente do botão. Escolheremos a opção com um texto e passaremos uma string como "Entrar".

SigningView

// código omitido

Button(action: {}, label: {
        ButtonView(text: "Entrar")
})

// código omitido

Agora, criaremos um NavigationLink, pois, no texto "Ainda não possui uma conta? Cadastre-se.", às pessoas usuárias serão redirecionadas para a tela de cadastro. Indo para o Navigation Link, selecionaremos a opção NavigationLink(destination, label).

Como é uma View de destino, precisamos criar a tela de cadastro a seguir. Na pasta Views, no canto esquerdo, clicaremos com o botão direito e escolheremos "New File > Swift UI View" e selecionamos "Next. Nomearemos essa View como SignUpView.

Seremos redirecionados para o arquivo com um código padrão.

Na nossa SignUpView, começaremos a estilizá-la. Vamos remover o Text() e iniciaremos a inserção de ScrollView. Optamos por utilizar o ScrollView devido à quantidade considerável de campos de texto, permitindo que as pessoas usuárias possam rolar a tela.

Para o ScrollView, configuramos o parâmetro ShowsIndicators com o valor false, de modo a não exibir a barra de rolagem.

SignUpView.swift

import SwiftUI

struct SignUpView: View {
var body: some View {
ScrollView(showsIndicators: false) {
}
}
}
#Preview {
SignUpView()
}

Isso acarretará erro, pois na SignInView, não estamos fazendo nada nas linhas 62 ou 64 ainda. Assim, na linha 62, a View de destino é a SignUpView().

Vamos retornar à tela de cadastro em um momento. Vamos substituir o Label por um Text e, em seguida, inseriremos a string "Ainda não possui uma conta, cadastre-se." Aplicaremos alguns modificadores, como o estilo bold.

Adicionamos um .frame(maxWidth: .infinity,) para ocupar toda a largura do dispositivo e um alignment: .center para garantir que fique centralizado.

SigningView

// código omitido

NavigationLink {
SignUpView()
} label: {
Text("Ainda não possui uma conta? Cadastre-se.")
.bold()
.frame(maxWidth: .infinity, alignment: .center)
}
}

// código omitido

Testaremos isso pressionando "Command + R" para abrir o simulador e tentaremos clicar em "Ainda não possui uma conta? Cadastre-se.". Não está navegando para a nossa tela de cadastro. Isso acontece porque ainda não adicionamos nenhum NavigationStack para fazer isso.

Aplicando o NavigationStack

Portanto, vamos no nosso VollmedApp encapsular a nossa View, SigningView, em um NavigationStack. Isso é provisório, porque posteriormente faremos modificações na nossa ContentView, a TabView que criamos antes.

VollMedApp

import SwiftUI

@main
struct VollmedApp: App {
    var body: some Scene {
        WindowGroup {
            NavigationStack {
                SignInView()
            }
        }
    }
}

Após a inclusão do NavigationStack, pressionamos "Command + R" mais uma vez para executar. Nesse ponto, a cor da interface foi alterada para azul. Ao clicar em "Ainda não possui uma conta", a tela de cadastro será exibida.

Queremos eliminar o botão "Voltar" ("back") no canto superior esquerdo da tela de cadastro, já que não desejamos tê-lo presente. Queremos que, quando a pessoa usuária clique novamente em "Já possui uma conta", ela faça login.

Para alcançar esse objetivo, basta acessar a SignUpView, após o ScrollView, e ativar o modificador .navigationBarBackButtonHidder().

SignUpView.swift

import SwiftUI

struct SignUpView: View {
var body: some View {
ScrollView(showsIndicators: false) {
}
.navigationBarBackButtonHidder()
}
}
#Preview {
SignUpView()
}

Vamos realizar o teste, pressionamos "Command + R". Ao clicarmos em "Ainda não possui uma conta? Cadastre-se", observamos que o botão "Voltar" não está mais presente no canto superior esquerdo na tela de cadastro.

Estilizando a SignUpView

Vamos começar a estilizar a SignUpView. Começaremos adicionando a imagem. Para isso, digitamos image(.logo).

A implementação será semelhante à que fizemos na tela de login. Portanto, começamos com image(.logo) e adicionamos .resizable(). Em seguida, incluímos .scaledToFit(), seguido por .frame() , definindo MaxWidth como infinito e MaxHeight como 36 e alignment: .center. Adicionaremos também um .padding() na direção vertical, utilizando vertical.

SignUpView.swift

import SwiftUI

struct SignUpView: View {
var body: some View {
ScrollView(showsIndicators: false) {
Image(.logo)
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity, maxHeight: 36.0, alignment: .center)
.padding(.vertical)
}
.navigationBarBackButtonHidder()
}
}
#Preview {
SignUpView()
}

Em seguida, incluiremos um texto com o seguinte comando: Text("Olá, boas-vindas!"). Agora, vamos adicionar alguns modificadores, como .font(.title2), .bold() e .foregroundStyle(.accent).

SignUpView.swift

import SwiftUI

struct SignUpView: View {
var body: some View {
ScrollView(showsIndicators: false) {
Image(.logo)
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity, maxHeight: 36.0, alignment: .center)
.padding(.vertical)

Text("Olá, boas-vindas!")
.font(.title2)
.bold()
.foregroundStyle(.accent)
}
.navigationBarBackButtonHidder()
}
}
#Preview {
SignUpView()
}

Agora, vamos adicionar o VStack. Após a ScrollView, adicionaremos o VStack(), começando com parênteses, seguido por alignment: .leading e spacing: 16.0. Abriremos chaves, copiamos o Image(.logo) e esse Text(), aplicamos o comando "Command + X" e em seguida "Command + V" dentro do nosso VStack.

Agora sim. Dentro da ScrollView, logo após o modificador navigationBarBackButtonHidder, adicionaremos também um Padding.

SignUpView.swift

import SwiftUI

struct SignUpView: View {
var body: some View {
ScrollView(showsIndicators: false) {
VStack(alignment: .leading, spacing: 16.0) {
Image(.logo)
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity, maxHeight: 36.0, alignment: .center)
.padding(.vertical)

Text("Olá, boas-vindas!")
.font(.title2)
.bold()
.foregroundStyle(.accent)
}
}
.navigationBarBackButtonHidder()
.padding()
}
}
#Preview {
SignUpView()
}

Seguindo com a construção do código, inserimos mais um texto aqui, "Preencha para acessar sua conta.", juntamente com alguns modificadores: .font(.title3), .foregroundStyle(.gray) para uma cor cinza e também um .padding(.bottom).

Em seguida, adicionaremos um .padding(.bottom) também na parte inferior desse texto para que eles fiquem distantes do próximo elemento.

SignUpView.swift

// código omitido

Text("Olá, boas-vindas!")
.font(.title2)
.bold()
.foregroundStyle(.accent)

Text("Preencha para acessar sua conta.")
.font(.title3)
.foregroundStyle(.gray)
.padding(.bottom)
}
}
.navigationBarBackButtonHidder()
.padding()
}
}

// código omitido

Assim, temos nossa base criada. Vamos testar novamente no simulador, com o comando "Command + R".

No emulador, atualmente encontramos o logotipo da VollMed no centro superior. Abaixo, há o texto "Olá" seguido de "Preencha para acessar sua conta." Logo após, são visíveis os campos "Email" e "Senha", seguidos de um botão denominado "Entrar". Abaixo deste botão, encontramos um texto clicável com a mensagem "Ainda não possui uma conta? Cadastre-se".

Se clicarmos no texto "ainda não possuímos uma conta", ele nos levará para a tela de cadastro.

Conclusão e próximos passos

Agora, precisamos adicionar todos os campos de texto nessa tela de cadastro. Esperamos por você no próximo vídeo para concluir isso!

Sobre o curso iOS com SwiftUI: construindo autenticação de usuários em uma aplicação

O curso iOS com SwiftUI: construindo autenticação de usuários em uma aplicação possui 148 minutos de vídeos, em um total de 57 atividades. Gostou? Conheça nossos outros cursos de iOS em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda iOS acessando integralmente esse e outros cursos, comece hoje!

Plus

De
R$ 1.800
12X
R$109
à vista R$1.308
  • Acesso a TODOS os cursos da Alura

    Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

Matricule-se

Pro

De
R$ 2.400
12X
R$149
à vista R$1.788
  • Acesso a TODOS os cursos da Alura

    Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Luri powered by ChatGPT

    Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com Luri até 100 mensagens por semana.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

Matricule-se
Conheça os Planos para Empresas

Acesso completo
durante 1 ano

Estude 24h/dia
onde e quando quiser

Novos cursos
todas as semanas