DEV Community

Cover image for Let's finally build our app
oreoyona
oreoyona

Posted on

Let's finally build our app

Our job today will be to set up the layout of the ultimate clinical app we decided to build some days ago. We will write the helper functions and some CSS rules.

Last week, we wrote a lot of angular files and the time has come for us to focus on the UI.

At the end of this article, we should have an app looking like the image below

mockup of our app

Today's article will be very technical. Just grab your computer and code. You can find the entire code on GitHub.

Open your home.component.html

The screen of our application needs to take up all the available space and be divided into two parts:

  • a part showing principally the operations(for example the numbers, the current mode selected by the user).

  • another part where to place our buttons.

Let's then write our grid layouts.

We will use the first as the container, representing our app's screen.

The two others will serve respectively as the container of the operation's screen and the container of the buttons' screen.

<GridLayout rows="300, *" columns="*" class="container" height 
="100%" backgroundColor="#303030"> 

    <GridLayout  row="0" col="0" backgroundColor="#303030" columns="20,*" rows="40, *,*,*,*"> 
    </GridLayout>


 <GridLayout row="1" col="0" backgroundColor="#303030" columns="*,10,*,10,*,10,*" rows="*,*,*,*,*">

    </GridLayout>

</GridLayout>

Enter fullscreen mode Exit fullscreen mode

Time to add the buttons and the screens.

<GridLayout columns="*" rows="300, *" height="100%" *ngIf="currentMode != modes.fg && currentMode != modes.apgar">

    <GridLayout row="0" col="0" backgroundColor={{colors.gray}} columns="20,*" rows="40, *,*,*,*"
        *ngIf="currentMode == modes.pam">
        <TextView editable="false" col="1" row="1" class="uxText" color="aquamarine">
            __{{currentMode}}__
        </TextView>
        <FlexBoxLayout col="1" , row="2">
            <TextView editable="false" col="0" row="1" *ngIf="pamArray[0]" class="uxText">
                PAS: {{pamArray[0]}}
            </TextView>
            <TextView editable="false" col="0" row="2" *ngIf="pamArray[1]" class="uxText">
                PAD: {{pamArray[1]}}
            </TextView>

            <TextView editable="false" col="0" row="2" *ngIf="!pamArray[0] && !reponse" class="uxText">
                Valeur systole
            </TextView>
            <TextView editable="false" col="0" row="2" *ngIf="pamArray[0] && !pamArray[1]" class="uxText">
                Valeur diastole
            </TextView>
        </FlexBoxLayout>


        <TextView editable="false" col="1" row="3" class="operation" fontSize="32rem">
            {{screen}}
        </TextView>

        <TextView editable="false" col="1" row="4" class="operation">
            {{reponse}}
        </TextView>

    </GridLayout>
<GridLayout row="0" col="0" backgroundColor={{colors.gray}} columns="20,*" rows="40, *,*,*,*"
        *ngIf="currentMode == modes.imc">

        <TextView editable="false" col="1" row="1" class="uxText" color="aquamarine">
            __{{currentMode}}__
        </TextView>

        <TextView editable="false" col="1" row="3" class="operation">
            {{screen}}
        </TextView>


        <FlexBoxLayout col="1" , row="2">
            <TextView editable="false" col="0" row="1" class="active" *ngIf="imcArray[0]">
                Taille: {{imcArray[0]}}
            </TextView>
            <TextView editable="false" col="0" row="2" class="active" *ngIf="imcArray[1]">
                Poids: {{imcArray[1]}}
            </TextView>

            <TextView editable="false" col="0" row="2" *ngIf="!imcArray[0] && !reponse" class="uxText">
                Valeur taille(cm)
            </TextView>
            <TextView editable="false" col="0" row="2" *ngIf="imcArray[0] && !imcArray[1]" class="uxText">
                Valeur poids(kg)
            </TextView>
        </FlexBoxLayout>


        <TextView editable="false" col="1" row="4" class="operation ">
            {{reponse}}
        </TextView>

    </GridLayout>




    <GridLayout row="1" col="0" backgroundColor="#303030" columns="*,10,*,10,*,10,*" rows="*,*,*,*,*" paddingBottom="25"
        borderTopLeftRadius="20" borderTopRightRadius="20">
        <Button row="0" col="0" text={{currentMode}}  #ac fontSize="16px" disabled></Button>
        <Button row="0" col="2" text="AC" fontSize="20" #back (tap)="bck()"></Button>
        <Button row="0" col="4" text=">" class="nextBtn" #pour (tap)="next()" backgroundColor="#001A11" color="aquamarine"
            fontSize="32"></Button>
        <Button row="0" col="6" text={{modes.pam}} class="op" #div (tap)="changeMode(div)"></Button>

        <Button row="1" col="0" text="7" class="btn" #sept (tap)="getAnim(sept)"></Button>
        <Button row="1" col="2" text="8" class="btn" #huit (tap)="getAnim(huit)"></Button>
        <Button row="1" col="4" text="9" class="btn" #neuf (tap)="getAnim(neuf)"></Button>
        <Button row="1" col="6" text="{{modes.apgar}}" class="op" #fois [nsRouterLink]="['/apgar']"></Button>


        <Button row="2" col="0" text="4" class="btn" #quatre (tap)="getAnim(quatre)"></Button>
        <Button row="2" col="2" text="5" class="btn" #cinq (tap)="getAnim(cinq)"></Button>
        <Button row="2" col="4" text="6" class="btn" #six (tap)="getAnim(six)"></Button>
        <Button row="2" col="6" text={{modes.imc}} class="op" #mois (tap)="changeMode(mois)"></Button>


        <Button row="3" col="0" text="1" class="btn" #un (tap)="getAnim(un)"></Button>
        <Button row="3" col="2" text="2" class="btn" #deux (tap)="getAnim(deux)"></Button>
        <Button row="3" col="4" text="3" class="btn" #trois (tap)="getAnim(trois)"></Button>


        <Button row="4" col="0" text="C" class="btn" #ext (tap)="reset()"></Button>
        <Button row="4" col="2" text="0" class="btn" #zero (tap)="getAnim(zero)"></Button>
        <Button row="4" col="4" text="." class="btn" #point (tap)="getAnim(point)" value="."></Button>
        <Button row="4" col="6" text="=" class="opBtm" #egal (tap)="next()"></Button>
    </GridLayout>
</GridLayout>

Enter fullscreen mode Exit fullscreen mode

We need to update our component

import { Component, OnInit } from '@angular/core'
import { Button, Color } from '@nativescript/core';
import { Page } from '@nativescript/core/ui/page';
import { checkState, clear, compute, back, scaleAnim} from '../common/functions'
@Component({
  selector: 'Home',
  templateUrl: './home.component.html',
  styleUrls: ["./home.component.css"],
})
export class HomeComponent implements OnInit {
  //members of the class
  screen = "";
  reponse = "";
  pam = true;
  apgar = false;
  fg = false;
  imc = false;

  modes = {
    imc: "IMC",
    fg: "FG",
    apgar: "AP",
    pam: "PAM"
  }
  currentMode = this.modes.pam;
  images = {
    back: "~/assets/back.svg"
  }

  pamArray = [];
  imcArray = [];
  colors = {
    gray: new Color("#383838")
  }

  //end Members of the class definition

  /************************************* Methods ******************************************/


  /**
   * getAnim - saves the buttons typed to the screen
   * @param btn : Button clicked by the user
   */
  getAnim = (btn: Button) => {
    scaleAnim(btn);
    if(checkState(this.reponse)){
      this.reponse = clear(this.reponse);
      this.pamArray = [];
      this.imcArray = [];
    }
    this.screen += btn.text;
  }
  /**
   * reset - resets the screen and all the variables
   */

  reset = ()=>{
    this.reponse = clear(this.reponse);
    this.pamArray = [];
    this.imcArray = [];
    this.screen = clear(this.screen);
  }

  /**
   * changeMode - changes the mode of the calculator
   * and updates the screen accordingly
   * @param btn : Button clicked by the user
   */
  changeMode(btn: Button) {
    const mode = btn.text;
    if (mode != this.currentMode) {
      this.screen = clear(this.screen);
      this.reponse = clear(this.reponse);
      this.imcArray = [];
      this.pamArray = [];
    };
    this.currentMode = mode;

  }

  /**
   * bck - invokes the back function
   * to delete the latest entered char in the screen
   */
  bck(){
    this.screen = back(this.screen);
  }

  /**
   * next - saves variables and do the computations
   * according to the selected mode
   */
  next() {
    //checks that the current mode is indeed "PAM"
    if (this.currentMode == this.modes.pam) {
      //computations for the "PAM" mode.
      if (!this.screen && !this.pamArray[0]){}
      if (this.pamArray[0] && this.pamArray[1]) {
        this.reponse = String(compute("PAM", this.pamArray));
        this.pamArray = [];
        this.screen = clear(this.screen);
      }
      this.pamArray.push(Number(this.screen));
      this.screen = clear(this.screen);
    }
else if(this.currentMode == this.modes.imc){
      //computationa for the "IMC" mode.
      if (!this.screen && !this.imcArray[0]){}
      if (this.imcArray[0] && this.imcArray[1]) {
        this.reponse = String(compute("IMC", this.imcArray));
        this.imcArray = [];
        this.screen = clear(this.screen);
      }
      this.imcArray.push(Number(this.screen));
      this.screen = clear(this.screen);
    }

  }

  constructor(private page: Page) {
    this.page.actionBarHidden = true;

  }

  ngOnInit(): void {


  }
}

Enter fullscreen mode Exit fullscreen mode

Let's create the helper functions

Our calculator needs to compute a lot of stuff. Let's create a folder named common and a file, that we will name functions in which we will place every single helper function necessary to our app.

I commented the code so, it should be easy to understand it.

export function back(screen: string){
import { ElementRef, ViewChild } from "@angular/core";
import { Button } from "@nativescript/core";
export const formulas = {
    pam: "[(PAS + (2 x PAD) )/3]",
    imc: "[Poids(Kg)/Taille^2(m)]"
}
/**
 * clear - functions to clear the screen
 * @param screen : the screen to be cleared
 */
export function clear(screen: string){
    screen = "";
    return screen;
}
/**
 * 
 * @param mode the mode chosen by the user
 * @param dest the place of the screen where 
 * the mode should be displayed
 */
export function changeMode(mode: string, dest: string){
    dest = mode;
}

/**
 * 
 * @param pas systolic arterial pressure
 * @param pad diastolic arterial pressure
 * @returns mean arterial pressure
 */
export function pam(pas: number, pad: number){
    return (2*(pad) + pas)/3
}


/**
 * imc - computes the IMC
 * @param taille: length in cm
 * @param poids: weight in Kg
 * @returns the IMC
 */
export function imc(taille: number, poids: number){
    taille = converter(taille);
    const tailleCarre = Math.pow(taille, 2);
    return poids/tailleCarre;

}
/**
 * compute - finds the right formula and computes according to
 * the mode
 * @param mode the mode chosen by the user
 * @param store the array where are stored variables
 * @returns the desired computation
 */
export function compute(mode: string, store: string[]){
    switch (mode) {
        case "PAM":
            return pam(Number(store[0]), Number(store[1]))
        case "IMC":
            return imc(Number(store[0]), Number(store[1]))
    }
}
/**
 * pusher - stores the first param in an array
 * @param screen the screen containing the first param
 * @param store the array where to store thr first param
 */
export function pusher(screen: string, store: Array<string>){
    store.push(screen);
    clear(screen);
}
/**
 * scaleAnim - animates the btn to scale 0.5 times
 * from its original state
 * @param btn : the button to be animated
 */
export function scaleAnim(btn: Button){
    btn.animate({
        scale:{x:1.5, y:1.5},
        duration: 1,
        curve: "easeOut",
        iterations: 1,
    }).then(()=>{
        btn.animate({
            scale: {x:1, y:1}
        })
    })
}
/**
 * checkState - checks the state of the screen
 * @param screen : the screen to be checked
 * @returns true if the screen is not empty
 * false otherwise
 */
export function checkState(screen: string){
    return screen?true:false;
}

/**
 * getFormula - returns the formula of the selected mode 
 * @param mode : the formula to be ruturned
 */
export function getFormula(mode: string){
    switch (mode) {
        case "PAM" || "pam":
            return formulas.pam;
        default:
            break;
    }
}
/**
 * back - delete the latest entered value in the screen
 * @param screen the screen to be sliced
 * @returns a new string
 */
export function back(screen: string){
    if (screen){
        const len = screen.length - 1;
        return screen.slice(0, len);
}
    else{
        return screen;
}
}
/**
 * converter - converts the length from cm to m
 * @params len: the length in cm
 * @returns len in m
 */
export function converter(len: number){
    return len/100;
}

/**
 * choose - helps make a choice on 3 radio btns 
 * @param vcActive : the active viewChild
 * @param vc1 : an ElementRef to reset
 * @param vc2 : an ElementRef to reset
 * @param btn : the button used to toggle the change
 */
export async function choose(vcActive: ElementRef, vc1: ElementRef, vc2: ElementRef, btn?: Button){
    vcActive.nativeElement.toggle();
    vc1.nativeElement.checked = false;
    vc2.nativeElement.checked = false;
}

Enter fullscreen mode Exit fullscreen mode

Let's add some style to our app

Open the home.component.css file and write those rules

.op{
    color: aquamarine;
    background-color: transparent;
    font-size: 16em;
    margin-top: 8px;
    margin-bottom: 8px;
    z-index: 0;
  }
  .opBtm{
    border-radius:50%;
    background-color: gray;
    font-size: 25px;
    margin-bottom: 30px;
    z-index: 0;

  }
  .opBtm{
    box-shadow:  0 0 30px gray;
  }


  .uxText{
    color: white;
    font-style: italic;  
}
  .btn{
    color: #ccc;
    background-color: transparent;
    font-size: 35em;
    margin-top: 8px;
    margin-bottom: 8px;
    z-index: 0;

  }

Enter fullscreen mode Exit fullscreen mode

Add the icon fonts

I love Angular material so I'll use Google material icons.

In the source of your app, create a folder and name it fonts

Download the fonts here and place them in the fonts folder.

In your CSS file, write these rules

.m-icon-outlined{
     font-family: "MaterialIcons-Outlined";
     font-weight: 400;
}


Enter fullscreen mode Exit fullscreen mode

Keep in mind that the font family name must match the name of the font in your fonts folder. Click here to find the code of an icon. We will use that code just like it is recommended here, by the NativeScript Docs

Test your app, run:

ns run android

Please refer to my GitHub if you have some problems running your app.

Ps: We will release our app next time so stay tuned...

Top comments (0)