This shows you the differences between two versions of the page.
|
si:laboratoare:02 [2022/09/14 16:21] laura.ruse [Exerciții] |
— (current) | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ===== Laboratorul 02. Fitbit SDK - Application ===== | ||
| - | La fel ca în laboratorul trecut, target-ul cu care vom lucru este un produs Fitbit, și anume **Fitbit Versa 3** sau **Fitbit Sense**. Vom utiliza //Fitbit Software Development Kit// (//SDK//) pentru a dezvolta o aplicație (app) în acest laborator, folosind mediul de dezvoltare pus la dispoziție de către Fitbit (Fitbit Studio) și simulatorul (Fitbit OS Simulator). Documentația pentru dezvoltatorii de aplicații Fitbit se poate găsi pe [[https://dev.fitbit.com/]]. | ||
| - | O aplicație este de obicei un program specializat cu un scop clar (e.g. aplicație de exerciții fitness, aplicație de alarme/timere etc.), spre deosebire de o [[https://dev.fitbit.com/build/guides/clockfaces/|față de ceas]] care afișează în principiu ora și câteva statistici pentru ca utilizatorul să fie informat rapid când folosește smartwatch-ul. | ||
| - | |||
| - | ===== Setup ===== | ||
| - | |||
| - | <note tip>Vă recomandăm să folosiți **Windows** sau **macOS** pentru aceste laboratoare!</note> | ||
| - | |||
| - | Setup-ul este același ca în laboratorul trecut ([[https://ocw.cs.pub.ro/courses/si/laboratoare/01|laboratorul 1]]). | ||
| - | |||
| - | Mai exact, pentru a putea folosi infrastructura pusă la dispoziție de către Fitbit va trebui să urmați pașii: | ||
| - | - Creați-vă un cont Fitbit accesând [[https://www.fitbit.com/signup|acest link]]. | ||
| - | - Descărcați simulatorul (Fitbit OS Simulator) pentru [[https://simulator-updates.fitbit.com/download/latest/win|Windows]] sau [[https://simulator-updates.fitbit.com/download/latest/mac|macOS]]. Nu există support pentru Linux, dar există workarounds pentru acest lucru în cazul în care doriți să utilizați Linux la aceste laboratoare (urmați pașii de [[https://github.com/bingtimren/fitbit-sim-starter|aici]] pentru a rula simulatorul pe Linux). | ||
| - | - Accesați [[https://studio.fitbit.com/|Fitbit Studio]], mediul de dezvoltare online pus la dispoziție pentru developeri. | ||
| - | <note important>Conectați-vă atât la Fitbit Studio, cât și la simulator cu **același** cont Fitbit creat mai sus!</note> | ||
| - | |||
| - | ===== Exerciții ===== | ||
| - | <note important> | ||
| - | În cadrul simulatorului setați **Versa 3** sau **Sense** ca de tip device (Settings -> Device Type). | ||
| - | |||
| - | Trebuie să folosiți versiunea 6.0 a SDK-ului. | ||
| - | </note> | ||
| - | |||
| - | <note important> | ||
| - | Dacă Fitbit Studio nu se conectează la simulator, iar în simulator (la Settings) apare eroarea "Device bridge is disconnected", trebuie să actualizați certificatul simulatorului. Soluția se găsește în discuția de [[https://community.fitbit.com/t5/SDK-Development/Simulator-SSL-Problem/m-p/5003032/highlight/true#M16148|aici]]. Folderul este numit ''atlas'' pentru Versa 3 și ''vulcan'' pentru Sense. | ||
| - | |||
| - | Pe Mac OS folderul este ''/Applications/Fitbit OS Simulator.app/Contents/Resources/static/devicesim/mac/vulcan.app/Contents/Resources'' (pentru Sense). | ||
| - | |||
| - | </note> | ||
| - | |||
| - | **0.** Ne propunem să creăm o aplicație cu luminițe (cea din GIF-ul de mai jos). Aplicația va avea trei butoane care pornesc/opresc un mic spectacol de lumini. Pentru aceasta creați un nou proiect în [[https://studio.fitbit.com/|Fitbit Studio]] și alegeți template-ul //Minimal//. Descărcați template-ul pentru laborator de [[https://drive.google.com/file/d/18Yg3cV50ZhMa9pV4YM9Y5tmJ2Nlw37D8/view?usp=sharing|aici]] și aplicați-l în cadrul proiectului. Asigurați-vă că în ''package.json'' aveți setat tipul proiectului ca aplicație (**Type -> App**). Deocamdată ''app/index.js'' este gol, iar proiectul nu va fi buildat cu succes. | ||
| - | |||
| - | {{ :si:laboratoare:lightsapp.gif?300 |}} | ||
| - | |||
| - | <note tip> | ||
| - | Exercițiile din laborator se rezolvă în fișierul ''app/index.js''. Template-ul conține comentarii de tip //TODO// pentru fiecare subpunct al exercițiilor. Vom utiliza doar Device APIs, documentația lor se află [[https://dev.fitbit.com/build/reference/device-api/| aici]]. Limbajul de programare utilizat este Javascript, dar ne vom limita la funcționalitățile de bază. | ||
| - | </note> | ||
| - | |||
| - | **1.** Deocamdată ''app/index.js'' este gol, iar proiectul nu va fi buildat cu succes. Pentru acest exercițiu ne propunem să avem referințe către toate elementele din ''index.view'' și variabile pentru a putea manipula mai ușor starea luminițelor. | ||
| - | - obțineți referințele către lumini și adăugați-le într-un array.<code javascript> | ||
| - | import document from "document"; | ||
| - | |||
| - | // Get all lights references by the ID defined in index.view | ||
| - | const lights = [ | ||
| - | document.getElementById("bot1"), | ||
| - | document.getElementById("bot2"), | ||
| - | document.getElementById("bot3"), | ||
| - | document.getElementById("bot4"), | ||
| - | document.getElementById("bot5"), | ||
| - | document.getElementById("bot6"), | ||
| - | document.getElementById("bot7"), | ||
| - | document.getElementById("bot8"), | ||
| - | document.getElementById("bot9"), | ||
| - | document.getElementById("bot10"), | ||
| - | ]; | ||
| - | </code> | ||
| - | - obțineți referințele către cele trei butoane.<code javascript> | ||
| - | const blinkLightsButton = document.getElementById("lights-1"); | ||
| - | const slideLightsButton = document.getElementById("lights-2"); | ||
| - | const customLightsButton = document.getElementById("lights-3"); | ||
| - | </code> | ||
| - | - definiți două array-uri care să conțină culorile pentru stările când luminițele globurilor sunt aprinse, respectiv când acestea sunt închise.<code javascript> | ||
| - | // Colors for each light turned on | ||
| - | const lightOnColor = [ | ||
| - | "#FFA500", | ||
| - | "#FFA500", | ||
| - | "#FFA500", | ||
| - | "#FFA500", | ||
| - | "#FFA500", | ||
| - | "#FFA500", | ||
| - | "#FFA500", | ||
| - | "#FFA500", | ||
| - | "#FFA500", | ||
| - | "#FFA500", | ||
| - | ]; | ||
| - | |||
| - | // Colors for each light turned off | ||
| - | const lightOffColor = [ | ||
| - | "#FCF4A3", | ||
| - | "#FCF4A3", | ||
| - | "#FCF4A3", | ||
| - | "#FCF4A3", | ||
| - | "#FCF4A3", | ||
| - | "#FCF4A3", | ||
| - | "#FCF4A3", | ||
| - | "#FCF4A3", | ||
| - | "#FCF4A3", | ||
| - | "#FCF4A3", | ||
| - | ]; | ||
| - | </code> | ||
| - | - creați un array în care să țineți evidența globurilor aprinse/stinse.<code javascript> | ||
| - | const lightsOn = [ | ||
| - | false, | ||
| - | false, | ||
| - | false, | ||
| - | false, | ||
| - | false, | ||
| - | false, | ||
| - | false, | ||
| - | false, | ||
| - | false, | ||
| - | false, | ||
| - | ]; | ||
| - | </code> | ||
| - | <note tip> | ||
| - | **Explicații**: | ||
| - | * Pentru a putea obține referințele către elementele UI este nevoie de [[https://dev.fitbit.com/build/reference/device-api/document/|Document API]], în care avem acces la funcția **getElementById()**. | ||
| - | * Puteți folosi și alte culori dacă doriți. Pentru inspirație puteți intra [[https://dev.fitbit.com/build/guides/user-interface/css/|aici]]. | ||
| - | </note> | ||
| - | |||
| - | **2.** Pentru a putea face tranziția între jocurile de lumini avem nevoie de posibilitatea de a le stinge pe toate întâi. | ||
| - | - definiți funcția **turnOffLights()** care stinge luminițele (setează culorile pe starea de luminițe închise).<code javascript> | ||
| - | function turnOffLights() { | ||
| - | let i; | ||
| - | for (i = 0; i < lights.length; i++) { | ||
| - | lightsOn[i] = false; | ||
| - | lights[i].style.fill = lightOffColor[i]; | ||
| - | } | ||
| - | } | ||
| - | </code> | ||
| - | - apelați funcția definită anterior pentru a începe aplicația cu luminițele stinse.<code javascript> | ||
| - | turnOffLights(); | ||
| - | </code> | ||
| - | |||
| - | **3.** Creați primul joc de lumini astfel încât atunci când apăsați primul buton toate luminițele să se aprindă și să se stingă la un interval de timp definit de voi (e.g. 200 ms). Toate butoanele trebuie să implementeze stingerea jocului de lumini deja activ pentru a nu se influența două jocuri de lumini între ele. | ||
| - | - adăugați un eveniment pentru primul buton care să execute o funcție **blinkLights()** în care veți implementa jocul de lumini.<code javascript> | ||
| - | // We will recycle the same event handler | ||
| - | let intervalHandler = -1; | ||
| - | |||
| - | // First button event | ||
| - | blinkLightsButton.addEventListener("click", (evt) => { | ||
| - | if (intervalHandler == -1) { | ||
| - | intervalHandler = setInterval(blinkLights, 200); | ||
| - | } else { // Turn off event and cleanup | ||
| - | clearInterval(intervalHandler); | ||
| - | intervalHandler = -1; | ||
| - | turnOffLights(); | ||
| - | } | ||
| - | }); | ||
| - | </code> | ||
| - | - implementați funcția **blinkLights()** care a fost dată ca parametru la subpunctul anterior (toate luminițele să se aprindă dacă erau stinse, și să se stingă dacă erau aprinse).<code javascript> | ||
| - | function blinkLights() { | ||
| - | let i; | ||
| - | for (i = 0; i < lights.length; i++) { | ||
| - | if (lightsOn[i]) { | ||
| - | lights[i].style.fill = lightOffColor[i]; | ||
| - | } else { | ||
| - | lights[i].style.fill = lightOnColor[i]; | ||
| - | } | ||
| - | lightsOn[i] = !lightsOn[i]; | ||
| - | } | ||
| - | } | ||
| - | </code> | ||
| - | |||
| - | <note tip> | ||
| - | **Eplicații**: | ||
| - | * Pentru a se adăuga un eveniment la apăsarea unui buton s-a utilizat funcția **addEventListener()** pe elementul buton în care s-a setat un [[https://dev.fitbit.com/build/guides/user-interface/svg-components/buttons/#click-events| click event]]. | ||
| - | * Pentru a apela o funcție la un anumit interval de se utilizeaza funcția **setInterval()** care primește ca parametri o funcție de apelat și un interval de milisecunde în care să apeleze funcția dată, și întoarce un număr ce reprezintă ID-ul timer-ului setat. Pentru a dezactiva timer-ul se utilizează funcția **clearInterval()** care primește ca parametru ID-ul timer-ului. Pentru documentație intrați [[https://dev.fitbit.com/build/reference/companion-api/globals/|aici]]. | ||
| - | * Variabila **intervalHandler** are rolul de a reține ID-ul ultimului timer setat pentru a-l putea deseta la următoarea apăsare de buton. | ||
| - | </note> | ||
| - | |||
| - | **4.** Creați al doilea joc de lumini astfel încât atunci când apăsați al doilea buton să se aprindă un singur rând de lumini, restul fiind stinse. La un interval de timp definit de voi (e.g. 400 ms) să se aprindă următorul rând de lumini, iar cel anterior să se stingă. Toate butoanele trebuie să implementeze stingerea jocului de lumini deja activ pentru a nu se influența două jocuri de lumini între ele. | ||
| - | - adăugați un eveniment pentru al doilea buton care să execute o funcție **slideLights()** în care veți implementa jocul de lumini.<code javascript> | ||
| - | let currentLight; // keep track of the current lights for the slide show | ||
| - | slideLightsButton.addEventListener("click", (evt) => { | ||
| - | if (intervalHandler == -1) { | ||
| - | currentLight = 0; | ||
| - | lights[currentLight].style.fill = lightOnColor[currentLight]; | ||
| - | lightsOn[currentLight] = true; | ||
| - | lights[currentLight+rows].style.fill = lightOnColor[currentLight+rows]; | ||
| - | lightsOn[currentLight+rows] = true; | ||
| - | |||
| - | intervalHandler = setInterval(slideLights, 400); | ||
| - | } else { // Turn off event and cleanup | ||
| - | clearInterval(intervalHandler); | ||
| - | intervalHandler = -1; | ||
| - | turnOffLights(); | ||
| - | } | ||
| - | }); | ||
| - | </code> | ||
| - | - implementați funcția **slideLights()** care a fost dată ca parametru la subpunctul anterior (să se aprindă următorul rând de lumini, iar cel anterior să se stingă).<code javascript> | ||
| - | function slideLights() { | ||
| - | lights[currentLight].style.fill = lightOffColor[currentLight]; | ||
| - | lightsOn[currentLight] = false; | ||
| - | lights[currentLight+rows].style.fill = lightOffColor[currentLight+rows]; | ||
| - | lightsOn[currentLight+rows] = false; | ||
| - | |||
| - | currentLight = (currentLight + 1) % rows; | ||
| - | lights[currentLight].style.fill = lightOnColor[currentLight]; | ||
| - | lightsOn[currentLight] = true; | ||
| - | lights[currentLight+rows].style.fill = lightOnColor[currentLight+rows]; | ||
| - | lightsOn[currentLight+rows] = true; | ||
| - | } | ||
| - | </code> | ||
| - | |||
| - | <note tip> | ||
| - | **Explicații**: | ||
| - | * Variabila **currentLight** are rolul de a reține rândul de lumini ce a fost aprins pentru a putea fi stins după ce a trecut intervalul de timp. | ||
| - | </note> | ||
| - | |||
| - | **5.** Creați al treilea joc de lumini după cum doriți voi. Puteți urma ca exemplu celălalte jocuri de lumini. Toate butoanele trebuie să implementeze stingerea jocului de lumini deja activ pentru a nu se influența două jocuri de lumini între ele. | ||
| - | - adăugați un eveniment pentru al treilea buton care să execute o funcție **customLights()** în care veți implementa jocul de lumini.<code javascript> | ||
| - | customLightsButton.addEventListener("click", (evt) => { | ||
| - | if (intervalHandler == -1) { | ||
| - | intervalHandler = setInterval(customLights, 1000); // adjust the interval timer | ||
| - | } else { // Turn off event and cleanup | ||
| - | clearInterval(intervalHandler); | ||
| - | intervalHandler = -1; | ||
| - | turnOffLights(); | ||
| - | } | ||
| - | }); | ||
| - | </code> | ||
| - | - implementați funcția **customLights()** care a fost dată ca parametru la subpunctul anterior (voi definiți acest joc de lumini).<code javascript> | ||
| - | function customLights() { | ||
| - | // TODO complete here | ||
| - | console.log("custom lights show"); | ||
| - | } | ||
| - | </code> | ||
| - | |||
| - | **[BONUS]6.** Înlocuiți imaginea de background cu o alta la alegerea voastra. Asigurați-vă că aceasta este tot un fișier cu extensia .png/.jpg și dimensiune maxim 336 x 336 pentru Fitbit Sense. Puteți muta poziția luminilor din fișierul ''index.view''. Distracție placuta! | ||
| - | |||
| - | |||
| - | |||
| - | <hidden> | ||
| - | Atasat se gaseste o implementare a solutiei {{ si:laboratoare:application_2020_index.txt |}}. | ||
| - | Din motive de securitate fisierul original a fost salvat cu extensia //".txt"//. | ||
| - | Pentru a putea fi folosit acesta trebuie redenumit la **application_2020_index.js**. | ||
| - | </hidden> | ||
| - | ===== Resurse ===== | ||
| - | * [[https://drive.google.com/file/d/18Yg3cV50ZhMa9pV4YM9Y5tmJ2Nlw37D8/view?usp=sharing|Template Laborator]] | ||
| - | * [[https://dev.fitbit.com/getting-started/| Getting Started with Fitbit SDK]] | ||
| - | * [[https://dev.fitbit.com/build/reference/device-api/| Fitbit SDK - Device API Reference]] | ||
| - | * [[https://dev.fitbit.com/build/guides/| Fitbit SDK Guides]] | ||
| - | * [[https://dev.fitbit.com/build/guides/user-interface/svg-components/buttons/| Button Components Guide]] | ||