# <center> Kviz aplikacija za predmet Programiranje I </center>
##### Prirodno-matematički fakultet
##### Odsjek za matematiku
##### Teorijska kompjuterska nauka
##### Razvoj mobilnih aplikacija
<hr>
Projekat radile:
Šejla Dizdarić
Adna Hrnjić
Predmetni profesor:
Prof. Dr. Elmedin Selmanović
Predmetni asistent:
Eldina Maslo, MA
## O kvizu
<div style="text-align: justify">
Aplikacija Kviz – riječ je o odgovaranju na pitanja iz predmeta Programiranje I –Python.
Dati kviz nosi 100 bodova.Ukoliko korisnik odgovori tačno na pitanje , osvaja 1,2 ili 3 boda, zavisno od nivoa.
Predmetni profesor na Programiranju I je Elmedin Selmanović.
Postoje tri nivoa težine pitanja na koja se odgovara, korisnik se opredjeljuje za jednu od njih.
Također, korisnik može birati na koliko će pitanja odgovarati, raspon je od 1 do 25 ( što je maksimalni broj pitanja).
Nakon što završi kviz, dođe do samog kraja, prikazan je rezultat, koliko je tačnih a koliko pogrešnih odgovora ukupno te je li iskorišten joker – jedna od pogodnosti ovog kviza. Naime, prilikom odgovaranja na pitanja, moguće je iskoristiti joker – zovi prijatelja. Aplikacija ode u kontakte korisnika, ukoliko on to dopusti, naravno, te je moguće izvršiti poziv, nazvati nekoga od prijatelja, koji će moći pomoći te probati odgovoriti na postavljeno pitanje.
Ukoliko je korisnik zadovoljan postignutim rezultatima, ukoliko je ponosan na sebe i svoje znanje iz datog predmeta, može podijeliti svoje rezultate s drugima unutar neke druge aplikacije.
Dodatno, aplikacija je podržana na engleskom te na bosanskom jeziku.
Korištena je početna verzija trivia aplikacije prilikom izrade naše aplikacije, koja je prilagođena našem projektu, tj. uređena te unaprijeđena, a preuzeta je sa linka:
https://github.com/google-developer-training/android-kotlin-fundamentals-starter-apps/tree/master/AndroidTrivia-Starter
</div>
## Layout
<div style="text-align: justify">
Za svaki posebni fragment dodan je layout.
Budući da aplikacija treba biti responzivna, za svaki ponaosob vertikalni layout također dodan je horizontalni – landscape layout na način :
</div>
<img src="https://imgur.com/oMowvz8.png">
## Welcome
<img src="https://imgur.com/D68si6w.png" height="350px" width="200px">
<br><br>
<div style="text-align: justify">
Ovo je početna stranica naše aplikacije, sa nje se prelazi na novu stranicu (tj. novi layout) pritiskom na dugme GO TO QUIZ. Ovime prelazimo na iduću stranicu, tj. layout.
U aktivnosti Welcome nije korišteno ništa novo, ništa specijalno, već što nije viđeno, samo da se klikom na dugme pređe na iduću aktivnost (MainActivity).
U layout-u Welcome kao pozadinska slika je prikaza slika rađena po mjeri, s naše strane, također i logo kviza, kao i sve ikonice koje se nalaze u ovom projektu, a ukoliko neko želi također napraviti vlastiti logo po svojoj želji i dizajnu, to može učiniti, naravno besplatno, na linku
https://www.freelogodesign.org/
Također, font koji je korišten gotovo na svim layout-ima, sem dekorativnih, je Raleway, a taj font, kao i bilo koji drugi google font, se bira te preuzima na ovaj način:
</div>
<img src="https://imgur.com/iaSeS4D.png" height="250px" width="300px">
<br>
<br>
<img src="https://imgur.com/Z2xgMdk.png" height="350px" width="350px">
## Main
<div style="text-align: justify-all">
Na ovom dijelu aplikacije korisnik unosi nivo težine pitanja na koja će davati svoj odgovor, na koliko želi pitanja odgovarati u intervalu od 1 do 25.
Nakon što unese ispravno potrebne podatke ( neophodno je i odrediti nivo težine pitanja te njihov broj), time se, pritiskom na dugme START QUIZ, započinje kviz.
U aktivnosti Main postavljen je layout fragmenta Title fragment, a sa strane, u trenutnom
layout –u, postavljen je i navigation bar sa strane.
</div><br>
<img src="https://imgur.com/3cKrok0.png" height="350px" width="175px"><br>
<div style="text-align:jusify">
U navigation baru se nalaze About i Rules, koji vode na nove layout-e, na kojima se nalazi opis aplikacije te pravila igre respektivno. Naravno, zavisno od jezika, pravila te opis aplikacije će biti predstavljeni na jeziku, na kojem je lokaliziran mobilni uređaj korisnika.
</div>
<img src="https://imgur.com/yrSIrkO.png" height="350px" width="175px"><br>
<img src="https://imgur.com/7kjjBIG.png" height="350px" width="450px">
## Game
<div>
<img src="https://imgur.com/UYNUSsd.png"
width="200px">
<img src ="https://imgur.com/7K2rxz5.png" width="200px">
<img src="https://imgur.com/5wulcJ0.png" width="200px">
</div>
<br><br>
<div style="text-align:jusify">
Ovo je glavni dio aplikacije, gdje se odvija sami kviz. Pitanja se na random način prikazuju, zavisno koje težine i koliko njih. Prilikom odgovaranja na pitanja, samo jednom se smije iskoristiti joker – zovi prijatelja. Zavisno od vrste pitanja (tri su vrste pitanja:
</div>
<ul>
<li>dopuni</li>
<li> Da/Ne pitanja</li>
<li>pitanja s višestrukim odgovorima</li>
</ul>
<div>
različito se prikažu pitanja, tj. nije isti izgled te stranice.
Nakon što korisnik odgovori na pitanje, prelazi na iduće pritiskom na dugme SUBMIT. Time se šalje odgovor te se provjerava je li ispravno odgovoren te kad odgovori na posljednje pitanje, na idućem layoutu se prikaže rezultat na koliko je tačnih pitanja korisnik odgovorio te koliko je poena osvojio.
Zavisno od izabranog jezika, pitanja će biti ili na bosanskom ili na engleskom jeziku.
</div>
## End game
<img src="https://imgur.com/v4BIvnv.png" height="350px" width="200px">
<div style="text-align: justify">
Kada se dođe do kraja, prikaže se End game layout, gdje se prikažu rezultati kviza, ukoliko se korisnicima svidio kviz te ukoliko izraze želju za ponovnim kvizom, mogu to postići klikom na dugme TRY AGAIN? . Ukoliko ne žele ponovno raditi kviz, onda su došli do samog kraja te nemaju dodatnih opcija sem da podijele rješenja, ukoliko im se sviđaju rezultati te žele da podijele lijepe vijesti s nekim, mogu podijeliti te iste rezultate u nekoj od drugih aplikacija.
</div>
## Manifest
<div style="text-align: justify">
Svaki aplikacija treba imati AndroidManifest.xml datoteku (s tačno tim nazivom) u korijenu skupa izvora projekta. U file-u manifest nalaze se bitne informacije o aplikaciji za alate za izgradnju Android-a, operativni sistem Android i Google Play. Između ostalog, file manifest potreban je za deklarisanje sljedećeg: Naziv paketa aplikacije, koji se obično podudara sa prostorom imena koda. Alat za izgradnju Android koristi to za određivanje lokacije entiteta kodova prilikom izrade projekta. Prilikom pakiranja aplikacije alati za sastavljanje zamjenjuju ovu vrijednost ID-em aplikacije iz gradskih datoteka Gradle, koja se koristi kao jedinstveni identifikator aplikacije na sistemu i na Google Playu. Pročitajte više o nazivu paketa i ID-u aplikacije. Komponente aplikacije, koje uključuju sve aktivnosti, usluge, prijemnike za emitovanje i pružanje sadržaja. Svaka komponenta mora definirati osnovna svojstva, kao što su npr. naziv imena klase Kotlin ili Java. Može deklarisati i mogućnosti poput konfiguracija uređaja kojima može upravljati i filtere namjere koji opisuju kako se komponenta može pokrenuti. Pročitajte više o komponentama aplikacija. Dozvole koje su aplikaciji potrebne za pristup zaštićenim dijelovima sistema ili drugim aplikacijama. Također objavljuje sve dozvole koje moraju imati druge aplikacije, ako žele pristupiti sadržaju iz ove aplikacije.
U Manifest-u je dodana dozvola za obavljanje poziva, pri upotrebi jokera unutar kviza:
</div>
<br><br>
<ul>
<li style="color:blue"><uses-permission android:name="android.permission.CALL_PHONE"/></li>
<li style="color:blue"><uses-permission android:name="android.permission.SEND_SMS" /></li>
</ul>
<br>
<div>
Da ne bi došlo do gubitka informacija prilikom rotiranja, dodana je linija koda: <span style="color:blue">android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"</span>
</div>
<br>
## Question classes
<img src="https://imgur.com/MTZHfyj.png" height="200px" width="700px">
<br>
<br>
<div>
Svako od pitanja koja mogu biti prikazana na našoj stranici pripadaju jednoj od ove tri klase -
<ul>
<li>EnteringQuestion – pitanja čije odgovore korisnik sam unosi, </li>
<li>BooleanQuestion – pitanja Da/Ne tipa</li>
<li>MultipyQuestion – pitanja s više ponuđenih odgovora ( može biti također više i samih tačnih odgovora) .</li>
</ul>
<br>
Svaka klasa, od ove tri se sastoji od teksta samog pitanja, nivoa koje težine je dato pitanje, jezika na kojem je ispisano pitanje, kao i sami odgovori, koji su, shodno klasi, ili tekstualni, ili istinitosne vrijednosti, ili su pak liste parova (ukoliko je riječ o pitanjima s višestrukim odgovorima). Nakon toga se kreiraju pitanja u singleton klasama, koja su tipa jedne od ove tri, prethodno navedene klase.
</div>
## Singleton
<div style="text-align:justify">
Singleton pattern je pattern ( uzorak) softverskog dizajna, koji garantuje da klasa ima samo jednu instancu, a ta klasa pruža globalnu tačku pristupa. Kad god više klasa ili klijenti zatraže tu klasu, dobijaju istu instancu klase. Ova klasa Singleton možda je odgovorna za instanciranje samog sebe ili stvaranje predmeta možete delegirati u fabričku klasu.
Nek se uzme primjer mobitela i njegovog vlasnika. Telefon je obično u vlasništvu jedne osobe, dok osoba može posjedovati više telefona. Kad god jedan od ovih telefona zazvoni, isti vlasnik se javi na njega.
Sasvim je lako implementirati ovaj pattern. Sljedeći isječak koda prikazuje kako se kreira Singleton.
</div>
<img src="https://imgur.com/uhxAc0y.png" height="375px" width="500px">
<div style="text-align:justify">
Pitanja na engleskom jeziku, kao i ista, prevedena na bosanskom, su inicijalizirana u tri različita singletona, predstavljena kao promjenjive lista pitanja questionList, a pitanja mogu biti jednog od tri različita tipa – klasa BooleanQuestions, EnteringQuestion ili MultipleQuestion pa zavisno od toga imamo i tri različita singletona .
Prikaz pitanja će biti na jeziku kojeg korisnik unese, to ne zavisi od defaultnog jezika, na kojem je postavljen, tj. lokaliziran korisnički mobilni uređaj.
</div>
<br>
<img src="https://imgur.com/fbhHizF.png">
<div style="text-align:justify">
Pomoću ove funkcije se pitanja prosljeđuju game fragmentu, također se isto, pomoću preostala dva singletona,preostale dvije vrste pitanja prenose u isti fragment.
Prvo se doda u listu ukupan broj pitanja, koji postoje za tu vrstu te se onda izbriše višak pitanja, koji nam neće trebati za ovu vrstu ( tačno ih treba biti n).
</div>
<hr>
# Fragment
<div style="text-align:justify">
Fragment predstavlja ponašanje ili dio korisničkog interfejsa u FragmentActivity. Može se kombinovati više fragmenata u jednoj aktivnosti da bi se izradio korisnički interfejs s više okna i ponovo iskoristiti fragment u više aktivnosti. O fragment se može razmišljati kao o modularnom odjeljku aktivnosti, koji ima vlastiti životni ciklus, prima vlastite ulazne događaje i koje možete dodavati ili uklanjati dok se aktivnost izvodi (nalik „podaktivnosti“ koju možete ponovno
upotrebiti u različitim aktivnostima).
Fragment mora uvijek biti smješten u aktivnosti, a na lifecycle fragmenta izravno utječe lifecycle aktivnosti hosta. Na primjer, kada je aktivnost pauzirana, svi su fragmenti u njoj, a kada je aktivnost uništena, svi su fragmenti također uništeni. Međutim, dok se neka aktivnost pokreće (nalazi se u ponovnom stanju lifecycle-a), svaki fragment možete manipulisati nezavisno, poput dodavanja ili uklanjanja istih. Kada se izvodi takva transakcija fragmenta, može se dodati i u zadnji snop kojim upravlja aktivnost - svaki unos zadnjeg skupa u aktivnost je zapis transakcije fragmenta koji se dogodio. Zadnja hrpa omogućava korisniku da preokrene transakciju fragmenta (pomicanje unazad) pritiskom na tipku Nazad.
Kada se doda fragment kao dio izgleda aktivnosti, on živi u ViewGroupu unutar hijerarhije prikaza aktivnosti, a fragment definiše svoj vlastiti izgled view-a. Može se umetnuti fragment u svoj izgled aktivnosti deklarisanjem fragmenta u fajlu izgleda aktivnosti, kao <fragment> elementa ili iz vašeg aplikacijskog koda dodavanjem ga u postojeću ViewGroup.
</div>
## About Fragment
<div style="text-align:justify">
U ovom fragmentu se nalazi opis naše aplikacije, sve pojedinosti koje korisnika mogu interesovati o ovoj aplikaciji može naći upravo na ovom fragmentu. Njemu se pristupa preko navigation bara ili preko menu button-a.
</div>
## Rules Fragment
<div style="text-align:justify">
U ovom fragmentu nalaze se pravila ovog kviza, koliko koje pitanje nosi bodova, koliko pitanja općenito može maksimalno se prikazati te sve ostale specifikacije, koje su potrebne znati prije nego korisnik krene s kvizom.
</div>
## Title Fragment
<div style="text-align:justify">
U ovom fragmentu prvo je kreirana klasa Info, koja čuva informacije o broju pitanja, nivoa težine pitanja te jezika na kojem će se dati jezici prikazivati.
Dvije su radio grupe, preuzete s Title Fragmenta, jedna označava nivo težine pitanja, dok druga označava jezik.
Prilikom slanja informacija idućem fragmetu, Game fragmentu, preuzme se tačno koji je nivo u pitanju, koliki je broj ukupnih pitanja koji je korisnik unio, ukoliko unese broj veći od 25, prikladna poruka mu se prikaže( pomoću toast-a) te ponovo unosi u isto polje drugi broj pitanja.
Budući da je ova aplikacija lokalizirana na engleskom i na bosanskom, provjerava se s radio buttona prve radio grupe koji je nivo tačno u pitanju, npr. ukoliko je “Easy” ili “Lakši”, onda u klasi info se promijeni da je level (nivo) 1.
Na kraju se prelazi na idući fragment, game, pomoću NavController-a, objekta koji upravlja navigacijom aplikacije unutar NavHost. Svaki NavHost ima svoj odgovarajući NavController. NavController pruža nekoliko različitih načina za navigaciju do odredišta, koji su dalje opisani u donjim odjeljcima.
Funkcije onCreateOptionsMenu() i onOptionsItemSelected() su funkcije pomoću kojih se prikazuje menu, pomoću menu button-a. Pomoću prve se kreira menu, tj. prikaže, a pomoću druge funkcije se dobija koji je element unutar tog menija izabran, tj. pritisnut.
</div>
## Game Fragment
<div style="text-align:justify">
U početku je kreirana klasa Points, u kojoj su smješteni podaci o rezultatu kviza: broj pitanja, broj tačno odgovorenih pitanja te broj ukupnih bodova.
Ukoliko treba da se funkcija ili svojstvo vežu za klasu, a ne za instance za nju (slično kao @staticmethod u Python-u), može se proglasiti unutar popratne klase.
To je upravo ovdje urađeno, kao i u prethodnom fragmentu.
Iz tri singletona – questionSingleton, enteringQuestionSingleton, booleanQuestionSingleton, preuzmu se pitanja, kreirane su nove liste pitanja – tri različite vrste pitanja te jedna, glavna, u koju će se smještati pitanja, koja će se prikazivati korisnicima.
U Game layout-u postoje tri relativna layout-a, za svaku vrstu pitanja po jedan. Zavisno od pitanja koje će biti korisniku prikazano, tako jedan od tri layout-a se prikaže, a preostala dva se uklone.
Također, dodatne varijable su broj pitanja nižeg, srednjeg te višeg nivoa, također, zavisno od vrste odgovora, dodatne varijable su lista parova, stringova ili istinitosne vrijednosti.
Na kraju će se prikazati pitanje te određeni odgovori na to pitanje, bili oni checkbox, radio buttoni ili input tag, u kojeg će korisnik pokušati dati svoj odgovor na postavljeno pitanje.
Na dnu samog layout-a bit će prikazan floating button- fabMain, prilikom klika na njega bit će prikazana preostala dva buttona, također floating buttoni – fabCall I fabMess, prilikom klika na njih iskorištava se joker zovi prijatelja, moguće je samo kontaktirati nekog od poznanika putem jednog od ova dva načina kontaktiranja.
Submit button – setOnClickListener()
Pomoću ove funkcije provjerava se ispravnost odgovora na pitanje, na način da prvo vršimo provjeru o kojem tipu pitanja je riječ, onda ukoliko je riječ o prvom tipu pitanja, tj. MultypleChoiceQuestion, prođe se kroz listu pitanja te se provjeri koliko ponuđenih odgovora je korisnik tačno zabilježio, da li je i na jedno tačno odgovorio.
Ukoliko je odgovorio tačno na dato pitanje, sve odgovore koje je trebao zabilježiti je zabilježio, ukupni rezultat mu se povećava.
Ukoliko je riječ o BooleanQuestions,tj. pitanjima Da/Ne tipa, prvo se preuzme koji od data dva radio buttona je korisnik označio, ukoliko je tačno označio, dodaju mu se poeni na rezultat te se poveća ukupni broj tačno odgovorenih pitanja.
Inače, u trećem je slučaju riječ o pitanjima EnteringAnswerQuestion, gdje se odgovor unosi preko polja za unos. Budući da se ne treba voditi računa o velikim i malim slovima prilikom unosa, provjeri se samo je li odgovor kojeg korisnik unese jednak tačnom odgovoru, tako što i jednom I drugom povećamo slova (eng. capitalize).
Ukoliko je tačan odgovor, povećaju se zbirni bodovi te broj odgovorenih tačnih pitanja.
Kada dođemo do krajnjeg pitanja , prelazi se na idući, EndGame fragment.
Ukoliko nije kraj pitanjima, poveća se brojač, u našem je to slučaju questionIndex, koji, sve dok je manji od broja pitanja koja se prikazuju, se poveća nakon svakog prikazanog pitanja.
Kada se pritisne na jedan od dva joker buttona, joker se više ne može iskoristiti(varijabla joker se postavi na false i više ga nije moguće iskoristiti).
Funkcija randomizeQuestions() koristi dvije pomoćne funkcije- countingProcent()
te setQuestion().
Funkcija countingProcent() računa procenat za svako pitanje, zavisno od nivoa težine te vrste pitanja, ovdje imamo devet varijabli, koji će predstavljati, svaki zasebno, određenu vrstu pitanja te njegovog nivoa.
Zavisno od izabranog nivoa, pitanja iz tog nivoa će biti 50%, iz preostala dva nivoa će ih biti po 25%.
Ukoliko je riječ o pitanjima s višestrukim odgovorima, njih će biti prikazano 40% ( jer po našem mišljenju su najinteresantnija i komplikovanija od ostalih za ovu vrstu aplikacije, a i najviše ih je smišljeno takvih), dok će do 30% biti preostale dvije vrste pitanja.
Na kraju u jednu listu se dodaju sve tri liste pitanja ( zavisno od nivoa u tri različite liste tri različita tipa pitanja), te se onda nakon dodavanja u te tri liste pitanja, one dodaju u glavnu, questions listu.
Funkcija setQuestion() postavlja pitanja na layout, zavisno od vrste pitanja, taj relativni layout postavi da je vidljiv (VISIBLE), a preostala dva stavi da nisu vidljivi(GONE).
Zavisno od tipa pitanja, prikupe se svi odgovori te se prikažu ili u checkbox-ovima ili u radio buttonima. Ukoliko je niži level, tada pitanje nosi jedan poen, srednji nivo donosi 2 poena, a viši 3 poena. Zavisno od jezika pitanja, postave se odgovori na da i ne( ili yes i no).
Dodatne su funkcije setMyFabs(), openMenu() i closeMenu() služe se prikazivanje floating buttona na dnu samog layout – pomoću kojih se pristupa jokeru.
</div>
## QuizWon Fragment
<div style="text-align:justify">
Ovaj fragment se prikaže, ukoliko se stiglo do kraja kviza. Na njegovom layout-u su prikazani rezultati kviza te se korisniku nudi ponuda ponovnog testiranja, ukoliko želi ponovo uraditi taj isti kviz, ili čak i teži od trenutnog nivoa težine pitanja izabrati, a to može postići ukoliko se pritisne button za ponovnu igru, kojim se prelazi na početni fragment.
</div>
<hr>
# Nagivation.xml
<img src="https://imgur.com/W40TRku.png" >
<br>
<br>
<div style="text-align:justify">
Navigacija se odvija između odredišta aplikacije - to jeste bilo gdje u aplikaciji, do koje korisnici mogu dospjeti. Ova odredišta su povezana putem akcija.
Navigacijski graf je file s resursima, koji sadrži sva odredišta i radnje. Grafikon predstavlja sve navigacijske staze aplikacije.
Ovdje prikazan je vizualni prikaz navigacijskog grafikona aplikacije, koja sadrži pet odredišta, od kojih su tri povezana s tri akcije. Svako odredište predstavljeno je sličicom za pregled, a radnje povezivanja predstavljene su strelicama koje pokazuju kako korisnici mogu kretati s jednog odredišta na drugo.
</div>
# Activity
<div style="text-align:justify">
Android aktivnost je jedan ekran korisničkog interfejsa aplikacije Android. Na taj način je Android aktivnost vrlo slična Windowsima u desktop aplikaciji. Android aplikacija može sadržavati jednu ili više aktivnosti, znači jedan ili više stranica.
</div>
## Welcome Activity
<div style="text-align:justify">
U aktivnosti Welcome nije korišteno ništa novo, ništa specijalno, već što nije viđeno, samo da se klikom na dugme pređe na iduću aktivnost (MainActivity).
</div>
## Main Activity
<div>
Također, ni u ovoj aktivnosti nije korišteno ništa specijalno, što ranije nije već viđeno, sem možda funkcije
onSupportNavigateUp(), koja je ovdje overrideana.
</div>
<br>
<img src="https://imgur.com/yuv6a9O.png">
<br><br>
<div style="text-align:justify">
onSupportNavigateUp() dolazi iz AppCompatActivity. Treba se override-ati metoda tamo gdje je definisan NavHostFragment. Override-a se na način da NavigationUI može pravilno podržavati gornju navigaciju ili čak i izbornik drawer layout-a. AppCompatActivity i NavigationUI su dvije nezavisne komponente, tako da se ova metoda override kako bi se one povezale.
</div>