CAPITOLUL I: INTRODU CERE ………………………….. ………………………….. ………………………….. ………. 1 CAPITOLUL… [613772]

Cuprins
CAPITOLUL I: INTRODU CERE ………………………….. ………………………….. ………………………….. ………. 1
CAPITOLUL II: STADIU L ACTUAL AL APLICAȚI ILOR ÎN DOMENIUL FIT NESS -ULUI ȘI AL NUTRIȚIEI …. 4
2.1. IMPACTUL TEHNOLOGIEI ÎN DOMENIUL FITNESS -ULUI ȘI AL NUTRIȚIEI ………………………….. ………………….. 5
2.2. APLICAȚII SIMILARE EX ISTENTE ………………………….. ………………………….. ………………………….. ……… 6
2.2.1. MyFitnessPal ………………………….. ………………………….. ………………………….. ……………….. 6
2.2.2. LoseIt! ………………………….. ………………………….. ………………………….. ………………………… 7
2.3. AVANTAJELE APLICAȚIEI PRONUTRITION ………………………….. ………………………….. ………………………. 8
CAPITOLUL III: UNELT E SOFTWARE FOLOSITE PENTRU DEZVOLTAREA A PLICAȚIEI ………………….. 10
3.1. PLATFORMA DE DEZVOLTA RE PENTRU APLICAȚII MOBILE IONIC (IONIC FRAMEWORK )………………………….. 10
3.1.1. Angular ………………………….. ………………………….. ………………………….. …………………….. 11
3.1.2. Cordova ………………………….. ………………………….. ………………………….. ……………………. 12
3.2. LIMBAJE DE PROGRAMARE ………………………….. ………………………….. ………………………….. ………… 13
3.2.1. HTML (HyperText Markup Language) ………………………….. ………………………….. ……….. 13
3.2.2. SCSS ( Sassy CSS) ………………………….. ………………………….. ………………………….. …………. 14
3.2.3. TypeScript ………………………….. ………………………….. ………………………….. …………………. 14
3.3. BAZE DE DATE ………………………….. ………………………….. ………………………….. ………………………. 15
3.3.1. Alegerea unei baze de date pentru stocarea datelor ………………………….. ……………….. 15
3.3.2. Alegerea sistemului de gestionare al bazei de date MySQL ………………………….. ………. 16
CAPITOLUL IV: PROIEC TAREA ȘI DEZVOLTAREA APLICAȚIEI ………………………….. ……………………. 18
4.1. ANALIZA PROIECTĂRII A PLICAȚIEI ………………………….. ………………………….. ………………………….. …. 18
4.1.1. Proiectarea bazei de date ………………………….. ………………………….. ………………………… 18
4.1.2. Precizarea str ucturii mulțimilor candidat ………………………….. ………………………….. …… 19
4.2. DEZVOLTAREA APLICAȚIE I ………………………….. ………………………….. ………………………….. …………. 20
4.2.1. Ghidul utilizatorului ………………………….. ………………………….. ………………………….. ……. 20
4.2.2. Ghidul dezvoltatorului ………………………….. ………………………….. ………………………….. … 35
CAPITOLUL V: CONCLUZ II ………………………….. ………………………….. ………………………….. ………… 58
BIBLIOGRAFIE ………………………….. ………………………….. ………………………….. ………………………… 61
ANEXĂ CODURI SURSĂ ………………………….. ………………………….. ………………………….. ……………. 64

1

Capitolul I: Introducere

Odată cu trecerea timpului au fost dezvoltate noi tehnologii c are au permis
fabricanților de hardware să concentreze cât mai multă performanță într -un mediu de
dimensiuni cât mai mici. Plecând de la sisteme desktop din ce în ce mai compacte și
ajungându -se la sisteme de tip all -in-one sau laptop, următorul pas a fost, firește,
investiția și dezvoltarea pe piața telefoanelor mobile.
O aplicație mobilă este un program software construit special pentru rularea pe
un dispozitiv mobil, precum telefon, tabletă sau smartwatch. Aplicațiile de acest tip au
devenit din ce în ce mai răspândite printre c ei ce folosesc telefoane mobile [26].
Dezvoltarea de aplicații mobile presupune luarea în considerare a limitărilor și
caracteristicilor dispozitivelor în cauză. Aceste dispozitive rulează datorită energiei
provenite de la o baterie, așadar au o putere de procesare, în general, mai slabă față de
un computer personal, având totodată mai multe caracteristici precum camere
foto/video, detectare de locație etc. De asemenea , aplicațiile trebuie dezvoltate dinamic
pentru a se putea auto -adapta la o gamă variată de r ezoluții și dimensiuni de ecran [6].
Acest tip de aplicații joacă un rol din ce în ce mai important în ceea ce privește
sistemul de sănătate, iar atunci când acestea sunt proiectate și implementate
corespunzător pot aduce un număr semnificativ de beneficii [29,27].
Pot spune cu siguranță că aplicațiile mobile reprezintă viitorul, așadar ideea
dezvoltării de aplicații proprii ce țintesc această piață se poate dovedi mai mult decât
atractivă. Prin urmare , văzând acest potențial, a m ales să combin o pasiune ce nu
prezintă o legătură directă cu domeniul pe care am decis sa îl urmez, și anume fi tnessul
și nutriția cu domeniul informaticii. Obiectivele pe care mi le -am propus să le ating în
dezvoltarea aplicației mobile sunt:
a. Stocarea informațiilor ut ilizatorilor într -o bază de date , cu scopul
schițării unui profil personal, relevant domeniului nutriției ;

2
b. Calculul automat (și cât mai precis) al necesarului zilnic de kilocalorii,
macronutrienți și micronutrienți de care organismul are nevoie pentru o
dezvoltare echilibrată în ceea ce privește obiectivele unui stil de viață
sănătos , pe baza profilului personal ;
c. Posibilitatea modificării profilului personal de către utilizator, acesta
permițând stabilirea unor limite în ceea ce privește nutrienții dăunător i în
cantități mai mari decât limitele impuse ;
d. Securizarea aplicației prin dezvoltarea unui sistem de înregistrare și
logare a utilizatorilor pe baza unei adrese de e -mail și a unei parole.
e. Crearea unui jurnal virtual în care utilizatorul să poată trece fi ecare
aliment consumat, în cantitatea consumată ;
f. Afișare a progres ului pentru o zi în care utilizatorul a introdus în jurnal
toate alimentele consumate într -o pagină în care acesta va putea observa
dacă a îndeplinit sau depășit cantitatea zilnică impusă de kilocalor ii și
nutrienți ;
g. Dezvoltarea unui meal planner care să genereze un exemplu simplu de
dietă pentru utilizator.

Lucrarea a fost structurată după cum urmează:
 Capitolul 1. Introducere : Acest capitol prezintă tema alea să precum și
obiectivele pe care mi le -am propus să le ating în dezvoltarea aplicației .
De asemenea sunt prezentate și structura lucrării pe capitole, motivul din
spatele alegerii temei Dezvoltarea unei aplicații mobile de tip Fitness &
Nutrition pe platforma Android și abordarea realiză rii lucrării ;
 Capitolul 2. Stadiul actual al aplicațiilor în domeniul fitness -ului și al
nutriției : Este capitolul în care am descris modul în care domeniul
informaticii, și în general tehnologia, au influențat lumea fitness -ului și a
nutriției. De asemene a am prezentat alte două apli cații mobile similare,
făcând o comparație cu aplicația dezvoltată de către mine ;
 Capitolul 3 . Unelte software folosite pentru dezvoltarea aplicației : În
acest capitol am prezentat instrumentele software folosite și am
argument at alegerea acestora. Tot în acest capitol sunt prezentate

3
limbajele de programare ce au fost folosite pentru a duce aplicația la bun
sfârșit ;
 Capitolul 4. Proiectarea și dezvoltarea aplicației : Este capitolul în care
am analizat proiectarea aplicației ProNutrition și am creat dou ă ghiduri,
unul pentru utilizator, ce are rolul de a prezenta procesul de folosire al
aplicației, iar celălalt pentru dezvoltatorii de aplicații similare, care
prezintă modul de funcționare al acesteia ;
 Capitolul 5 . Concluzii : În capitolul 5 am prezentat concluziile referitoare
la realizarea obiectivelor, la experiența dobândită în timpul dezvoltării
aplicației și am încercat să aduc câteva idei pentru o posibilă
îmbunătățire a acesteia pe viitor .

Pentru a realiza proiectul am fol osit platforma Ionic alături de o bază de date
pentru stocarea datelor necesare funcționării corecte a aplicației .

4

Capitolul II: Stadiu l actual al aplicați ilor în domeniul fitness -ului și al
nutriției
Un factor important de luat în considerare în moment ul folosirii aplicației este
că aceasta a fost destinată persoane lor cu vârste de peste 18 ani. Atât pentru copii, cât și
pentru persoanele cu o vârstă foarte înaintată, capitolul nutriție va deveni mai fragil,
cea mai sigură soluție fiind consultul și urm area recomandărilor medicului de familie
sau ale unui medic specializat.
Conform AHA (American Heart Association), limita maximă admisă în ceea ce
privește consumul de sodiu se află un deva între 1500 și 2300mg pe zi [4].
De asemenea USDA (United States Dep artment of Agriculture), AND
(Academy of Nutrition and Dietetics) și ADA (American Diabetes Association)
recomandă același 1500 – 2300mg consum/zi. Așadar aplicația va impune o limită
standard de 2000mg permițând utilizatorului să modif ice în orice moment acest număr
[25].
Zahărul poate fi găsit sub două forme într -un aliment: zahăr natural (fructoz a)
prezent, în general, în fructe și legume , este forma recomandată consumului zilnic,
acesta aducând beneficii organismului. Cea de -a doua formă, și anume zahăr ul adăugat
din alimente (s ucroza), devine o problemă în momentul consumului exagerat . Cu toate
acestea, organismul poate tolera consumul acestui tip de zahăr fără a fi afectat într -un
mod îngrijorător dacă ac esta este consumat cu moderație [3].
În ceea ce privește acest tip, doza zilnică recomandată de către AHA este de 25g
pentru femei și 38g pentru bărbați. Aplicația va seta o limită de 2 0g indiferent de sexul
utilizatorului, această limită având, desigur, posibilitatea de a fi modificată.
Grăs imile saturate reprezintă încă o piedică în nutriția unui stil de viață sănătos.
AHA recomandă un consum zilnic (în grame) maxim de 5 % sau 6% din bugetul caloric
zilnic. Aplicația va calcula bugetul caloric zilnic apoi va seta limita grăsimilor satur ate
la 5% din bugetul respectiv [16].

5
În ultimă fază va trebui tratată și problema colesterolului. Deși este mai
importantă limitarea grăsimilor saturate deoarece acestea sunt factorul principal de
mărire al colesterolului din sânge, nu este o idee rea să fim at enți și la colesterolu l luat
din alimentele consumate [2]. Aplicația impune o limită de 20% din bugetul caloric
calculat (în miligrame) . Acest număr poate fi , desigur, modificat de către utilizator, fără
restricții.
Limitele anterior menționate pot să dife re, în general, de la persoană la persoană
atât din cauza diferențelor stilului de viață al acestora, cât și din pricina anumitor
condiții medicale. De exemplu un oricare individ, ales la întâmplare, poate avea un
metabolism mai rapid sau mai lent față de o oricare altă persoan ă. Similar oamenii pot
prezenta o sensibilitate sau, în caz contrar, o rezistență crescută în ceea ce privește
reacția organismului la diverse substanțe. În alt caz, presupunând că un om suferă de o
anumită boală, limitele vor fi mult mai stricte și, posibil, mai drastice prin comparație
cu recomandările generale menționate anterior.
Din acest motiv aplicația oferă posibilitatea modificării acestor limite după
bunul plac al utilizatorului, fără vreo anumită restricție. Valorile calcula te automat
reprezintă doar o simplă recomandare generală și nu pot fi calculate cu exactitate.
Specificul pentru fiecare utilizator în parte trebuie să țină cont de mai multe variabile,
iar cea mai potrivită persoană pentru aceste recomandări va fi, în fin al, un medic
capabil, specializat în domeniu.
2.1. Impactul tehnologiei în domeniul fitness -ului și al nutriției
Cu siguranță era tehnologică a influențat în numeroase moduri lume a fitness –
ului și a nutriției. Aceasta a adus avantaje precum posibilitatea construirii unor aparate
pentru fitness, atât pentru recuperarea medicală (din domeniul fizioterapiei), cât și
pentru numeroase tipuri de antrenament, pentru per soane de toate vârstele. Însă
totodată tehnologia a contribuit , din nefericire, și la creștere a sedentarism ului în rândul
populației [22].
Pe lângă partea hardware, au fost și sunt dezvoltate și numeroase programe
software, pe diverse platforme, ce au fost și sunt folosite pentru a ghida utilizatorul în
atingerea unor țeluri impuse, chiar dac ă este vorba de combaterea anumitor condiții
medicale sau de țeluri impuse individual . În ceea ce privește aplicațiile mobile, acestea

6
reprezintă o modalitate modernă prin care un dezvoltator poate ajunge cu ușurință la
mii de utilizatori, dat fiind faptul că o bună parte din populație folosește un dispozitiv
compatibil.
Există, desigur, diverse tipuri de aplicații mobile create în mod special pentru
pasionații de fitness și nutriție. Din păcate însă, principalul dezavantaj al folosirii
acestor aplicați i este reprezentat prin faptul că utilizatorul nu poate beneficia de toate
caracteristicile acestora decât în cazul achi ziționării unui pachet premium.
Prin dezvoltarea propriei aplicații plănuiesc să ofer aceste caracteristici încă de
la prima instalare, fără a bombarda utilizatorul cu reclame sau oferte de achiziționare,
astfel permițându -i acestuia să se concentreze în proporție de 100% pe ceea ce contează
și anume atingerea obiectivelor impuse. Totodată doresc ca aplicația să ofere în plus
posibilitatea gene rării automate a unui plan nutrițional pentru utilizatorii care doresc
acest lucru. Aplicația pune de asemenea accent pe impactul diferitelor alimente asupra
organismului și anunță utilizatorul în cazul în care anumite limite au fost depășite
(precum limit ele zilnic e de sodiu, grăsimi saturate etc) .
2.2. Aplicații similare existente
În continuare voi prezenta două aplicații similare, ce au fost dezvoltate în trecut
și care, în prezent, au un număr considerabil de utilizatori.
2.2.1. MyFitnessPal
MyFitnessPal a fost concepută în 2005 de către Albert Lee și Mike Lee urmând
ca drepturile asupra aplicației să fie achiziționate de Under Armour în 2015. Aceasta
este o aplicație mobilă ce calculeaz ă un buget caloric al utilizatorului bazat pe date
person ale și permite ținerea unui jurnal virtual în care utilizatorul notează alimentel e
consumate alături de cantităț ile lor. MyFitnessPal folosește o bază de date ce conține
milioane de alimente. Aplicația verifică dacă utilizatorul a respectat acest buget, și
calculează raportul de macronutrienți pe baza alimentelor consumate [9]. Interfața
aplicației poate fi văzută în figura 1.

7

Figura 1: Interfața MyFitnessPal [14]

2.2.2. LoseIt !
În aplicația LoseIt ! utilizatorul începe prin a seta țelul dorit (pierdere greutate,
menținere greutate etc ). Aplicația va calcula apoi, similar MyFitnessPal, bugetul caloric
și nutrițional [6].
După spusele acestora, Începând cu 2008, LoseIt! a ajutat mai mult de 30 de
milio ane de utilizatori să scape de 27+ milioane kg de grăsime prin oferirea celui mai
cuprinzătoar program personal de slăbit, pe baza de aplicației mobile [8]. Interfața
aplicației LoseIt este ilustrată în figura 2.

8

Figura 2: Interfața LoseIt [12]

Un avan taj în ceea ce privește folosirea aplicațiilor menționate este reprezentat
de o caracteristică comună între acestea, și anume posibilitatea scanării codului de bare
al unui aliment și introducer ea automată a acestuia în jural [5,7]. Acest lucru simplifică
substanțial procesul de adăugare.
2.3. Avantajele aplicației ProNutrition
Principalul avantaj al aplicației ProNutrition este reprezentat de oferirea
posibilității urmăririi anumitor nutrienți (Nutrient Tra cking), și anume sodiu, zahăr
adăugat, grăsimi sat urate și colesterol. Cu alte cuvinte, ProNutrition pune accentul în
primul rând pe sănătate, utilizatorul fiind informat în timp real dacă a depășit sau nu
anumite limite impuse. Î n acest fel, acesta poate lua oricând decizia corectă, decizie
bazată pe aceste informații.
Un al doilea avantaj constă în faptul că aplicația este User -friendly. După
completarea câmpurilor din pagina PROFILE , utilizatorului i se vor prezenta numai 3
pagini ce pot fi accesate cu ușurință cu un singur clic, folosind tab -urile din josul
ecranului. Fără alte opțiuni ascunse, aplicația încearcă să ofere un mediu de lucru curat,
cât mai c lar, ce oferă doar strictul necesar în ceea ce privește satisfacerea nevoilor
utilizatorului .

9
Un alt avantaj este reprezentat de lipsa totală a reclamelor. Pe lângă faptul că
acest lucru permite utilizatorului să se concentreze fără distrageri asupra atingerii
obiectivelor impuse, l ipsa reclamelor ajută aplicația în minimizarea timpului de
încărcare a paginilor, de prelucrare a datelor și de efectuare a calculelor matematice din
spatele acesteia.
Un ultim avantaj este oferit, desigur, de posibilitatea generării unei liste de
alimente ce, odată consumate, vor satisface nevoile utilizatorului în ceea ce privește
necesarul de nutrienți în luarea unei mese . În acest mod , acesta se poate inspira în orice
moment din generatorul paginii MEAL , oferindu -i posibilitatea de a evita atât
„pierder ea” timpului cât și efortul ce trebuie depus în căutare a prin alte mijloace.

Ținând cont de cele prezentate anterior, în tabelul 1 am rezumat îndeplinirea
unor criterii de comparații pentru cele trei tipuri de software -uri destinate nutriției și
fitness -ului:

Tabelul 1: Analiza comparativă
LoseIt MyFitnessPal ProNutrition
Calorie Counter   
Macronutrient chart   
Interfață User -friendly x  
Lipsa reclamelor încă de
la prima instalare x x 
Nutrient Tracking
de la prima instalare x x 
Meal Planner x x 

10

Capitolul III: Unelte software folosite pentru dezvoltarea aplicației
3.1. Platforma de dezvoltare pentru aplicații mobile Ionic ( Ionic Framework )
Am considerat că alegerea potrivită în ceea ce privește platforma de dezvoltare
pentru această aplicație este Ionic Framework . Deși inițial am vrut să dezvolt aplicația
în mediu nativ, strict pentru Android , (iar acest l ucru implica folosirea limbaju lui de
programare oficial al platformei, și anume JAVA), am descoperit o alternativă cel puțin
interesantă prin Ionic .
Ionic Framework este un SDK (software development kit) dedicat dezvoltării de
aplicații pentru dispozitivele mobile. Platforma a fost c reată în anul 2013 de către Max
Lynch, Ben Sperry și Adam Bradley, membri ai companiei Drifty Co , și a avut ca scop
principal oferirea unei posibilități de dezvoltare hibridă (în comparație cu dezvoltarea
nativă , ce diferă de la sistem de operare la sistem de operare ) a aplicaților mobile [10].
Prima versiune Ionic avea la bază AngularJS , o platformă de dezvoltare open –
source front -end, concepută de Google , ce are la bază limbajul de programare
JavaScript , rolul acesteia fiind interpretarea de cod HTML și crearea unor legături între
tag-uri și variabile JavaScript , și Apache Cordova (cunoscută anterior ca PhoneGap ),
platformă creată de către Nitobi Software (preluată mai târziu de către Adobe Systems ),
ce permite programatorilor software să dezvolte aplicați i mobile folosind CSS3 ,
HTML5 și JavaScript [10].
Principal ul avantaj al platformei Ionic este reprezentat , în mod evident, de
posibilitatea scrierii unui singur cod pentru o multitudine de dispozitive mobile,
indiferent de si stemul de operare al acestora .
Ultima versiune, cunoscută sub numele de Ionic 3 sau simplu Ionic, are la baza
Angular și Cordova . Platforma face posibilă dezvoltarea de aplicații prin folosirea
anumitor tehnologii web disponibile , și anume HTML 5, Scss și TypeScript , ca mai apoi

11
acestea să fie distribuite, cu ajutorul platformei Cordova , pe magazinele native de
aplicații ( Android , iOS și Windows ) [10].
Ionic folosește plugin -uri Cordova pentru a putea accesa caracteristicile
sistemelor de operare instalate pe dispozitivele mobile, precum cameră, GPS, bliț etc.
Utilizatorii pot își pot dezvolta aplicațiile iar mai apoi le pot personaliza în funcție de
platforma mob ilă aleasă [11].
Folosin d Angular , Ionic pune la dispoziție un set de componente și metode
personalizate pentru diverse interacțiuni, un scurt exemplu fiind collection repeat ,
componentă ce permite utilizatorului să treacă printr -o listă (scroll) de mii de elemente
fără a afecta în vreun fel performanța.
Ulterior a fost dezvoltat Ionic Creator , un software destinat în special
dezvoltatorilor începători, dar nu numai, ce oferă funcționalitate drag&drop ca un mod
mai simplu de creare a interfețelor grafice. În lucrarea prezentată Ionic Creator nu a
fost folosit.
3.1.1. Angular
Angular (cunoscut și ca Angular 2+ sau Angular v2 and above ) este o
platformă de dezvoltare open -source front -end, ce are la bază limbajul de programare
TypeScript. Aceasta a fost creată de la zero de către aceeași echipă care a dezvoltat
AngularJS . [https://en.wikipedia.org/wiki/Angular_(application_platform) ]
Fiind reproiectată, noua versiune a adus numeroase îmbun ătățiri și a fost mai
eficient optimizată pentru dezvoltarea web, dov edind acest lucru prin performanț a
mărită, așadar, t recerea de la AngularJS la Angular a fost un pas firesc pentru
dezvoltatorii platformei Ionic [1].
Platforma oferă utilizatorului posib ilitatea de a crea aplicații client în HTML și
TypeScript, însăși platforma fiind scrisă în TypeScript. Angular implementează
funcționalități de bază (core) și opționale sub forma unor biblioteci ce vor fi importate
în aplicații în cazul î n care se dorește folosirea lor [1].
În ceea ce privește platforma Ionic , aceasta lucrează după modelul platformei
Angular, așadar conține template -uri, directive și configurații ale proiectului în aceeași
manieră a platformei Angular. De ex emplu, Ionic folosește serviciul $http oferit de
către Angular, însă include și propriile servicii precum $loading sau $actionSheet . Se

12
poate spune că „o aplicație Ioni c este, în esență, o aplicație Angular ” [11]. Următoarea
diagramă exemplifică conceptu l unui proiect Angular (figura 3).

Figura 3: Modul de funcționare al platformei Angular [1]

3.1.2. Cordova
Aplicațiile Ionic sunt construite prin Cordova . Cordova este o platformă ce
permite co nstruirea de aplicații mobile native, indiferent de cerințele platformei.
Concep tul funcționă rii acesteia este ilustrat în figura 4.

Figura 4: Dezvoltarea aplicațiilor pe diverse platforme folosind Cordova [19]

13

Cordova reprezintă un mijloc de „ambalare” a codurilor scrise în trio -ul
HTML/CSS/JavaScript în aplicații ce pot rula atât pe dispozitive mobile cât și desktop,
făcând disponibile în același timp o arhitectură de plugin -uri ce au rol de a accesa
funcționalități nat ive, dincolo de cel e oferite de către un browser web ce folosește
JavaScript. Așadar, platforma Ionic preia structura Cordova [11].
Platformele fișierelor conțin proiectele iOS și Android. Cordova lucrează prin
instalarea de plugin -uri în proiectul aplicației.
3.2. Limbaje de programare
3.2.1. HTML (HyperText Markup Language )
HTML este un limbaj de marcare standard folosit pentru a crea pagini și
aplicații web. „Scopul HTML este mai degrabă prezentarea informațiilor – paragrafe,
fonturi, tabele ș.a.m.d. – decât des crierea se manticii documentului ” [20].
HyperText reprezintă metoda prin care navigarea este efectuată pe web (prin
accesarea de hyperlink -uri ce trimit utilizatorul către altă pagină), iar Markup se referă
la tag -urile ce sunt folosite pentru a da diverse proprietăț i textului respectiv [20].
HTML constă într -o serie de coduri scurte (tag -uri), scrise într -un fișier text, de
către autorul unui website, de exemplu. Fișierul este apoi salvat cu extensia .html și
vizualizat folosind un browser web.
Ionic folosește părți din HTML clasic, însă vine cu adăugări proprii, precum
tag-uri speciale ce fac posibilă folosirea elementelor special concepute pentru
dezvoltare mobilă. De exemplu, dacă vrem să folosim proprietățile oferite de către
Ionic în ceea ce privește un buton HTM L, va trebui să adăugăm directiva ion-button
astfel:

<button ion -button>Button</button>

Platforma Ionic oferă numeroase directive ce pot schimba radical atât design -ul
cât și funcționalitate a oferite de către varianta clasică de HTML.

14
3.2.2. S CSS (Sassy CSS)
Sass (Syntactically Awesome StyleSheets) reprezintă o extensie a CSS -ului ce
adaugă mai multă putere și eleganță limbajului de bază . Acesta face posibilă folosirea
variabilelor, regulilor imbricate, directivelor mixin , precum și multe altele, folosind o
sintaxă 100% compatibilă cu cea a CSS -ului. Limbajul ajută în ținerea stylesheet -urilor
mari bine organizare și în aducerea celor mici în sta diu de rulare cât mai rapid, în
special cu ajutorul bibl iotecii Compass style .
Există două sintaxe disponibile p entru Sass . Cea mai nouă, cunoscută ca SCSS,
reprezintă o extensie a sintaxei CSS. Acest lucru înseamnă că fiecare stylesheet valid în
CSS este valid și în SCSS, acesta având aceeași interpretare. Fișierele ce folosesc
această sintaxă vor avea extensia .scss [15].
În procesul de compilare fișierele .scss vor fi transformate în .css, ca mai apoi să
fie lansate pe platforma dorită . Acest lucru este ilustrat în figura 5.

Figura 5: Workflow -ul SASS [21]
3.2.3. Type Script
Pentru a face mai ușoară munca dezvoltatorului, Ionic folosește TypeScript ca
limbaj principal de programare, în loc de JavaScript.
TypeScript este un limbaj de programare open -source dezvoltat și întreținut de
către Microsoft. Acesta este un superset sint actic al limbajului JavaScript ce
compilează codul în JavaScript clasic . Limbajul poate fi folosit atât pentru dezvoltarea
aplicațiilor pe partea de client cât și pe part ea de server (folosind Node.js) [17].
Compilatorul TypeScript (denumit tsc) este scris în același limbaj. Drept urmare
acesta poate fi compilat în JavaScript clasic și rulat pe orice motor JavaScript. Figura 6
arată pașii procesului scriere cod – compilare – execuție .

15

Figura 6: Scrierea, compilarea și execuția programelor TypeScript [18]
3.3. Baze de date
3.3.1. Alegerea unei baze de date pentru stocarea datelor
Pentru stocarea datelor și informațiilor relevante alegerea firească a fost,
desigur, o bază de date , principalul motiv fiind nevoia de stocare a datelor pe un suport
extern . Un a l doilea motiv a fost reprezentat de nevoia unui SGDB (Sistem de Gestiune
a Bazelor de Date) ce va face posibil lucrul cu anumite date (de exemplu căutarea
rapidă a unui element dintr -o mulțime de dimensiuni relativ mari, modificarea datelor
personale ale utilizatorului etc.), sistemul de gestionare oferind un set de instrumente ce
au fost dezvoltate în acest scop.
O bază de date este o colecție de date utilizată pentru a reprezenta informațiile
de interes pentru un sistem informațional [23].
Prin definiție, datele și informațiile au semnificații diferite, prin faptul că
informația este un rezultat în urma prelucrării datelor [24].
Sistemul de gestiune a bazei da date (SGBD) este un sistem informatic având
rolul de a stoca si prelucra un volum mare de informație (date prelucrate). El este un
pachet de programe specializate ce permite utilizatorilor să comunice cu baza de date și
constituie interfața acestora cu baza de date [24].
Un sistem de gestiune a bazelor de date (SGBD) este un sistem soft ware capabil
[23]:

16
 să gestioneze colecții de date mari, partajate și persistente ;
 să asigure corectitudinea și securitatea datelor ;
 să fie eficient ;
 să producă rezultatul scontat .

Componentele unui SGBD [24]:
 nucleul: realizează funcția de definire și manipulare a bazei de date;
 interfață: asigură comunicarea cu limbajele de programare;
 instrumente: și anume editoare, depanatoare etc.
3.3.2. Alegerea sistemului de gestionare al bazei de date MySQL
După ce am decis crearea unei baze de date, evident urmă torul pas a fost
alegerea unui SGBD care să îmi ofere posibilitatea manipulării cât mai eficiente a
datelor.
Deși aplicația nu necesită stocarea datelor într -o bază de date relațională,
SGBD -ul MySQL a fost o alegere subiectivă, motivul principal fiind lip sa experienței
personale în ceea ce privește folosirea altor sisteme de gestiune, iar această alegere mi –
a permis să îmi concentrez într-o mai mare măsură atenția asupra unor noi concepte
necesare dezvoltării aplicației , precum program area reactive , și pe învățarea uno r noi
limbaje de programare. Interfața sistemului se poate vedea în figura 7.

Figura 7: Interfața MySQL

17

SGBD -ul MySQL [28]:
 este unul dintre cele mai cunoscute SGBD -uri relaționale în regim
OpenSource;
 este mult mai simplu de folosit spre deosebire de alte SGBD -uri
complicate cum ar fi Oracle;
 realizează gestiunea informației structurând -o în tabele între care sunt
stabilite constrângeri de integritate;
 folosește limbajul standard SQL (Structured Query Language);
 este sistem client -server d eoarece sistemul MySql suportă programe
client care au rolul de a asigura interfața cu utilizatorii fiind scrise în
diverse limbaje de programare;
 suportă o varietate de limbaje de programare.

18

Capitolul IV: Proiectarea și dezvoltarea aplicației
4.1. Analiza proiec tării aplicației
4.1.1. Proiectarea b azei de date
Pentru dezvoltarea aplicației am construit o bază de date pentru a stoca
informații despre entitățile specifice aplicației (USERS și FOOD). Deoarece,
momentan, alimentele adăugate sunt stocate doar nativ (pe spațiul de stocare al
dispozitivului), nu a fost necesară cr earea de legături între entităț ile bazei de date. Cele
două entități sunt ilustrate mai jos, în figurile 8 și 9.

Figura 8: Diagrama entității USERS

19

Figura 9: Diagrama entității FOOD

4.1.2. Precizarea structurii mulțimilor candidat
Cele două entități ale bazei de date au fost concepute după cum urmează:
1. Mulțimea entitate USERS păstrează atât datele contului utilizatorului cât
și informații personale despre acesta, după cum urmează:
 id, de tipul int(11) care este și cheia primară, identificând unic
fiecare înregistrare ;
 email , de tipul varchar(50) ;
 password , de tipul varchar(70) ;
 gender , de tipul varchar(10) ;
 birthdate , de tipul date;
 height , de tipul decimal(10,0) ;
 weigh t, de tipul decimal(10,0) ;
 f_goal , de tipul set (cu valorile ’Losing fat’, ’Maintaining weight’
și ’Gaining muscle’) ;
 t_freq , de tipul int(11) ;
 m_freq , de tipul int(11) ;
 so_limit , de tipul int(11) ;
 su_limit , de tipul int(11) ;

20
 sat_limit , de tipul int(11) ;
 cho_limit , de tipul int(11) .

2. Mulțimea entitate FOOD păstrează informații despre diverse alimente,
având următoarea structură:
 id, de tipul int(11) care este și cheia primară, identificând unic
fiecare înregistrare ;
 name , de tipul varchar(50) ;
 type, de tip ul varchar( 14);
 cooking , de tipul varchar(10) ;
 kcal, de tipul int(11) ;
 protein , de tipul decimal(6 ,2);
 carbs , de tipul decimal( 6,2);
 added_sugar , de tipul decimal( 6,2);
 fats, de tipul decimal( 6,2);
 fat_sat , de tipul decimal (6,2);
 sodium , de tipul int(11) ;
 cholesterol , de tipul int(11) .
4.2. Dezvoltarea aplicației
Aplicația ProNutrition este destinată , în mod special, persoanelor care doresc să
urmeze un stil de viață sănătos prin nutriție. Aceasta este comparabilă cu o agendă în
care utilizatorul își noteaz ă alimentele consumate, avantajul clar fiind calculul automat
al kilocaloriilor și al tuturor nutrienților relevanți și posibilitatea verificării progresului
pentru ziua respectivă, incluzând anumite limite asupra unor nutrienți care, prin
depășirea lor, v or avea un impact negativ asupra stării de sănătate a organismului.
4.2.1. Ghidul utilizatorului
În momentul rulării a plicației , utilizatorul este întâmpinat de pagina AUTH .
(figura 10)

21

Figura 10: Pagina de AUTH

Utilizatorul poate alege să își creeze un nou cont sau, dacă acesta are deja un
cont înregistrat, poate trece mai departe dând clic pe butonul LOGIN . În figura 11 este
ilustrată pagina de register.

Figura 11: Pagina REGISTER

Utilizatorul va completa câ mpul email cu o adresă de email și câmpul password
cu o parolă pe care va fi nevoit să o repete în câmpul repeat password . (ca în fig. 12)

22

Figura 12: Pagina REGISTER completată

După completarea câmpurilor, utilizatorul va fi nevoit să dea clic pe buton ul
register . După clic, aplicația va lansa un mesaj scurt care, prin acceptarea lui,
utilizatorul confirmă că va lua în considerare sfaturile unui specialist în domeniu,
înainte de a începe orice activitate fizică sau de a urma orice dietă. Mesajul este
prezentat în figura 13.

Figura 13: Pagina REGISTER cu condiție

Dacă utilizatorul va executa un clic pe butonul cance l, aplicația nu va trimite
date către server, drept urmare crearea unui nou cont nu va putea avea loc. Pentru a
continua, utilizatorul va trebui să revină asupra butonului register . După apăsarea
butonului, î n cazul în care în câmpul repeat password nu a fost introdu să aceeași

23
valoare ca în câmpul password , aplicația va lansa un mesaj de eroare precum arată
figura 14.

Figura 14: Pagina REGISTER cu mesaj de eroare

Dacă procesul de înregistrare s -a îndeplinit cu succes, utilizatorul va fi trimis
automat către pagina PROFILE , unde va fi nevoit să introducă un set de date personale
necesare anumitor calcule efectuate de către aplicație. Figur a 15 prezintă pagina
PROFILE imediat după înregistrare.

24

Figura 15: Pagina PROFILE

În cazul în care utilizatorul are deja un cont creat, acesta va face clic pe butonul
login de pe pagina AUTH (figura 10). Acestuia i se va prezenta un formular în care va
trebui să introducă o adresă de email și parola contului respectiv, după cum arată figura
16.

25

Figura 16: Pagina AUTH cu formular pentru login

În cazul în care utilizatorul va introduce greșit informaț iile din cele două
câmpuri, după apăsarea butonului login acesta va fi întâmpinat de un mesaj de eroare,
ilustrat mai jos în figura 17.

Figura 17: Pagina AUTH cu mesaj de eroare

Dacă procesul de logare a fost efectuat cu succes, aplicația va duce utili zatorul
în pagina de profil, scriind automat câmpurile (presupunând că acestea au fost
completate anterior de către utilizator, după procesul de înregistrare) prin copierea
acestora direct din baza de date, precum se poate vedea din figura 18.

26

Figura 18: Pagina PROFILE completată

Utilizatorul poate alege să nu completeze rubrica Daily Nutrient Limits , iar în
acest caz, aplicația va calcula și va scrie câmpurile respective în mod automat, în
funcție de informațiile completate anterior. Celelalte câmpuri sunt obligatorii, iar
omiterea unuia sau mai multe dintre acestea va prezenta un mesaj de eroare ce nu va
face posibilă continuarea în aplicație până la completarea lor, după cum arată figura 19.

27

Figura 19: Pagina PROFILE cu mesaj de eroare

După ce câm purile au fost copiate din baza de date, sau după ce acestea au fost
completate/modificate de către utilizator, prin apăsarea butonului SAVE , aplicația va
salva datele din pagina PROFILE și va trimite utilizatorul către pagina STATUS . (figura
20).

Figur a 20: Pagina STATUS la prima rulare

28

La acest moment pagina STATUS nu va fi completată deoarece principalele date
folosite de către aceasta vor fi importate din pagina COUNTER , după ce utilizatorul va
fi adăugat un aliment. Figura 21 prezintă pagina COUNTE R la prima rulare.

Figura 21: Pagina COUNTER la prima rulare

Pentru a menține totul cât mai simplu, această pagină conține numai două
elemente. Primul element este reprez entat de o bară de căutare prin care utilizatorul va
putea accesa baza de date, că utând un aliment dorit , după cum este prezentat în figura
22.

Figura 22: Funcționlitatea search de pe pagina COUNTER

În momentul în care utiliza torul a găsit alimentul dorit va trebui să dea clic pe
acesta și va fi întâmpinat de un formular care solicită completarea cantității alimentului
consumat, în grame, ca în figura 23.

29

Figura 23: Pagina COUNTER cu fomular pentru cantitatea alimentului

După introducerea cantității dorite se va apăsa butonul ADD iar alimentul va fi
adăugat într -o listă și salvat pe dispozitiv, ca în figura 24.

Figura 24: Pagina COUNTER cu lista de alimente consumate

În momentul adăugării unui aliment în listă, aplicația va actualiza automat
pagina STATUS. Fi ecare aliment va prezenta ora la care a fost adăugat. Acest luc ru
este ilustrat în figur a 25.

30

Figura 25: Pagina STATUS actualizată

Pentru a afla mai multe detalii despre un aliment adăugat, pentru modificarea
cantității deja introduse sau pentru ștergerea alimentului respectiv din listă, se va da
clic pe alimentul dorit din pagina COUNTER , fapt ce va deschide o pagină nouă prin
care v or fi posibile lucrurile anterior menționate, după cum arată figura 26.

31

Figura 26: Pagina FOOD -INFO

Cantitatea poate fi modificată de către utilizator, fapt care va recalcula
kilocaloriile și nutrienții alimentului în cauză (figura 27), actualizând tot odată lista de
alimente și pagina COUNTER , precum în figura 28.

32

Figura 27: Pagina FOOD -INFO actualizată

La apăsarea butonului de confirmare () lista de alimente din pagina
COUNTER va fi și ea actualizată. Acest lucru se poate vedea în figura 28.

Figura 28: Pagina COUNTER actualizată

În același timp se va actualiza și pagina STATUS cu noile date, ca în figura 29.

33

Figura 29: Pagina STATUS actualizată

Tot în pagina FOOD -INFO utilizatorul poate opta pentru eliminarea alimentului
afișat pe pagină dând clic pe butonul REMOVE FOOD , fapt ce va șterge alimentul în
cauză din lista de alimente . Lista va fi actualizată, p recum este prezentat în figura 30 ,
urmând ca mai apoi să se actu alizeze și pagina STATUS .

34

Figura 30: Pagina COUNTER cu lista actualizată

Ultima pagina (pagina MEAL ) a fost concepută pentru utilizatorii ce doresc un
exemplu de dietă ca un punct de start în ceea ce privește inițierea în nutriție.
Utilizatorul va da c lic pe butonul GENERATE MEAL iar aplicația va afișa automat un
plan alimentar de scurtă durată, ținând cont de preferințele utilizatorului (și anume de
datele introduse în pagina PROFILE ). Acest lucru poate fi văzut în figura 31.

Figura 31: Pagina MEAL

Pentru a accesa în orice moment pagina PROFILE , sau pentru a părăsi aplicația,
utilizatorul poate da clic pe butonul de meniu ( ) situat în partea de sus a ecranului,
în colțul din dreapta, dacă acesta se află în oricare dintre cele trei pagini principale ale

35
aplicației ( STATUS , COUNTER , MEAL ). După clic, pe ecran se va afișa un meniu cu
opțiunile PROFILE , LOGOUT și CLOSE MENU , după cum este ilustrat în figura 32.

Figura 32. Meniul aplicației

Din acest meniu, utilizatorul poate accesa pagina de profil pentru a analiza sau
efectua, dacă este cazul, modificări ale datelor deja introduse. Butonul Logout va duce
utilizatorul pe prima pagină (și anume pagina AUTH ), acesta fiind nevoit să introducă
datele contului și să apese din nou butonul login în cazul în care dorește să folosească
în continuare aplicația . În final, butonul Close Menu va permite utilizatorului să închidă
meniul fără a se modifica nimic atât în frontend -ul cât și în backend -ul aplicației.
4.2.2. Ghidul dezvoltatorului
Pentru d ezvoltarea aplicației sunt necesare următoarele programe software:
 WampServer (Windows, Apache, MySQL, PHP), pentru crearea bazei de
date MySQL.
 Node.js , ce va permite recunoașterea liniei de comand ă a comenzilor
npm.
 Platforma Ionic Framework ce va fi instalată folosind comanda npm
install -g ionic .
 Instalarea plugin -ului Cordova NativeStorage pentru a permite accesul
aplicației la mediul de sto care al dispozitivelor mobile.
 Instalarea pachetului Chart.js pentru a fa ce posibilă afișarea și folosirea
de grafice de tip doughnut .
Pentru crearea unei noi aplicați i va fi rulată comanda ionic start ionic_app
tabs, unde ionic_app reprezintă numele, iar tabs modelul aplicației.

36
Fișierele de bază ale proiectului se află în folderul src/app . După compilare,
primul fișier rulat este app.component.ts . [11] Acesta încarcă principalul template
HTML al aplicației, și anume app.html prin:

@Component({
templateUrl: 'app.html'
})

al cărui cod sursă este următorul:

<ion-menu side="right" [content]="mycontent">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion -title>
</ion-toolbar>
</ion-header>

<ion-content>
<ion-list>
<button ion -item menuClose (click)="profile()">
Profile
</button>
<button ion -item menuClose (click)="logout()">
Logout
</button>
<button ion -item menuClose>Close Menu</button>
</ion-list>
</ion-content>
</ion-menu>

Această pagină are rolul de a constr ui interfața meniului prezentat anterior. Apoi
va fi declarat controller -ul meniului prin @ViewChild(Nav) nav: Nav; , iar pagina
AUTH va fi setată ca pagină principală prin rootPage:any = AuthPage; .

37

export class MyApp {
@ViewChild(Nav) nav: Nav;
rootPage:any = AuthPage;

Se vor declara două variabile ( profilePage și authPage ) ce vor reține valorile
paginilor PROFILE și AUTH pentru a putea fi accesate din meniu . În constructor vor fi
mai apoi injectate modulele necesare rulării aplicației, iar funcția platform.ready() va
verifica dacă programul a rulat fără probleme. În caz afirmativ, aceasta va seta stilul
Default pentru bara de stare și va ascunde pagina de loading .

private profilePage = ProfilePage;
private authPage = AuthPage;

constructor(
platform: Platform,
statusBar: StatusBar,
splashScreen: SplashScreen,
public storage: NativeStorage) {

platform.ready().then(() => {
statusBar.styleDefault();
splashScreen.hide();
});
}

În ultimă fază vor fi declarate două funcții pentru butoanele PROFILE și
LOGOUT ale meniului, și anume funcția profile() , ce are rolul de a încărca (push)
pagina PROFILE în stiva controller -ului navigației , după apelare , și funcția logout() ,
care în momentul apelării va șterge toate datele de pe dispozitivul de stocare al
telefonului mobil și va seta ca rootPage pagina AUTH , ce va prezenta utilizatorului
opțiunile de Login și Register .
profile() {

38
this.nav.push(ProfilePage);
}

logout() {
this.storage.clear();
this.nav.setRoot(AuthPage);
}

Cea mai importantă pagină a aplicației este app.module.ts , pagină în care se vor
impor ta toate modulele, plugin -urile și paginile folosite, după cum urmează:

import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform –
browser';
import { IonicApp, I onicModule, IonicErrorHandler }
from 'ionic -angular';
import { MyApp } from './app.component';
import { HttpModule } from '@angular/http';
import { Native Storage } from '@ionic -native/native -sto
rage'

De asemenea se vor importa și toate paginile folosite (cele create de către
dezvoltator):

import { CounterPage } from '../pages/counter/counter';
import { FoodInfoPage } from '../pages/food -info/food –
info';
import { MealPage } from '../pages/meal/meal';
import { StatusPage } from '../pages/status/status';
import { TabsPage } from '../pages/tabs/tabs';
import { ProfilePage } from '../pages/profile/profile';
import { AuthPage } from '../pages/auth/auth';
import {RegisterPage} from '../pages/register/register';

39

Apoi vor fi importate bara de stare și pagina de loading .

import { StatusBar } from '@ionic -native/status -bar';
import { SplashScreen } from '@ionic -native/splash –
screen';

În continuare se vor declara toate paginile create de către dezvoltator, bara de
stare, modulul de loading , plugin -urile native ( Cordova ) folosite și, la final, va fi
exportată clasa principală a aplicației, și anume AppModule .

@NgModule({
declarations: [
MyApp,
CounterPage,
FoodInfoPage,
MealPage,
StatusPage,
TabsPage,
ProfilePage,
AuthPage,
RegisterPage
],
imports: [
BrowserModule,
HttpModule,
IonicModule.forRoot(MyApp),
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
CounterPage,
FoodInfoPage,
MealPage,

40
StatusPage,
TabsPage,
ProfilePage,
AuthPage,
RegisterPage
],
providers: [
StatusBar,
SplashScreen,
NativeStorage,
{provide: ErrorHandler,
useClass: IonicErrorHandler}
]
})
export class AppModule {}

Fișierul main.ts va importa clasa AppModule , anterior menționată.

import { platformBrowserDynamic } from '@angular/platfo
rm-browser -dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

Paginile create de către dezvoltator se vor găsi în folderul src/pages . Prima
pagină la care utilizatorul va avea acces este pagina AUTH. Aceasta încarcă un
template HTML, scris în auth.html , după cum urmează:

<ion-content padding>

<h5 ion -text color="dark" text -center>Welcome!
</h5>
<div id="authButtons">

41
<button ion -button round small block
(click)="openLogin()">Login</button>
<button ion -button round small block
(click)="openRegister()">Register< /button>
</div>

</ion-content>

Pagina prezintă două butoane, și anume login și register . În momentul apăsării
butonului login (figura 33), se va apela funcția openLogin() , care poate fi găsită în
fișierul auth.ts, și care va prezenta utilizatorului un alert ce va cere introducerea datelor
email și password .

Figura 33: Butonul login

După introducerea datelor și apăsarea butonului login va fi apelată funcția
getUserData() . În cazul în care datele introduse de către utilizator sunt greșite, pe
ecran va a părea un alt alert ce va anunța utilizatorul des pre acest lucru, iar în caz
contrar se va efectua prima conexiune cu baza de date , prin http.post() și vor fi
preluate datele utilizatorului din contul respectiv, urmând a fi stocate local pe
dispozitivul mobil prin funcția storage.setItem() . Ca ultim pas, controller -ul navigației
va seta ca rootPage pagina PROFILE , prin setRoot( Profile Page) .

Funcția openLogin() :
openLogin() {
let alert = this.alertCtrl.create({
title: 'Login',
inputs: [
{
name: 'email',
placeholder: 'Email',
type: 'email'

42
},
{
name: 'password',
placeholder: 'Password',
type: 'password'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
}
},
{
text: 'Login',
handler: data => {
this.email = data['email'];
this.password = data['password'];
this.getUserData();
}
}
]
});
alert.present();
}

Funcția getUserData() :
getUserData() {
var headers = new Headers();
headers.append("Accept","application/json");
headers.append("Content –
Type","application/json");

43
let postParams = {
email: this.em ail,
password: this.password };
let options = new Requ estOptions({
headers: headers});
let url = 'http://url';

this.http.post(url, postParams, options)
.subscribe(data => {
this.user_data = data['_body'];

if(this.user_data == 'Wrong data') {
let alert = this.alertCtrl.creat e({
subTitle: "Wrong username/password",
buttons: ['OK']
});
alert.present();
} else {
this.storage.setItem(
'user_profile',
this.user_data);
this.navCtrl.setRoot( Profile Page);
}
}
}

În cazul în care utilizatorul dorește să creeze un nou cont, acesta poate da clic pe
butonul register (figura 34), iar funcția openRegister() va fi apelată.

Figura 34: Butonul register

Funcția openRegister() :

44
openRegister() {
this.navCtrl.push(RegisterPage);
}

În momentul apelării ei se va deschide pagina REGISTER după cum urmează:
<ion-header>
. . .

<ion-content padding>
<ion-list>
<ion-item>
<ion-label floating>Email</ion -label>
<ion-input type="email" [(ngModel)]="email"></ion –
input>
</ion-item>

<ion-item>
<ion-label floating>Password</ion -label>
<ion-input type="password" [(ngModel)]="password"><
/ion-input>
</ion-item>

<ion-item>
<ion-label floating>Repeat password</ion -label>
<ion-input type="password" [(ngModel)]="password2"><
/ion-input>
</ion-item>
</ion-list>

<div padding>
<button ion -button round block (click)="conditions()"
>Register</button>
</div>

45
</ion-content>

După completarea câmpurilor respective și apăsarea butonului register (figura
35), după apariția mesajului de confirmare (figura 13), va fi apelată funcția
registerAccount() din fișierul register.ts .

Figura 35: Butonul REGISTER pentru confirmare

registerAccount() {

var headers = new Headers(); //url
headers.append("Accept","application/json");
headers.append("Content -Type","application/json");
let postParams =
{
type: 'register',
email: this.email,
password: this.password
};
let options = new RequestOptions({headers: headers});
let url = 'http://url/;

this.http.post(url, postParams, options).subscribe(
data => {
if(data['_body'] == 'Succes') {
this.register_data = data['_body'];
this.navCtrl.setRoot(Profile Page);
} else {
let alert = this.alertCtrl.create({
message: 'Could not connect to server',
buttons: [
{

46
text: 'Ok',
handler: () => {
}
}
]
});
alert.present();
}
}

După procesul de înregistrare, următoarea pagină deschisă va fi pagina
PROFILE , iar utilizatorul va fi nevoit să completeze câmpurile paginii. Codul HTML
(parțial) al paginii PROFILE :
. . .

<ion-item (click) ="genderRadio()">
<ion-label color="primary">Gender: <p float -right>
{{gender}} </p> </ion -label>
</ion-item>

<ion-item>
<ion-label color="primary">Date of birth:</ion –
label>
<ion-datetime displayFormat="YYYY -MM-DD"
[(ngModel)]="birthdate" (ionChange)="ge tAge()"></ion –
datetime>
</ion-item>

<ion-item>
<ion-label color="primary">Height:</ion -label>
<ion-input type="number" placeholder="(cm)"
[(ngModel)]="height"></ion -input>
</ion-item>

47
<ion-item>
<ion-label color="primary">Weight:</ion -label>
<ion-input type="number" placeholder="(kg)"
[(ngModel)]="weight"></ion -input>
</ion-item>

. . .

<ion-item>
<ion-label color="primary">Cholesterol limit:</ion –
label>
<ion-input type="number" placeholder="(mg)"
[(ngModel)]="cholesterol_limit"></ion -input>
</ion-item>

După completarea câmpurilor paginii și apăsarea butonului SAVE va fi apelată
funcția saveProfile() .

saveProfile() {
if(this.gender == null ||
this.birthdate == null ||
this.height == null ||
this.weight == null ||
this.goal == null ||
this.training_frequency == null ||
this.meal_frequency == null) {

this.updateProfile();

let toast = this.toastCtrl.create({
message: 'Profile updated.',
duration: 1500
});
toast.present();

48
this.navCtrl.setRoot(TabsPage);
} else {
this.nullCheck();
}
}

Funcția saveProfile() apelează la rândul ei funcția nullCheck() , dacă
utilizatorul lasă unul sau mai multe câmpuri necompletate, sau funcția updateProfile()
în caz contrar.

Funcția nullCheck() :

nullCheck() {

let alert = this.alertCtrl.create({
message: 'Please fill in all the empty fields.',
buttons: [
{
text: 'Ok',
handler: () => {
console.log('Ok clicked');
}
}
]
});
alert.present();
}

Funcția updateProfile() :

updateProfile() {

var headers = new Headers();

49
headers.append("Accept","application/json");
headers.append("Content -Type","application/json");
let postParams =
{
type: 'save',
email: this. email,
gender: this.gender,
birthdate: this.birthdate,
height: this.height,
weight: this.weight,
f_goal: this.goal,
t_freq: this.training_frequency,
m_freq: this.meal_frequency,
so_limit: this.sodium_limit,
su_limit: this.added_sugar_limit,
sat_limit: this.saturated_limit,
cho_limit: this.cholesterol_limit
};

let options = new RequestOptions({headers: headers});
let url = 'http://url';

this.http.post(url, postParams, options).subscribe
(data => {
if(data['_body'] == 'Succes') {
this.storage.setItem('user_profile',JSON.string
ify(postParams))
this.importProfileData();
});
}

Ultima funcție apelată este importProfileData() , ce are rolul de a actualiza
variabilele locale cu noile valori ce au fost scrise în baza de date.

50
importProfileData() {
this.storage.getItem(' user_profile').then((data) => {
this.profile_data = JSON.parse(data);

this.email = this.profile_data['email'];
this.gender = this.profile_data['gender'];
this.birthdate = this.profile_data['birthdate'];
this.height = this.profile_data['height'];
this.weight = this.profile_data['weight'];
this.goal = this.profile_data['f_goal'];
this.training_frequency=this.profile_data['t_freq'];
this.meal_frequency = this.profile_data['m_freq'];

if(this.profile_data['so_limit'] == null ||
this.profile_data['so_limit'] == 0) {
this.sodium_limit = 2000;
} else {
this.sodium_limit = this.profile_data['so_limit']; }

if(this.profile_data['su_limit'] == null ||
this.profile_data['su_limit'] == 0) {
this.added_sugar_limit = 25;
} else {
this.added_sugar_limit=this.profile_data['su_limit'];}

if(this.profile_data['sat_limit'] == null ||
this.profil e_data['sat_limit'] == 0) {
this.saturated_limit = Math.floor((this.kcal_bu
dget * 0.05) / 9);
} else {
this.saturated_limit=this.profile_data['sat_limit'];}

if(this.profile_data['cho_limit'] == null ||
this.profile_data['cho_limit'] == 0) {

51
this.cholesterol_limit = Math.floor(this.kcal_bu
dget * 0.1);
} else {
this.cholesterol_limit = his.profile_data['cho_lim
it'];}
});
}

După acest proces , utilizatorul va fi trimis în pagina STATUS unde un set de
date va fi preluat din pagina PROFILE prin funcția importFromProfile() .

importFromProfile() {
this.storage.getItem('kcal_budget').then((data) => {
this.kcal_budget = Math.round(data);
});
this.storage.getItem('sodium_limit') .then((data)=> {
this.sodium_limit = parseFloat(data);
});
this.storage.getItem('added_sugar_limit').then((data)
=> {
this.added_sugar_limit = parseFloat(data);
});
this.storage.getItem('saturated_limit').then((data)
=> {
this.saturated_limit = parseFloat(data);
});
this.storage.getItem('cholesterol_limit').then((data)
=> {
this.cholesterol_limit = parseFloat(data);
});
}

Pentru a adăuga un aliment consumat în lista de alimente, acesta va trebui să
intre în pagina COUNTER unde va căuta prin bara de search alimentul dorit.

52

Bara de search:
<ion-searchbar
[(ngModel)]="searchInput"
(ionInput)="getData($event)"
(ionCancel )="onCancel($event)">
</ion-searchbar>

Utilizatorul va face clic pe un aliment, iar funcția setFoodQuantity() va fi
apelată.

setFoodQuantity(item) {
const prompt = this.alertCtrl.create({
title: 'Add food',
inputs: [
{
name: 'quan tity',
placeholder: 'Enter the weight in grams',
type: 'number'
},
],
buttons: [
{
text: 'Cancel',
handler: data => {
console.log('Cancel clicked');
}
},
{
text: 'Add',
handler: data => {
if (data.quantity == '' || data.quantity ==
'0') {
let alert = this.alertCtrl.create({

53
subTitle: "Please enter a quantity",
buttons: ['OK']
});
alert.present();
} else {
this.quan tity = parseInt(data.quantity);
this.multiplier = parseInt(data.quantity)
/ 100;
this.addFoodToList(item);
}
}
}
]
});
prompt.present();
this.searchInput = '';
}

După introducerea cantității dorite va fi apelată f uncția addFoodToList(item)
ce va salva (push) alimentul respectiv într -un array salvat în spațiul de stocare local :

addFoodToList(item) {
let now = new Date();
let date = now.getHours()+':'+now.getMinutes();
item.time = date;
item.quantity = this.quantity;
item.multiplier = this.multiplier

this.food.push(item);
this.storage.setItem('food', this.food);

this.addFoodToLog();
}

54
Funcția addFoodToList(item) se încheie prin apelarea funcției
addFoodToLog() , ce are rolul de a adăuga valorile ultimului aliment în variabilele
corespunzătoare, după cum urmează:
addFoodToLog() {
let last_added = this.food[this.food.length – 1];

this.counter_kcal += (parseFloat(last_added['kcal'])
* this.multiplier) ;

this.counter_fats += (parseFloat(last_added['fats'])
* this.multiplier);

this.counter_carbs +=
(parseFloat(last_added['ca rbs']) * this.multiplier);

this.counter_protein +=
(parseFloat(last_added['protein']) * this.multiplier);

this.counter_sodium +=
(parseFloat(last_added['sodium']) * this.multiplier);

this.counter_added_sugar +=
(parseF loat(last_added['added_sugar'])* this.multiplier)
;
this.counter_saturated +=
(parseFloat(last_added['fat_sat']) * this.multiplier);

this.counter_cholester ol +=
(parseF loat(last_added['cholesterol'])*this.multiplier)
;
this.logToStorage();
}

55
În ultimă fază se va apela funcția logToStorage() , ce are rolul de a salva pe
spațiul de stocare al dispozitivului valorile alimentelor adăugate.

logToStorage() {

this.storage.setItem('counter_kcal',this.counter_kcal);

this.storage.setItem('counter_fats',this.c ounter_fats);

this.storage.setItem('counter_carbs',this.counter_carbs
);
this.storage.setItem('counter_protein',this.counter_pro
tein);

this.storage.setItem('counter_sodium',this.counter_sodi
um);

this.storage.setItem('counter_added_sugar',this.counter
_added_sugar);

this.storage.setItem('counter_saturated',this.counter_s
aturated);

this.storage.setItem('counter_cholesterol',this.counter
_cholesterol);
}

Apoi pagina STATUS va fi actualizată prin funcția importFromCounter() , ce ia
valorile arătate anterior din spațiul de stocare local .

importFromCounter() {
this.storage.getItem('counter_kcal').then((data) =>
{

56
this.kcal = Math.round(data);
});

this.storage.getItem('counter_fat s').then((data) =>
{
this.fats = Math.round(data);
});
this.storage.getItem('counter_carbs').then((data)
=> {
this.carbs = Math.round(data);
});
this.storage.getItem('counter_protein').then((data)
=> {
this.protein = Math. round(data);
});
this.storage.getItem('counter_sodium').then((data)
=> {
this.sodium = parseFloat(data.toFixed(2));
});
this.storage.getItem('counter_added_sugar').then((data)
=> {
this.added_sugar = parseFloat(data.toFixed(2));
});
this.storage.getItem('counter_saturated').then((data)
=> {
this.saturated = parseFloat(data.toFixed(2));
});
this.storage.getItem('counter_cholesterol').then((data)
=> {
this.cholesterol = parseFloat(data.toFixed(2));
});
}

57
Pentru a genera un meniu ce, odată consumat, va satisface nevoile nutriționale
ale utilizatorului la o masă , acesta va trebui să facă clic pe butonul GENERATE MEAL
(figura 36) din pagina MEAL . Codul generatorului nu a fost inclus din motive de
protejare a d repturilor de autor.

Figura 36: Butonul GENERATE MEAL din pagina MEAL

58

Capitolul V: Concluzii
La începutul demarării proiectului, experiența mea în dezvoltarea aplicațiilor
mobile consta în trei săptămâni de participare la un stagiu de practică în care am
încercat, prin propriile forțe (învățând în mediu online , din cursuri și tutoriale), să
dezvolt o aplicație Android, folosind limbajul de programare standard al platformei , și
anume JAVA , în programul software oferit de Google, Android Studio .
Ținând cont de faptul că am ales să folosesc un cu totul alt set de instrumente
pentru realizarea acestui proiect, pot spune că nivelul de experiență în acest sens a fost
aproape zero. Însă prin munca depusă , după o perioadă îndelungată de studiu, am reușit
să ating multe din obiectivele propuse. Desigur că acestea nu au putut fi atinse în
totalitate și pot spune că, după acest timp, abia am descoperit suprafața conceptului de
programare pentru dispozitivele mobile. Cred însă că pe viitor, după un nivel
substan țial de efo rt depus , voi putea să înțeleg mai bine părți din acest vast domeniu și
să dezvolt aplicații din ce în ce mai complexe .
În dezvoltarea aplicației ProNutrition am încercat să mențin totul cât mai
simplu, fără a adăuga elem ente ce pot afecta perfo rmanța sau deranja utilizatorul în
timpul folosirii acesteia. Am considerat că, în acest mod, utilizatorul va putea ajunge
cât mai repede la rezultatul dorit și se va putea concentra mai eficient pe o anume
sarcină , așadar aș putea spune că principala caracteristică a aplicați ei ProNutrition este
simplitatea.

Contribuții proprii în dezvoltarea și programarea aplicației:
 Securizarea aplicației : a fost realizat ă prin procesul de înregistrare/logare
ce permite accesul diferențiat la aplicație, procesul de login având loc cu
succes doar în urma introducerii corecte a unei parole ce se află în baza
de date (sub formă criptată);

59
 Stocarea datelor utilizatorilor într -o bază de date prin formularul paginii
PROFILE , printr -o funcție de face legătura cu baza de date în momentul
apăsării butonului SAVE ;
 Realizarea modificărilor datelor deja existente ale utilizatorului în baza
de date prin aceeași metodă menționată anterior (apăsare a butonul ui
SAVE al paginii PROFILE );
 Efectuarea de calcule relevante actualiz ării în mod corect a stării actuale
a jurnalului virtual și pentru afișarea corectă a acesteia ;
 Oferirea unei posibilități simple de citire a detaliilor unui aliment
adăugat, de modificare a cantității aces tuia în cazul introducerii greșite,
sau de ștergere din lista de alimente ;
 Dezvoltarea unui Meal Planner simplu .

Desigur că pe parcursul realizării lucrării au fost întâmpinate dificultăți în ceea
ce privește programarea propriu -zisă a aplicației, precum :
 Conexiunea aplicației la baza de date (dezvoltată în MySQL) atât pentru
procesul de înregist rare și logare cât și pentru procesul de căutare în
tabelul de alimente ;
 Crearea unui formular pentru modificarea sau ștergerea unui aliment deja
adăugat în spațiul de stocare local ;
 Actualizarea corectă a paginilor STATUS și COUNTER după adăugarea,
modificarea sau ștergerea unui aliment și după modificarea câmpurilor
din pagina PROFILE ;
 Dezvoltarea unui Meal Planner în funcție de anumite informații introduse
de către utilizator .

Printre p lanuri le de viitor și ideile de îmbunătățire se numără :
 Trimiterea unui mail de confirmare după ce utilizatorul a creat un nou
cont;
 Trecerea bazei de date din MySQL într -o bază de date NoSQL, ca
Google Firebase sau MongoDB (deoarece aplicația nu se folosește de

60
partea relațională, iar aceste baze de date sunt mai bine optimizate pentru
aplicațiile mobile);
 Luarea în considerare a întregului spectru de micronutrienți (vitamine și
minerale) ;
 Înregistrarea mai multor date în cee a ce privește nutriția ( de exemplu
dieta urmată de către utilizator – omnivor ă, vegetarian ă, vegan ă etc – și
posibilele intoleranțe ale acestuia la diverse tipuri de substanțe , precum
lactoza sau glutenul) ;
 Optimizarea Meal Planner -ului pentru a oferi rezu ltate cât mai precise în
funcție de cerințele utilizatorului ;
 Posibilitatea scanării codului de bare pentru introducerea mai simplă și
mai rapidă al unui aliment în jurnalul virtual .

O parte a aplicației pe care mi -am propus să o dezvolt , dar nu am reușit, este
aceea a măsurării progresului utilizatorului, salvarea acestuia în baza de date și oferirea
posibilității de a verifica progresul respectiv pe o anumită perioadă de timp
(săptămână/lună/an) . La momentul actual aceste date sunt stocate temporar , doar pe
spațiul de stocare al dispozitivului mobil, acestea fiind înlocuite în fiecare zi. Chiar și
după dezvoltarea acestui modul, aplicația va funcționa în același mod, diferența fiind
doar una vizuală.
Un ultim aspect ce trebuie luat în considerare în momentul folosirii aplicației, în
ceea ce privește nu programarea din spatele aplicației, ci mentalitatea utilizatorului,
este reprezentat de faptul că persoana din spatele dispozitivului va fi în proporție de
100% responsabilă în ceea ce privește îndepli nirea obiectivelor impuse și că, indiferent
de tehnologiile folosite și de complexitatea lor, acestea nu vor avea niciun cuvânt de
spus, în final, în așa -zisa luptă a utilizatorului cu el însuși.

61

Bibliografie
1. ***, Angular – Architecture overview , https://angular.io/guide/architecture ,
Accesat : 14.06.2018
2. ***, How Much Cholesterol Should I Be Having Each Day to Be Healthy?
https://w ww.healthline.com/health/high -cholesterol/rda , Accesat: 03.06.2018
3. ***, How Much Is Too Much? http://sugarscience.ucsf.edu/the -growing -concern –
of-overconsumption.html , Accesat: 03.06.2018
4. ***, How Much Sodium Should I Eat Per Day?,
https://sodiumbreakup.heart.org/how_much_sodium_should_i_eat?utm_source=S
RI&utm_medium=HeartOrg&utm_term=Website&utm_content=SodiumAndSalt
&utm_campaign=SodiumBreakup , Accesat: 03.06.2018
5. ***, How to scan barcodes, https://help.loseit.com/hc/en –
us/articles/115006017087 -How -to-scan-barcodes , Accesat: 05.06.2018
6. ***, How LoseIt! works, https://loseit.com/how -it-works/ , Accesa t: 05.06.2018
7. ***, How do I use the barcode scanner to log foods,
https://myfitnesspal.desk.com/customer/portal/articles/13640 -how-do-i-use-the-
barcode -scanner -to-log-foods , Accesat: 05.06.2018
8. ***, https://www.loseit.com/about/ , Accesat: 05.06.2018
9. ***, https://www.myfitnesspal.com/ , Accesat: 05.06.20 18
10. ***, Ionic SDK https://en.wikipedia.org/wiki/Ionic_(mobile_app_framework) ,
Accesat: 04.06.2018
11. ***, Ionic Structure https://ionicframework.com/docs/v1/concepts/structure.html ,
Accesat: 04.06.2018
12. ***, Lose It!, https://play .google.com/store/apps/details?id=com.fitnow.loseit ,
Accesat: 05.06.2018
13. ***, Mobile App, https://en.wikipedia.org/wiki/Mobile_app , Accesat: 02.06.2018

62
14. ***,MyFitnessPal, https://play.google.com/store/apps/details?id=com.myfitnesspal.
android , Accesat: 0 5.06.2018
15. ***, Sass (Syntactically Awesome StyleSheets) https://sass –
lang.com/documentation/file.SASS_REFERENCE.html , Accesat: 21.06.2018
16. ***, Saturated Fats https://healthyforgood.heart.org/eat -smart/articles/saturated –
fats, Accesat: 03.06.2018
17. ***, TypeScript – JavaScript that scales, https://www.typescriptlang.org/ , Accesat:
21.06.2018
18. ***, TypeScript Workflow, http://angularfirst.com/typescript -systemjs -workflow –
diagram/ , Accesat: 21.06.2018
19. ***, What is Cordova and how does it work?,
https://blogs.sap.com/2014/07/27/what -is-cordova -and-how-does-it-work/ ,
Accesat: 21.06.2018
20. ***, What is HTML?, http://www.yourhtmlsource.com/starthere/what ishtml.html ,
Accesat: 21.06.2018
21. ***, What is Sass?, http://www.spiceforms.com/blog/frontend -development -sass-
and-compass -introduction/ , Accesat: 21.06.2018
22. Beth A. Lewis, Melissa A. Na politano, Matthew P. Buman, David M. Williams,
Claudio R. Nigg , Future directions in physical activity intervention research:
expanding our focus to sedentary behaviors, technology, and dissemination, First
Online: 08 October 20 16
23. Florin -Cătălin Brăescu, Facultatea de Automatica si Calculatoare, Iasi ,
http://bd.ac.tuiasi.ro/Doc/curs/Curs_01.pdf , Accesat: 22.06.2018
24. Georgiana Andreescu, Curs: Baze de date (BD) sistem de gesti une al bazelor de
date (SGBD), 2012
25. Kris Gunnars, BSc, 2017, The Salt Myth – How Much Sodium Should You Eat Per
Day?, https://www.healthline.com/nutrition/how -much -sodium -per-day, Accesat:
03.06.2018
26. Ludwig, Sean. December 5, 2012. venturebeat.com, study: "Mobile app usage
grows 35%, TV & web not so much"].

63
27. Marcano -Belisario, José S.; Gupta, Ajay K.; O'Donoghue, John; Morrison, Cecily;
Car, Josip (1 January 2016). "Tablet computers for implementing NICE antenatal
mental health guidelines: protocol of a feasibility study"
28. Mark C. Chan, Steven W. Griffith, Anthony F. Iasi, JAVA 1001 secrete pentru
programatori, Editura Teora, București, 2001
29. Ventola, CL (2014). "Mobile devices and apps for health care professionals: uses
and benefits"

64

Anexă coduri sursă
app.html
<ion-menu side="right" [content]="mycontent">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion -title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button ion -item menuClose (click)="profile()">
Profile
</button>
<button ion -item menuClose (click)="logout()">
Logout
</button>
<button ion -item menuClose>
Close Menu
</button>
</ion-list>
</ion-content>
</ion-menu>

app.module .ts
import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform –
browser';

65
import { IonicApp, IonicModule, IonicErrorHandler }
from 'ionic -angular';
import { MyA pp } from './app.component';
import { Http, Headers, RequestOptions, HttpModule }
from '@angular/http';
import { NativeStorage } from '@ionic -native/native –
storage'

import { CounterPage } from '../pages/counter/counter';
import { FoodInfoPage } from '../p ages/food -info/food –
info';

import { MealPage } from '../pages/meal/meal';
import { StatusPage } from '../pages/status/status';
import { TabsPage } from '../pages/tabs/tabs';
import { ProfilePage } from '../pages/profile/profile';
import { AuthPage } from '../pages/auth/auth';
import { RegisterPage } from
'../pages/register/register';

import { StatusBar } from '@ionic -native/status -bar';
import { SplashScreen } from '@ionic -native/splash –
screen';

@NgModule({
declarations: [
MyApp,
CounterPage,
FoodInfoPage,
MealPage,
StatusPage,
TabsPage,
ProfilePage,
AuthPage,

66
RegisterPage
],
imports: [
BrowserModule,
HttpModule,
IonicModule.forRoot(MyApp),
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
CounterPage,
FoodInfoPage,
MealPage,
StatusPage,
TabsPage,
ProfilePage,
AuthPage,
RegisterPage
],
providers: [
StatusBar,
SplashScreen,
NativeStorage,
{ provide: ErrorHandler, useClass:
IonicErrorHandler }
]
})
export class AppModule {}

app.component.ts
import { Component, ViewChild } from '@angular/core';
import { Platform, Nav } from 'ionic -angular';
import { StatusBar } from '@ionic -native/stat us-bar';

67
import { SplashScreen } from '@ionic -native/splash –
screen';
import { NativeStorage } from '@ionic -native/native –
storage';

import { TabsPage } from '../pages/tabs/tabs';
import { ProfilePage } from '../pages/profile/profile';
import { AuthPage } f rom '../pages/auth/auth';

@Component({
templateUrl: 'app.html'
})
export class MyApp {

@ViewChild(Nav) nav: Nav;
rootPage:any = AuthPage;
private profilePage = ProfilePage;
private authPage = AuthPage;
public calendar = new Date();
public today = this.calendar.getDay();

constructor(
platform: Platform,
statusBar: StatusBar,
splashScreen: SplashScreen,
public storage: NativeStorage) {

platform.ready().then(() => {
this.storage.getItem('day').then((data) => {
if(data < this.today) {
this.storage.remove('food');
this.storage.setItem('day', this.today);
}
});

68

statusBar.styleDefault();

this.storage.getItem('check').then((data) => {
this.firstPag e(JSON.parse(data));
});
splashScreen.hide();
});
}
firstPage(x) {
if(x == 1) {
this.rootPage = TabsPage;
} else {
this.rootPage = AuthPage;
}
}
profile() {
this.nav.push(ProfilePage);
}
logout() {
this.storage.clear();
this.nav.setRoot(AuthPage);
}
}

main .ts
import { platformBrowserDynamic } from
'@angular/platform -browser -dynamic';

import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule );

69
auth.ts
< import { Component } from '@angular/core';
import { NavController, AlertController } from 'ionic –
angular';
import { RegisterPage } from '../register/register';
import { Http, Headers, RequestOptions } from
'@angular/http';
import { NativeStorage } from '@ionic -native/native –
storage';

import { ProfilePage } from '../profile/profile';

@Component({
selector: 'page -auth',
templateUrl: 'auth.html'
})
export class AuthPage {

public user_data;
public email;
public passw ord;
public user_profile = [];

constructor(
public navCtrl: NavController,
private alertCtrl: AlertController,
public http: Http,
public requestOptions: RequestOptions,
public storage: NativeStorage) {

}

openRegister() {
this.navCtrl.push(RegisterPage);

70
}
openLogin() {
let alert = this.alertCtrl.create({
title: 'Login',
inputs: [
{
name: 'email',
placeholder: 'Email',
value: 'email@gmail.com',
type: 'email'
},
{
name: 'password',
placeholder: 'Password',
value: 'demo',
type: 'password'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
},
{
text: 'Login',
handler: data => {

this.email = data['email'];
this.password = data['password'];
this.getUserData();

}
}
]

71
});

alert.present();

}

getUserData() {
var headers = new Headers();
headers.append("Accept","application/json");
headers.append("Content -Type","application/json");
let postParams = { email: this.email, pass word:
this.password };
let options = new RequestOptions({headers:
headers});
let url = 'http://url';

this.http.post(url, postParams,
options).subscribe(data => {
this.user_data = data['_body'];
if(this.user_data == 'Wrong data') {
let alert = this.alertCtrl.create({
subTitle: "Wrong username/password",
buttons: ['OK']
});
alert.present();
} else {
this.storage.setItem('user_profile',
this.user_data);
this.navCtrl.setRoot(ProfilePage);
this.storage.setItem('check',1);
}
});
}
}

72
register .ts
< import { Component } from '@angular/core';
import { NavController } from 'ionic -angular';
import { AlertController, ToastController } from
'ionic-angular';
import { Http, Headers, RequestOptions } from
'@angular/http';
import { NativeStorage } from '@ionic -native/native –
storage';

import { ProfilePage } from '../profile/profile';

@Component({
selector: 'page -register',
templateUrl : 'register.html'
})
export class RegisterPage {

public email;
public password;
public password2;
public register_data;

constructor(
public navCtrl: NavController,
public alertCtrl: AlertController,
public toastCtrl: ToastController,
public http: Http,
public requestOptions: RequestOptions,
public storage: NativeStorage
) {

}

73
conditions() {
let alert = this.alertCtrl.create({
title: 'Before you continue',
message: 'By clicking "REGISTER" you agree to
consult with your physician before starting any type of
physical routine or diet.',
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: () => {
console.log( 'Cancel clicked');
}
},
{
text: 'Register',
handler: () => {
if(this.password == this.password2) {
this.registerAccount();
} else {
this.passwordMatch();
}
}
}
]
});

alert.present();

}

passwordMatch() {
let alert = this.alertCtrl.create({
message: 'The passwords do not match.',

74
buttons: [
{
text: 'Ok',
handler: () => {
}
}
]
});

alert.present();

}
registerAccount() {
var headers = new Headers();
headers.append("Accept","application/json");
headers.append("Content -Type","application/json");
let postParams =
{
type: 'register',
email: this.email,
password: this.password
};
let options = new RequestOptions({headers:
headers});
let url = 'http://url';
this.http.post(url, postParams,
options).subscribe(data => {
if(data['_body'] == 'Succes') {
this.register_data = data['_body'];
this.navCtrl.setRoot(ProfilePage);
this.storage.setItem('check',1);
let toast = this.toastCtrl.create({
message: 'Please fill in your profile i nfo',
duration: 3000

75
});
toast.present();
}
});
}
}

tabs.html
<ion-tabs>
<ion-tab [root]="tab1Root" tabTitle="Status"
tabIcon="podium"></ion -tab>
<ion-tab [root]="tab2Root" tabTitle="Calorie Counter"
tabIcon="timer"></ion -tab>
<ion-tab [root]="tab3Root" tabTitle="Meal Planner"
tabIcon="calendar"></ion -tab>
</ion-tabs>

tabs.ts
import { Component } from '@angular/core';

import { CounterPage } from '../counter/counter';
import { MealPage } from '../meal/meal';
import { StatusPage } from '../status/status';

@Component({
templateUrl: 'tabs.html'
})
export class TabsPage {

tab1Root = StatusPage;
tab2Root = CounterPage;
tab3Root = MealPage;

76
constructor() {

}
}

status.ts
< import { Component, ViewChild } from '@angular/core';
import { NavController } from 'ionic -angular';
import { Chart } from 'chart.js';
import { NativeStorage } from '@ionic -native/native –
storage';

@Component({
selector: 'page -status',
templateUrl: 'status.html'
})
export class StatusPage {

@ViewChild('doughnutCanvas') doughnutCanvas;
doughnutChart: any;

public kcal;
public fats;
public carbs;
public protein;
public toggle_limits = false;
public sodium;
public added_sugar;
public saturated;
public cholesterol;
public kcal_budget;
public sodium_limit;
public added_sugar_limit;
public saturated_limit ;

77
public cholesterol_limit;

constructor(
public navCtrl: NavController,
public storage: NativeStorage) {
}

ionViewWillEnter() {
this.importFromProfile();
this.importFromCounter();
this.showMacroChart();
}

importFromProfile() {
this.storage.getItem('kcal_budget'). then((data) =>
{
this.kcal_budget = Math.round(data);
});

this.storage.getItem('sodium_limit').then((data) =>
{
this.sodium_limit = parseFloat(data);
});

this.storage.getItem('added_sugar_limit').then((data)
=> {
this.ad ded_sugar_limit = parseFloat(data);
});

this.storage.getItem('saturated_limit').then((data)
=> {
this.saturated_limit = parseFloat(data);
});

78

this.storage.getItem('cholesterol_limit').then((data)
=> {
this.cholesterol_limit = parseFloat(data);
});
}

importFromCounter() {
this.storage.getItem('counter_kcal').then((data) =>
{
this.kcal = Math.round(data);
});

this.storage.getItem('counter_fats').then((data) =>
{
this.fats = Math.round(data);
});
this.storage.getItem('counter_carbs').then((data)
=> {
this.carbs = Math.round(data);
});
this.storage.getItem('counter_protein').then((data)
=> {
this.protein = Math.round(data);
});

this.storage.getItem('counter_sodium').then((data)
=> {
this.sodium = parseFloat(data.toFixed(2));
});

this.storage.getItem('counter_added_sugar').then((data)
=> {
this.added_sugar = parseFloat(data.toFixed(2));

79
});

this.storage.getItem('counter_saturated').then((data)
=> {
this.saturated = parseFloat(data.toFixed(2));
});

this.storage.getItem('counter_cholesterol').then((data)
=> {
this.cholesterol = parseFloat(data.toFixed(2));
});
}

budget(data) {
if(data >= 0) {
return Math.abs(parseFloat(data.toFixed(2))) + '
left';
} else {
return Math.abs(parseFloat(data.toFixed(2))) + '
over';
}
}

showMacroChart() {
this.doughnutChart = new
Chart(this.doughnutCan vas.nativeElement, {

type: 'doughnut',
data: {
labels: ["Fat", "Carb", "Pro"],
datasets: [{
label: 'macros',
data: [this.fats, this.carbs, this.protein],
backgroundColor: [

80
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}]
}
});
}
}

counter.ts
< import { Component } from '@angular/core';
import {
NavController,
ActionSheetController,
AlertController,
ModalController,
Modal,
ModalOptions } from 'ionic -angular';
import { Http, Headers, RequestOptions } from
'@angular/http';
import { NativeStorage } from '@ionic -native/native –
storage';

import { FoodInfoPage } from '../food -info/food -info';

@Component({
selector: 'page -counter',
templateUrl: 'counter.html'

81
})
export class CounterPage {

public data: any;
public food = [];
public searchInput;
public quantity;
public multiplier;
public counter_kcal;
public counter_fats;
public counter_carbs;
public counter_protein;
public counter_sodium;
public counter_added_sugar;
public counter_saturated;
public counter_cholesterol;

constructor(
public navCtrl: NavController,
public http: Http,
public actionSheetCtrl: ActionSheetController,
public alertCtrl: AlertController,
public modalCtrl: ModalController ,
public storage: NativeStorage

){
this.storage.getItem('food').then((data) => {
this.food = data;
});

}

ionViewWillEnter() {

82
this.storage.getItem('counter_kcal').then((data)
=> {
this.counter_kcal = parseFloat(data);
});

this.storage.getItem('counter_fats').then((data)
=> {
this.counter_fats = parseFloat(data);
});
this.storage.getItem('counter_carbs').then((data)
=> {
this.counter_c arbs = parseFloat(data);
});

this.storage.getItem('counter_protein').then((data) =>
{
this.counter_protein = parseFloat(data);
});

this.storage.getItem('counter_sodium').then((data) => {
this.counter_sodium = parseF loat(data);
});

this.storage.getItem('counter_added_sugar').then((data)
=> {
this.counter_added_sugar = parseFloat(data);
});

this.storage.getItem('counter_saturated').then((data)
=> {
this.counter_saturated = parseFloat(data);
});

83

this.storage.getItem('counter_cholesterol').then((data)
=> {
this.counter_cholesterol = parseFloat(data);
});

if(this.counter_kcal < 1) {
this.counter_kcal = 0;
}
if(this.counter_fats < 1) {
this.counter_fats = 0;
}
if(this.counter_carbs < 1) {
this.counter_carbs = 0;
}
if(this.counter_protein < 1) {
this.counter_protein = 0;
}
if(this.counte r_sodium < 1) {
this.counter_sodium = 0;
}
if(this.counter_added_sugar < 1) {
this.counter_added_sugar = 0;
}
if(this.counter_saturated < 1) {
this.counter_saturated = 0;
}
if(this.counter_cholesterol < 1) {
this.counter_cholesterol = 0;
}
}

getData(event) {
if(event != '') {

84
var headers = new Headers();
headers.append("Accept","application/json");
headers.append("Content –
Type"," application/json");
let query = event.target.value;
let options = new RequestOptions({ headers:
headers });
let url = 'http://url?query=' + query;
this.http.get(url, options).subscribe(data => {
data = JSON.parse(data['_body ']);
this.data = data;
}
);
}
}

setFoodQuantity(item) {
const prompt = this.alertCtrl.create({
title: 'Add food',
inputs: [
{
name: 'quantity',
placeholder: 'Enter the weight in grams',
type: 'number'
},
],
buttons: [
{
text: 'Cancel',
handler: data => {
console.log('Cancel clicked');
}
},
{

85
text: 'Add',
handler: data => {
if (data.quantity == '' || data.quantity ==
'0') {
let alert = this.alertCtrl.create({
subTitle: "Please enter a quantity",
buttons: ['OK']
});
alert.present();
} else {
this.quantity =
parseInt(data.quantity);
this.multiplier =
parseInt(data.quantity) / 100;
this.addFoodToList(item);
}
}
}
]
});

prompt.present();
this.searchInput = '';
}

addFoodToList(item) {
let now = new Date();
let date = now.getHours()+':'+now.getMinutes();
item.time = date;
item.quantity = this.quantity;
item.multiplier = this.multiplier;
this.food.push(item);
this.storage.setItem('food', this.food);
this.addFoodToLog();

86
}

addFoodToLog() {
let last_added = this.food[this.food.length – 1];

this.counter_kcal +=
(parseFloat(last_ added['kcal']) * this.multiplier);
this.counter_fats +=
(parseFloat(last_added['fats']) * this.multiplier);
this.counter_carbs +=
(parseFloat(last_added['carbs']) * this.multiplier);
this.counter_protein +=
(parseFloat(last_added['protein']) * this.multiplier);
this.counter_sodium +=
(parseFloat(last_added['sodium']) * this.multiplier);
this.counter_added_sugar +=
(parseFloat(last_added['added_sugar']) *
this.multiplier);
this.counter_saturated +=
(parseFloat(last_added['fat_sat']) * this.multiplier);
this.counter_cholesterol +=
(parseFloat(last_added['cholesterol']) *
this.multiplier);

this.logToStorage();
}

logToStorage() {
this.storage.setItem('counter_kcal',this.counter_kcal);
this.storage.setItem('counter_fats',this.counter_fats);
this.storage.setItem('counter_carbs',this.counter_carbs
);
this.storage.setItem('counter_protein',this.counter_pro
tein);

87
this.storage.setItem('counter_sodium',this.counter_sodi
um);
this.storage.setItem ('counter_added_sugar',this.counter
_added_sugar);
this.storage.setItem('counter_saturated',this.counter_s
aturated);
this.storage.setItem('counter_cholesterol',this.counter
_cholesterol);
}

Similar Posts