Neste artigo veremos como gerenciar dados de usuários usando o banco de dados Realtime Database do Firebase. |
Continuando a primeira parte do artigo vamos iniciar a criação do projeto Xamarin Forms.
Recursos usados:
Criando o projeto Xamarin Forms
Vamos criar um novo projeto Xamarin Forms no VS 2019 Community com o nome XF_FirebaseUsuarios
Nota: Verifique se você precisa atualizar as versões do Xamarin Forms e do Xamarin.Essentials
Você pode ver como criar um projeto no Xamarin Forms neste link: Criar Projeto Xamarin Forms
A seguir vamos incluir o seguinte pacote no projeto criado:
Esta biblioteca é um invólucro (wrapper) sobre a API REST do Firebase Realtime Database, e, dentre outros recursos, suporta a API de streaming que você pode usar para notificações em tempo real.
Veja o código fonte a documentação neste link: https://github.com/step-up-labs/firebase-database-dotnet
A seguir vamos criar as seguintes pastas no projeto compartilhado que iremos usar em nossa aplicação:
No projeto Android, na pasta Resources/drawable vamos incluir o arquivo logorede1.jpg que iremos usar na página de Login.
Na pasta Models crie a classe User que representa um usuário que vai acessar nossa aplicação e que possui um nome e uma senha:
public class User { public string Email { get; set; } public string Password { get; set; } } |
Agora vamos criar a classe FirebaseUserService onde vamos implementar a funcionalidades para acessar nossa base de dados Firebase e implementar os métodos para gerenciar os usuários. Aqui vamos usar o link de referência ao nosso banco de dados Firebase Realtime Database.
Iremos usar também a referência à biblioteca Firebase.Database e Firebase.DatabaseQuery onde vamos usar classe FirebaseClient e definir os métodos:
Para isso crie a classe FirebaseUserService na pasta Services:
using Firebase.Database;
using Firebase.Database.Query;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using XF_FirebaseUsuarios.Models;
namespace XF_FirebaseUsuarios.Services
{
public class FirebaseUserService
{
public static FirebaseClient firebase =
new FirebaseClient("https://xamarinfirebasedb-e9df0.firebaseio.com/");
public static async Task<List<User>> GetAllUsers()
{
try
{
var userlist = (await firebase
.Child("Users")
.OnceAsync<User>()).Select(item =>
new User
{
Email = item.Object.Email,
Password = item.Object.Password
}).ToList();
return userlist;
}
catch (Exception e)
{
Debug.WriteLine($"Error:{e}");
return null;
}
}
public static async Task<User> GetUser(string email)
{
try
{
var allUsers = await GetAllUsers();
await firebase
.Child("Users")
.OnceAsync<User>();
return allUsers.Where(a => a.Email == email).FirstOrDefault();
}
catch (Exception e)
{
Debug.WriteLine($"Error:{e}");
return null;
}
}
public static async Task<bool> AddUser(string email, string password)
{
try
{
await firebase
.Child("Users")
.PostAsync(new User() { Email = email, Password = password });
return true;
}
catch (Exception e)
{
Debug.WriteLine($"Error:{e}");
return false;
}
}
public static async Task<bool> UpdateUser(string email, string password)
{
try
{
var toUpdateUser = (await firebase
.Child("Users")
.OnceAsync<User>()).Where(a => a.Object.Email == email).FirstOrDefault();
await firebase
.Child("Users")
.Child(toUpdateUser.Key)
.PutAsync(new User() { Email = email, Password = password });
return true;
}
catch (Exception e)
{
Debug.WriteLine($"Error:{e}");
return false;
}
}
public static async Task<bool> DeleteUser(string email)
{
try
{
var toDeleteUser = (await firebase
.Child("Users")
.OnceAsync<User>()).Where(a => a.Object.Email == email).FirstOrDefault();
await firebase.Child("Users").Child(toDeleteUser.Key).DeleteAsync();
return true;
}
catch (Exception e)
{
Debug.WriteLine($"Error:{e}");
return false;
}
}
}
}
|
Assim temos nosso serviço pronto para acessar o Firebase, e gerenciar os usuários.
Como vamos usar a abordagem MVVM vamos criar agora as seguintes view models :
Cada view model vai implementar a interface INotifyPropertyChanged() e definir a lógica para fazer o login, o registro do usuário e o gerenciamento da conta.
Para otimizar o código vamos implementar a interface INotifyPropertyChanged() em uma classe BaseViewModel e a seguir cada uma das outras view models vai herdar dessa classe.
Na pasta ViewModels vamos criar a classe BaseViewModel:
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace XF_LancheApp.ViewModels
{
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
|
Além disso para não invocar mensagens de alerta a partir da view model usando DisplayAlert(), o que não seria uma boa prática, vamos criar um serviço de mensagens da seguinte forma:
public interface IMessageService { Task AlertaAsync(string message); }
public class MessageService : IMessageService { public async Task AlertaAsync(string message) { await App.Current.MainPage.DisplayAlert("Usuarios", message, "Ok"); } }
public App() { DependencyService.Register<IMessageService,MessageService>(); InitializeComponent();MainPage = new NavigationPage(new LoginPage()); }
Agora podemos usar o serviço em cada view model inicializando o serviço no construtor e usando o método AlertAsync() como veremos a seguir.
Para concluir vamos otimizar a navegação que será feita nas view models. Podemos passar INavigation para o construtor da View Model mas isso pode ser dispendioso em termos de código se tivermos uma arquitetura de ViewModels mais aninhada.
Uma outra forma é envolver INavigation com um singleton, acessível a partir de qualquer View Model.
Vamos cria então um Singleton chamado NavigationDispatcher na pasta Services:
using System;
using Xamarin.Forms;
namespace XF_FirebaseUsuarios.Services
{
public class NavigationDispatcher
{
private static NavigationDispatcher _instance;
private INavigation _navigation;
public static NavigationDispatcher Instance =>
_instance ?? (_instance = new NavigationDispatcher());
public INavigation Navigation =>
_navigation ?? throw new Exception("NavigationDispatcher não foi inicializado");
public void Initialize(INavigation navigation)
{
_navigation = navigation;
}
}
}
|
A seguir no arquivo App.xaml.cs vamos inicializar o serviço :
public App() { DependencyService.Register<IMessageService,MessageService>(); InitializeComponent(); MainPage = new NavigationPage(new LoginPage());
NavigationDispatcher.Instance.Initialize(MainPage.Navigation);
}
|
A seguir basta usar o singleton na view model e os métodos de navegação.
Agora vamos aplicar esses recursos na criação das ViewModels.
Vamos iniciar criando a view model LoginViewModel na pasta ViewModels:
using Xamarin.Forms;
using XF_FirebaseUsuarios.Services;
using XF_FirebaseUsuarios.Views;
namespace XF_FirebaseUsuarios.ViewModels
{
public class LoginViewModel : BaseViewModel
{
private readonly IMessageService _messageService;
public LoginViewModel()
{
_messageService = DependencyService.Get<IMessageService>();
}
private string email;
public string Email
{
get { return email; }
set
{
email = value;
OnPropertyChanged();
}
}
private string password;
public string Password
{
get { return password; }
set
{
password = value;
OnPropertyChanged();
}
}
public Command LoginCommand
{
get
{
return new Command(Login);
}
}
public Command SignUp
{
get
{
return new Command(() =>
{
NavigationDispatcher.Instance.Navigation.PushAsync(new RegisterPage());
});
}
}
private async void Login()
{
if (string.IsNullOrEmpty(Email) || string.IsNullOrEmpty(Password))
{
await _messageService.AlertaAsync("Informe o email e/ou senha");
}
else
{
var user = await FirebaseUserService.GetUser(Email);
if (user != null)
{
if (Email == user.Email && Password == user.Password)
{
await _messageService.AlertaAsync("Login feito com Sucesso");
await NavigationDispatcher.Instance.Navigation.PushAsync(new WelComePage(Email));
}
else
{
await _messageService.AlertaAsync("Informe o email/senha correto(s)");
}
}
else
{
await _messageService.AlertaAsync("Usuário não encontrado");
}
}
}
}
}
|
Na pasta Views crie a seguir a ContentPage LoginPage.xaml :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:XF_FirebaseUsuarios.ViewModels"
x:Class="XF_FirebaseUsuarios.Views.LoginPage"
BackgroundColor="WhiteSmoke"
Title="Login de Usuário">
<ContentPage.BindingContext>
<vm:LoginViewModel />
</ContentPage.BindingContext>
<StackLayout>
<Entry x:Name = "Email" Placeholder = "Email"
PlaceholderColor="Black"
Text="{Binding Email}"
TextColor="Black"
HeightRequest = "40"
Keyboard = "Email"/>
<Entry x:Name = "Password" Text="{Binding Password}" Placeholder = "Password"
PlaceholderColor="Black"
TextColor="Black"
HeightRequest = "40"
IsPassword = "True"/>
<Button x:Name= "loginbtn" Text = "Fazer Login "
TextColor="White"
BackgroundColor="DarkGoldenrod"
Command="{Binding LoginCommand}"
HorizontalOptions = "FillAndExpand"/>
<Button x:Name="signup" Text="Registrar Usuário"
TextColor="White"
BackgroundColor="DarkGoldenrod"
Command="{Binding SignUp}" HorizontalOptions="End"/>
</StackLayout>
</ContentPage> |
Na próxima parte do artigo vamos criar as demais ViewModels e as respectivas Views.
"Dando graças
ao Pai que nos fez idôneos para participar da herança dos santos na luz;
O qual nos tirou da potestade das trevas, e nos transportou para o reino do
Filho do seu amor;"
Colossenses 1:12,13
Referências:
NET - Apresentando o padrão Model-View-ViewModel
Xamarin Forms - MVVM - Macoratti.net
NET - O padrão MVVM (Model-View-ViewModel) revisitado
Xamarin Forms - MVVM - A interface ICommand
Padrão de Projeto - Aprendendo o padrão MVVM ..