Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Automatically Setting Your Profile Picture In A NativeScript Angular App

TwitterFacebookRedditLinkedInHacker News

It doesn’t just take a good idea when it comes to making a great mobile application. Sometimes it takes a little flair in the user interface department to make a good mobile application into a great mobile application. For example, when you have a user login screen, you could just ask for username and password credentials, or you could include profile picture information as well. Which do you think would be better?

Gravatar offers a global avatar registry based on user email address. In other words, you upload your profile picture to Gravatar, associate it with your email address, and then that same avatar can be used in any application that uses Gravatar. WordPress, the platform this blog is hosted on, uses Gravatar for my profile picture for example.

We’re going to see how to automatically set the user profile picture in a NativeScript Angular application using the Gravatar API.

The goal here is to use a mixture of techniques to make your application a little more memorable. Take the following animated image of two emulators, for example:

NativeScript Gravatar Example

In the above image we have an Android and an iOS emulator both running a NativeScript application. By default it shows the Gravatar placeholder image. When a matching email address is used, the placeholder image changes through an animation. The matching avatar is retrieved through the Gravatar API.

Creating a New NativeScript Angular Project

To keep things easy to understand, we’re going to create a fresh NativeScript project for Android and iOS that uses Angular and TypeScript.

From the Command Prompt (Windows) or Terminal (Linux and Mac), execute the following:

tns create GravatarProject --ng
cd GravatarProject
tns platform add ios
tns platform add android

If you’re not using a Mac with Xcode installed, you won’t be able to build and deploy for the iOS platform.

The Gravatar API requires all email addresses be hashed using the MD5 algorithm before sending them over HTTP via a request. JavaScript doesn’t have any functions for this included out of the box so we’ll have to download a library for the job.

From the command line, execute the following:

npm install blueimp-md5 --save

The above command will install the blueimp MD5 JavaScript library. Because of it’s simplicity, we won’t bother trying to find TypeScript type definitions for it.

Adding the TypeScript Logic for Using Gravatar

The goal of our logic is to hash emails and send them to Gravatar in hopes of getting an image back. We don’t need to do Angular HTTP requests to make this happen based on the format of the API.

Take the app/app.component.ts file for example:

import { Component } from "@angular/core";
var MD5 = require("blueimp-md5");

@Component({
    selector: "my-app",
    templateUrl: "app.component.html"
})
export class AppComponent {

    public picture: string;
    public email: string;

    public constructor() {
        this.email = "";
        this.picture = "https://www.gravatar.com/avatar/00000000000000000000000000000000?s=150";
    }

    public getProfilePicture(email: any) {
        if(this.validateEmail(email)) {
            this.picture = "https://www.gravatar.com/avatar/" + MD5(email) + "?s=150";
        }
    }

    // Taken from http://stackoverflow.com/a/46181/498479
    private validateEmail(email: any) {
        let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        return re.test(email);
    }

}

There isn’t much going on in the above code, but we’re going to break it down anyways.

After importing the Angular and MD5 components we enter the AppComponent class. In this class we have two public variables, one which will hold a link to a Gravatar image, whether it be placeholder or real, and one to hold the current email address.

In the constructor method we initialize these variables. The initial picture variable will be a link to the Gravatar placeholder image.

Notice the validateEmail method. I didn’t create this code, but instead I picked it off of Stack Overflow. What it does is checks to see if an email address is valid using regular expressions. We want this function because we only want to send valid emails to Gravatar to cut down on network requests.

public getProfilePicture(email: any) {
    if(this.validateEmail(email)) {
        this.picture = "https://www.gravatar.com/avatar/" + MD5(email) + "?s=150";
    }
}

In the above getProfilePicture method we pass an MD5 hashed, valid email, to Gravatar. If it doesn’t exist we’ll get a placeholder image back, otherwise we’ll get a correct image back.

This project will use an input form for emails and by default in Angular there is no data binding available. We have to include a particular forms module to make this possible.

Open the project’s app/app.module.ts file and include the following code:

import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/platform";
import { NativeScriptFormsModule } from "nativescript-angular/forms";

import { AppComponent } from "./app.component";

@NgModule({
    declarations: [AppComponent],
    bootstrap: [AppComponent],
    imports: [NativeScriptModule, NativeScriptFormsModule],
    schemas: [NO_ERRORS_SCHEMA]
})
export class AppModule { }

In the above we’ve just imported the NativeScriptFormsModule and added it to the imports array in the @NgModule block.

The code so far is quite basic, but it gets the job done. However, we want to fancy it up and get some animations into the mix.

Including Angular Animation Transitions and States

There are several ways to add animations to a NativeScript mobile application, but for best control it makes sense to use Angular animations. These animations will extend on our TypeScript code.

Open the project’s app/app.component.ts file and include the following in the @Component block:

@Component({
    selector: "my-app",
    templateUrl: "app.component.html",
    animations: [
        trigger("state", [
            transition("void => *", [
                animate(200, style({
                    transform: 'scale(2, 2)'
                })),
            ]),
            transition("* => *", [
                animate(500, keyframes([
                    style({ transform: 'scale(2, 2)' }),
                    style({ transform: 'scale(0, 0)' }),
                    style({ transform: 'scale(2, 2)' }),
                ]))
            ]),
        ])
    ]
})

Above defines a set of animations called state that don’t actually have states in them. Instead we have transition instructions only.

When the component is void, or in other words not rendered to the screen and that component status changes, it will be scaled by 200% over the span of 200 milliseconds. When the state changes to anything other than void to wildcard, we have keyframe animations. The keyframes scale from 200% to 0% and back to 200% over the span of 500 milliseconds. The animation will look like a pulse.

To change the non-defined states we need to create a boolean or some other variable to represent the current state:

public currentState: boolean;

Within the constructor method we can initialize this variable to false. When using a valid email against the getProfilePicture we can toggle the state to trigger the animation.

The full app/app.component.ts file would look like this:

import { Component, trigger, state, transition, animate, style, keyframes } from "@angular/core";
var MD5 = require("blueimp-md5");

@Component({
    selector: "my-app",
    templateUrl: "app.component.html",
    animations: [
        trigger("state", [
            transition("void => *", [
                animate(200, style({
                    transform: 'scale(2, 2)'
                })),
            ]),
            transition("* => *", [
                animate(500, keyframes([
                    style({ transform: 'scale(2, 2)' }),
                    style({ transform: 'scale(0, 0)' }),
                    style({ transform: 'scale(2, 2)' }),
                ]))
            ]),
        ])
    ]
})
export class AppComponent {

    public picture: any;
    public email: string;
    public currentState: boolean;

    public constructor() {
        this.email = "";
        this.picture = "https://www.gravatar.com/avatar/00000000000000000000000000000000?s=150";
        this.currentState = false;
    }

    public getProfilePicture(email: any) {
        if(this.validateEmail(email)) {
            this.currentState = !this.currentState;
            this.picture = "https://www.gravatar.com/avatar/" + MD5(email) + "?s=150";
        }
    }

    // Taken from http://stackoverflow.com/a/46181/498479
    private validateEmail(email: any) {
        let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        return re.test(email);
    }

}

This just leaves us to creating the XML and CSS based UI for the project.

Designing a Pleasant NativeScript UI

What happens next will span two different project files. The basic UI will be a screen with two sections positioned vertically. The top section will be the profile picture and the second section will be the form.

Open the project’s app/app.component.html file and include the following XML markup:

<ActionBar title="{N} Gravatar"></ActionBar>
<GridLayout rows="*, *" columns="*">
    <Image [src]="picture" [@state]="currentState ? 'active' : 'inactive'" height="75" width="75" class="img-rounded" row="0" col="0"></Image>
    <StackLayout class="form" row="1" col="0">
        <StackLayout class="input-field">
            <Label class="label" text="Email:"></Label>
            <TextField class="input input-border" [(ngModel)]="email" (ngModelChange)="getProfilePicture($event)" autocapitalizationType="none"></TextField>
        </StackLayout>
        <StackLayout class="input-field">
            <Label class="label" text="Password:"></Label>
            <TextField class="input input-border" secure="true"></TextField>
        </StackLayout>
    </StackLayout>
</GridLayout>

The GridLayout lets us split the screen into sections. I did previous article on GridLayout stretching, but essentially using a wildcard for each row means space them equally.

The first row is our image which is bound to the picture variable in the TypeScript code. The [@state] chunk is the state animation and it holds what our current state is. Remember, as long as it changes the animation will trigger. It doesn’t really matter what it changes to in our scenario.

The second row is a form with several input fields. The first input field is bound to our email variable and every time the data changes, the data is passed to the getProfilePicture method.

I’m not much of a fan when it comes to the default padding of input fields so I’ve defined my own in the app/app.css file:

.form .input-field .input {
    padding: 5;
    background-color: #F0F0F0;
}

@import 'nativescript-theme-core/css/core.light.css';

The above CSS will add padding and a background to every text field.

Conclusion

You just saw how to use Gravatar and Angular to automatically set a profile picture based on email addresses within your NativeScript Android and iOS application. While not totally necessary within a mobile application, it does make the application user experience a bit more fancy. Additionally it teaches you how to use Angular animations and change events on input fields.

A video version of this article can be seen below.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.