Ejercicio: Creación de una aplicación de traductor de números de teléfono

Completado

En este ejercicio, construirá la interfaz de usuario de la aplicación de marcador telefónico e implementará la lógica detrás de esta interfaz de usuario.

Creará una interfaz de usuario que aproveche las capacidades de la interfaz de usuario de .NET MAUI (interfaz de usuario de aplicación multiplataforma) y el paquete .NET MAUI Essentials para marcar el teléfono.

La aplicación permite al usuario escribir texto en un campo de entrada y traduce ese texto a dígitos numéricos. Usa las letras que se muestran en el teclado de un teléfono como base para la traducción. Por ejemplo, las letras cab se traducen como 222 porque el dígito 2 tiene las tres letras a, b y c.

Continúe con la solución Phoneword que ha creado en el ejercicio anterior.

Adición de un nuevo archivo de origen de C# a la aplicación

  1. Abra la solución Phoneword en Visual Studio si todavía no lo ha hecho.

  2. En la ventana Explorador de soluciones, haga clic con el botón derecho en el proyecto Phoneword, seleccione Agregar y seleccione Clase.

  3. En el cuadro de diálogo Agregar nuevo elemento, asigne un nombre al archivo de clase PhonewordTranslator.cs y seleccione Agregar.

    Recorte de pantalla del cuadro de diálogo Agregar nuevo elemento. El usuario llamó al archivo de clase PhonewordTranslator.cs

Adición de la lógica de traducción

Reemplace el contenido del archivo de clase por el código siguiente y guarde el archivo. El método estático ToNumber de la clase PhonewordTranslator traduce el número de texto alfanumérico a un número de teléfono convencional.

using System.Text;

namespace Core;

public static class PhonewordTranslator
{
    public static string ToNumber(string raw)
    {
        if (string.IsNullOrWhiteSpace(raw))
            return null;

        raw = raw.ToUpperInvariant();

        var newNumber = new StringBuilder();
        foreach (var c in raw)
        {
            if (" -0123456789".Contains(c))
                newNumber.Append(c);
            else
            {
                var result = TranslateToNumber(c);
                if (result != null)
                    newNumber.Append(result);
                // Bad character?
                else
                    return null;
            }
        }
        return newNumber.ToString();
    }

    static bool Contains(this string keyString, char c)
    {
        return keyString.IndexOf(c) >= 0;
    }

    static readonly string[] digits = {
        "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"
    };

    static int? TranslateToNumber(char c)
    {
        for (int i = 0; i < digits.Length; i++)
        {
            if (digits[i].Contains(c))
                return 2 + i;
        }
        return null;
    }
}

Creación de la interfaz de usuario

  1. Abre el archivo MainPage.xaml en el proyecto Phoneword.

  2. Quite el control ScrollView y su contenido, y deje solo el control ContentPage:

    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Phoneword.MainPage">
    
    </ContentPage>
    
  3. Agregue un control VerticalStackLayout con orientación vertical y un espaciado de 15 unidades y relleno de 20 unidades a ContentPage:

    <ContentPage ... >
        <VerticalStackLayout Spacing="15" Padding="20">
    
        </VerticalStackLayout>
    </ContentPage>
    
  4. Agregue un control Label a StackLayout:

    <ContentPage ... >
        <VerticalStackLayout ...>
            <Label Text = "Enter a Phoneword"
                   FontSize ="20"/>
        </VerticalStackLayout>
    </ContentPage>
    
  5. Agregue un control Entry a StackLayout, debajo de la etiqueta. Un control Entry proporciona un cuadro de texto en el que el usuario puede escribir datos. En este código, la propiedad x:Name asigna un nombre al control. Más adelante hará referencia a este control en el código de la aplicación:

    <ContentPage ... >
        <VerticalStackLayout ...>
            <Label .../>
            <Entry x:Name = "PhoneNumberText"
                   Text = "1-555-NETMAUI" />
        </VerticalStackLayout>
    </ContentPage>
    
  6. Agregue dos controles Button a VerticalStackLayout, después del control Entry. Actualmente, ninguno de los dos botones hace nada y el segundo se deshabilita inicialmente. Agregará el código para controlar el evento Clicked de estos dos botones en la siguiente tarea:

    <ContentPage ... >
        <VerticalStackLayout ...>
            <Label .../>
            <Entry ... />
            <Button x:Name = "TranslateButton"
                    Text = "Translate"
                    Clicked = "OnTranslate"/>
            <Button x:Name = "CallButton"
                    Text = "Call"
                    IsEnabled = "False"
                    Clicked = "OnCall"/>
        </VerticalStackLayout>
    </ContentPage>
    

Respuesta a la pulsación del botón TranslateButton

  1. En la ventana Explorador de soluciones, expanda la entrada MainPage.xaml y abra el archivo de código subyacente MainPage.xaml.cs.

  2. En la clase MainPage, quite la variable count y el método OnCounterClicked. La clase debería tener el siguiente aspecto:

    namespace Phoneword;
    
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    }
    
  3. Agregue la variable de cadena translatedNumber y el método OnTranslate siguiente a la clase MainPage, después del constructor. El método OnTranslate recupera el número de teléfono de la propiedad Text del control Entry y lo pasa al método estático ToNumber de la clase PhonewordTranslator que creó anteriormente.

    public partial class MainPage : ContentPage
    {
        ...
        string translatedNumber;
    
        private void OnTranslate(object sender, EventArgs e)
        {
            string enteredNumber = PhoneNumberText.Text;
            translatedNumber = Core.PhonewordTranslator.ToNumber(enteredNumber);
    
            if (!string.IsNullOrEmpty(translatedNumber))
            {
                // TODO:
            }
            else
            {
                // TODO:
            }
        }
    }
    

    Nota:

    En el paso siguiente, rellenará los bits TODO que faltan de este código.

  4. En el método OnTranslate, agregue código para cambiar la propiedad Text del botón Llamada para anexar el número de teléfono traducido correctamente. Puede usar el valor almacenado en el campo TranslatedNumber. Además, se habilitará y deshabilitará el botón en función de la traducción correcta. Por ejemplo, si TranslateNumber devuelve null, deshabilite el botón, pero si lo ha hecho correctamente, habilítelo.

    private void OnTranslate(object sender, EventArgs e)
    {
        string enteredNumber = PhoneNumberText.Text;
        translatedNumber = Core.PhonewordTranslator.ToNumber(enteredNumber);
    
        if (!string.IsNullOrEmpty(translatedNumber))
        {
            CallButton.IsEnabled = true;
            CallButton.Text = "Call " + translatedNumber;
        }
        else
        {
            CallButton.IsEnabled = false;
            CallButton.Text = "Call";
        }
    }
    

Creación del método de evento para el botón CallButton

  1. Agregue el método de control de eventos OnCall al final de la clase MainPage. Este método usa operaciones asincrónicas, así que márquelo como async:

    public partial class MainPage : ContentPage
    {
    
        ...
        async void OnCall(object sender, System.EventArgs e)
        {
    
        }
    }
    
  2. En el método OnCall, pida al usuario, mediante el método Page.DisplayAlert, que pregunte si quiere marcar el número.

    Los parámetros de DisplayAlert son un título, un mensaje y dos cadenas que se usan para el texto de los botones Accept y Cancel. Devuelve un valor booleano que indica si se ha presionado el botón Accept para cerrar el cuadro de diálogo.

    async void OnCall(object sender, System.EventArgs e)
    {
        if (await this.DisplayAlert(
            "Dial a Number",
            "Would you like to call " + translatedNumber + "?",
            "Yes",
            "No"))
        {
            // TODO: dial the phone
        }
    }
    

Prueba de la aplicación

  1. En la barra de herramientas de Visual Studio, seleccione el perfil Máquina Windows y comience la depuración.

  2. Pulse el botón Translate para convertir el texto predeterminado en un número de teléfono válido. El subtítulo del botón Call debe cambiar a Call 1-555-6386284:

    Recorte de pantalla de la interfaz de usuario de Phoneword. El usuario ha traducido el texto a un número de teléfono válido.

  3. Pulse el botón Call. Compruebe que aparece un mensaje en el que se le pide que confirme la operación. así que seleccione No.

    Captura de pantalla del mensaje Marcar un número de la interfaz de usuario de PhoneWord.

  4. Vuelva a Visual Studio y detenga la depuración.

Marcación del número de teléfono

  1. En el archivo de código subyacente MainPage.xaml.cs, edite el método OnCall y reemplace el comentario TODO por los bloques try/catch siguientes:

    async void OnCall(object sender, System.EventArgs e)
    {
        if (await this.DisplayAlert(
            "Dial a Number",
            "Would you like to call " + translatedNumber + "?",
            "Yes",
            "No"))
        {
            try
            {
                if (PhoneDialer.Default.IsSupported)
                    PhoneDialer.Default.Open(translatedNumber);
            }
            catch (ArgumentNullException)
            {
                await DisplayAlert("Unable to dial", "Phone number was not valid.", "OK");
            }
            catch (Exception)
            {
                // Other error has occurred.
                await DisplayAlert("Unable to dial", "Phone dialing failed.", "OK");
            }
        }
    }
    

    La clase PhoneDialer del espacio de nombres Microsoft.Maui.ApplicationModel.Communication proporciona una abstracción de la funcionalidad de marcación del teléfono (entre otras) para las plataformas Windows, Android, iOS (y iPadOS) y macOS. El método estático Open intenta utilizar el marcador telefónico para llamar al número proporcionado como parámetro.

    En los pasos siguientes se muestra cómo actualizar el manifiesto de la aplicación Android para permitir que Android use el marcador telefónico. Las aplicaciones de Windows, iOS y MacCatalyst siguen el mismo principio general, excepto que se especifica una funcionalidad diferente en el manifiesto en función del sistema operativo.

  2. En la ventana Explorador de soluciones, expanda la carpeta Plataformas, expanda la carpeta Android, haga clic con el botón derecho en el archivo AndroidManifest.xml y seleccione Abrir con>Selector de editor automático (XML). Seleccione Aceptar.

  3. Agregue el siguiente fragmento XML dentro del nodo de manifiesto después del contenido existente para este nodo.

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        ...
        <queries>
            <intent>
                <action android:name="android.intent.action.DIAL" />
                <data android:scheme="tel"/>
            </intent>
        </queries>
    </manifest>
    
  4. Guarde el archivo.

  5. En la barra de herramientas de Visual Studio, seleccione el perfil Android Emulators/Pixel 3a - API 30 (o similar) e inicie la depuración.

  6. Cuando la aplicación aparezca en el emulador (esto puede tardar unos minutos), escriba un número de teléfono (o acepte el valor predeterminado), seleccione Traducir y, a continuación, seleccione Llamar.

  7. En la alerta Dial a Number, seleccione Yes. Compruebe que el marcador telefónico de Android aparece con el número que ha proporcionado en la aplicación.

    Marcador telefónico de Android que contiene el número proporcionado por la aplicación.

  8. Vuelva a Visual Studio y detenga la depuración.

Resumen

En este ejercicio, ha agregado una interfaz de usuario personalizada a la aplicación mediante páginas y vistas. También ha agregado compatibilidad para realizar una llamada mediante las API específicas de la plataforma disponibles en Android.