lunes, 16 de marzo de 2020

Xamarin.Forms - Login con SQLite

En este post elaboraremos un ejemplo práctico para el inicio de sesión, con el fin de controlar los accesos de usuarios a las diferentes opciones de nuestra aplicación móvil.

De paso les dejo el link (App - DÍAbetes) donde se viene detallando todo lo elaborado acerca del diseño y desarrollo de la aplicación.

El ejemplo práctico será diseñada y desarrollada en Xamarin.Forms con almacenamiento de datos en SQLite. Para la cual crearemos la solución y proyecto de nombre AppLogin haciendo uso de Visual Studio y todas las pruebas serán realizadas en un equipo móvil físico con Sistema Operativo Android, esto no restringe el uso de emuladores.

Requisitos:
Microsoft Visual Studio Community 2019.
Xamarin.Froms - XAML.
SQLite - Gestión de datos local.

Crear Proyecto:
Crearemos el proyecto para las plataformas de Android y iOS desde el Visual Studio 2019.

Aplicación móvil (Xamarin.Froms) y clic en siguiente
Ingresamos el nombre, la ubicación y clic en Crear

Seleccionamos la plantilla En Blanco, marcamos para las plataformas de Android y iOS y para finalizar clic en OK

Estructura del Proyecto:
Ahora describiremos la estructura del proyecto que acabamos de crear:

Se crearon 3 proyectos:

El primero es AppLogin, proyecto portable en el que escribiremos el código común de la aplicación. En los proyectos AppLogin.Android y AppLogin.iOS se implementará lo que se requería de acuerdo a nuestra necesidad por cada plaforma. Para aclarar que en este artículo sólo trataremos el desarrollo para Android por ser las plataformas de terceros, iOS lo veremos más adelante.

Recordemos que Xamarin.Forms es una plataforma para desarrollar aplicaciones para plataformas iOS, Android , Windows Phone , Windows Store y Mac usando el lenguaje de programación C#. Compuesto por una serie de componentes que permite definir interfaces de usuario para distintas plataformas desde una misma base de código.

Xamarin.Forms está orientado a construir aplicaciones con interfaces de usuario sencillas, donde es más importante la capacidad de compartir código que el brindar interfaces de usuario avanzadas y personalizadas para cada plataforma, sin embargo, existe la posibilidad de hacer la personalización de los componentes a cada plataforma heredando nuestro componente básico de Xamarin.Forms a uno que se implementara en el proyecto de iOS y Android , y ahí podemos usar instrucciones típicas (equivalentes en .NET) de Objective-C y Java respectivamente.

Crear directorios:
Después de haber creado el proyecto, iniciaremos con la creación de los siguientes directorios: Data, Models y Views:

Crear clases:
En el directorio Data crearemos las siguientes clases: DataBase.cs, TaskExtensions.cs y UserDB.cs. Seguidamente en el directorio Models creamos la clase User.cs.

Diseño de Interfaz:
En el directorio Views agregamos un nuevo elemento de tipo Página de Contenido para XAML de nombre de Login.xaml, al crear el .xaml también se creará el Login.xaml.cs, aclaremos las diferencias:

.XAML: Es el lenguaje de marcado baso en XML creado por Microsoft, es decir es el quien define la interfaz de usuario para la aplicación. 
.XAML.CS: Es el encargo de almacenar el CodeBehind en relación al diseño y otras lógicas que programación que pueda existir sobre la necesidad y funcionalidad por la que fue creada.

Ahora iniciaremos definiendo la interfaz de nuestra aplicación, para lo cual - iniciaremos - abriendo el archivo MainPage.xaml del proyecto AppLogin y agregamos las siguientes propiedades:

<Image Source="LogoDIAbetes.jpg" HeightRequest="140" WidthRequest="140" FlexLayout.AlignSelf="Center" BackgroundColor="Transparent" />
<Button x:Name="btnLogin" FontSize="Medium" BorderColor="Black" FlexLayout.AlignSelf="Stretch" CornerRadius="5"  HorizontalOptions="CenterAndExpand" Text="Iniciar Sesión" Clicked="btnLogin_Clicked" TextColor="White" BackgroundColor="#3399ff"/>

Seguidamente abrimos el archivo Login.xaml y agregamos las siguientes propiedades:
                <Image Source="LogoDIAbetes.jpg" HeightRequest="140" WidthRequest="140" FlexLayout.AlignSelf="Center" BackgroundColor="Transparent" />
<Label TextColor="#3399ff" FontAttributes="Bold" Text="Iniciar Sesión" FlexLayout.AlignSelf="Center" FontSize="25"/>
<Entry x:Name="userNameEntry" ReturnType="Next" Placeholder="Email" FontSize="Medium" FlexLayout.AlignSelf="Stretch"  HorizontalOptions="CenterAndExpand"  TextColor="Black" />
<Entry x:Name="passwordEntry" ReturnType="Done" IsPassword="True" Placeholder="Password" FontSize="Medium" FlexLayout.AlignSelf="Stretch"  HorizontalOptions="CenterAndExpand"  TextColor="Black" />
<Button x:Name="loging" Clicked="loging_Clicked" FontSize="Medium" TextColor="White" BorderColor="Black" BackgroundColor="#00b33c"  CornerRadius="5" FlexLayout.AlignSelf="Stretch"  HorizontalOptions="CenterAndExpand" Text="Iniciar sesión"></Button>
<Label x:Name="forgetLabel" Text="¿Olvidó su contraseña?" TextColor="Blue" FontSize="15" BackgroundColor="Transparent" FlexLayout.AlignSelf="End"/>

Desarrollo de código:
Abrimos el archivo o clase MainPage.xaml.cs y agregamos la creamos  la tarea asíncrona btnLogin_Clicked que se encargará de llamar a la Página de Contenido para XAML de nombre de Login.xaml:

        private async void btnLogin_Clicked(object sender, EventArgs e)
        {           
            await this.Navigation.PushAsync(new Login());
        }

Seguidamente abrir el archivo o clase DataBase.cs y agregamos las siguientes instrucciones:

    public class DataBase
    {
        public const string DatabaseFilename = "DIAbetesSQLite.db3";

        public const SQLiteOpenFlags Flags =           
            SQLiteOpenFlags.ReadWrite | // open the database in read/write mode
            SQLiteOpenFlags.Create |    // create the database if it doesn't exist
            SQLiteOpenFlags.SharedCache;// enable multi-threaded database access

        public static string DatabasePath
        {
            get
            {
                var basePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
                return Path.Combine(basePath, DatabaseFilename);
            }
        }

    }

A continuación abrir el archivo o clase TaskExtensions.cs y agregamos las siguientes instrucciones:

    public static class TaskExtensions
    {       
        public static async void SafeFireAndForget(this Task task,
            bool returnToCallingContext,
            Action<Exception> onException = null)
        {
            try
            {
                await task.ConfigureAwait(returnToCallingContext);
            }

            // if the provided action is not null, catch and
            // pass the thrown exception
            catch (Exception ex) when (onException != null)
            {
                onException(ex);
            }
        }
    }

Luego abrimos el archivo o clase User.cs y agregamos los siguientes atributos que representarán el modelo de datos de nuestros usuarios:

    public class User
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
        public string email { get; set; }
        public string name { get; set; }
        [MaxLength(12)]
        public string password { get; set; }
        [MaxLength(10)]
        public string phone { get; set; }
    }

Ahora abrimos el archivos o clase UserDB.cs y creamos las siguientes instrucciones:

El método whereUser es el encargado de validar los datos de usuarios que fueron ingresados previamente. También puede revisar Xamarin.Forms - CRUD con SQLite.

    public class UserDB
    {
        static readonly Lazy<SQLiteAsyncConnection> lazyInitializer = new Lazy<SQLiteAsyncConnection>(() =>
        {
            return new SQLiteAsyncConnection(DataBase.DatabasePath, DataBase.Flags);
        });

        static SQLiteAsyncConnection Database => lazyInitializer.Value;
        static bool initialized = false;

        public UserDB()
        {
            InitializeAsync().SafeFireAndForget(false);
        }

        async Task InitializeAsync()
        {
            if (!initialized)
            {
                if (!Database.TableMappings.Any(m => m.MappedType.Name == typeof(User).Name))
                {
                    await Database.CreateTablesAsync(CreateFlags.None, typeof(User)).ConfigureAwait(false);
                    initialized = true;
                }
            }
        }

        #region metodos login
        public IEnumerable<User> whereUser(string strEmail, string strPwd)
        {
            var result = Database.QueryAsync<User>("Select * from User Where email=? and password=?", strEmail, strPwd);

            return result.Result;
        }
        #endregion
    }

Para finalizar abrimos archivo Login.xaml.cs y creamos las siguientes instrucciones:

La tarea asíncrono loging_Clicked es el encargado de realizar las validaciones de cara a la interfaz del usuario.

    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class Login : ContentPage    {

        UserDB userData = new UserDB();
        public Login()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Botón para validar e ingresar a la pantalla principal de la app
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void loging_Clicked(object sender, EventArgs e)
        {
            if (await ValidateForm())
            {
                IEnumerable<User> result = userData.whereUser(userNameEntry.Text.Trim(), passwordEntry.Text.Trim());

                if (result.Count() == 0)
                {
                    await DisplayAlert("Alerta", "Email o Password Incorrectos.", "OK");
                }
                else if (result.Count() == 1)
                {
                    await Navigation.PushAsync(new UsersList());
                }
                else if (result.Count() >= 1)
                {
                    await DisplayAlert("Alerta", "Existe más de una cuenta registada, favor de solicitar la correción de la cuenta.", "OK");
                    //await Navigation.PushAsync(new DuplicateAccountSendEmail());
                }
            }
        }

        /// <summary>
        /// Validar las propiedades de la pantalla de envio de email
        /// </summary>
        /// <returns></returns>
        private async Task<bool> ValidateForm()
        {
            //Valida si el valor en el Entry txtTo se encuentra vacio o es igual a Null
            if (String.IsNullOrWhiteSpace(userNameEntry.Text))
            {
                await this.DisplayAlert("Advertencia", "El campo Email es obligatorio.", "OK");
                return false;
            }
            else
            {
                //Valida que el formato del email sea valido
                bool isEmail = Regex.IsMatch(userNameEntry.Text, @"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z", RegexOptions.IgnoreCase);
                if (!isEmail)
                {
                    await this.DisplayAlert("Advertencia", "El formato del Email es incorrecto.", "OK");
                    return false;
                }
            }

            //Valida si el valor en el Entry txtSubject se encuentra vacio o es igual a Null
            if (String.IsNullOrWhiteSpace(passwordEntry.Text))
            {
                await this.DisplayAlert("Advertencia", "El campo Password es obligatorio.", "OK");
                return false;
            }

            return true;
        }

    }

Resultado:
Al finalizar la edición de esté post la interfaz a variado, sin embargo la funcionalidad son las mismas:

 


Comparto el vídeo 📹 acerca de lo desarrollado de acuerdo a la descripción de este post publicado, todas las pruebas fueron validados en plataforma 📱 para Android.


Mayor información disponible en:
👉 Saber más de XAML

Descarga la fuente de:
En proceso de carga...

Nuevamente gratitud a Dios y 😊 de antemano gracias a todos ustedes por la acogida de este nuevo post publicado, bendiciones 🙏 y fuerte 💪 abrazo...!!!

0 comentarios :