###### Univerzitet u Sarajevu ###### Prirodno-matematički fakultet ###### Odsjek za matematiku ###### Teorijska kompjuterska nauka ###### <center> Dokumentacija za projekat iz predmeta Razvoj mobilnih aplikacija, na temu </center> # <center> Kviz aplikacija Programiranje I </center> Projekat radio: Naser Abd-el Ilah Predmetni profesor:Prof. Dr. Elmedin Selmanović Predmetni asistent: Eldina Maslo, MA ## Sadržaj <ul> <li>Uvod</li> <li>Manifest</li> <li>Layout folder <ul> <li>activity_main.xml</li> <li>fragment_title.xml</li> <li>fragment_game.xml</li> <li>fragment_game_won.xml</li> <li>fragment_rules.xml</li> <li>fragment_about.xml</li> <li>nav_header.xml</li> </ul> </li> <li>menu folder <ul> <li>navdrawer_menu.xml</li> <li>options_menu.xml</li> <li>winner_menu.xml</li> </ul> </li> <li>navigation folder <ul> <li>navigation.xml</li></ul> </li> <li>Kotlin folder</li> <ul> <li>MainActivity</li> <li>TitleFragment</li> <li>GameFragment</li> <li>GameWonFragment</li> <li>RulesFragment</li> <li>AboutFragment</li> </ul> </ul> <hr> # Uvod <div style="text-align:justify"> Trivia aplikacija je moja verzija mobilne aplijacije za android mobitele ,gdje korisnik odgovara na postavljena pitanja, pitanje može imati odgovore tipa tekstualni odgovor ili višestruki odgovori, može pozvati nekog iz kontakata ili poslati poruku sa sadržajem pitanja, to jeste može se iskoristiti joker, pritom samo jednom u toku kviza. Na kraju dobije rezultat koliko je tačnih imao, koliko pogrešnih te je li uspio riješiti ga bez upotrebe bonusa – jokera. Za kreiranje ove aplikacije koristio sam src code, kojeg smo također koristili na predavanjima sa linka: github.com/udacity/andfun-kotlin-android-trivia te sam ga dorađivao i dodao dodatne specifikacije koje ste tražili. Na početku imam fragment kao na slici ispod, gdje se mogu birati jedna od tri težine - nivoa te se može unijeti broj željenih pitanja pitanja ( postoji gornji limit za svaki nivo). </div> <br><br> <img src="https://imgur.com/oau4QJ2.png"> <br><br> <div style="text-align:justify"> Klikom na dugme Play,kviz, tj. igrica počinje i prelazim na sljedeći fragment gdje je prikazano prvo pitanje. Ukoliko je pitanje s odgovorom tipa višestruki odgovori, onda će biti prikazana slika lijevo ispod, inače, ukoliko je pitanje tipa tekstualni odgovor, onda će biti prikazano slika desno ispod. Ovo vrijedi za sva pitanja koja će biti izgenerisana u samoj aplikaciji te prikazana korisniku, imala ona jedan, tekstualni odgovor ili više njih. </div> <img src="https://imgur.com/yn7CALH.png" style="padding: 15px"> <img src="https://imgur.com/J0dCRAV.png" style="padding: 15px"> <div style="text-align:justify"> Prilikom odgovaranja na nekoj pitanju, moguće je samo jednom iskoristiti joker -tj. pozvati neku osobu iz kontakata (ličnih). Ukoliko nema više preostalih pitanja, koji nisu bili prikazani, tj. ukoliko su sva pitanja prikazana korisniku, on je na njih odgovorio ili nije, tačno ili netačno. Nakon toga prelazi se na sljedeći fragment ( tj. na fragment GameWonFragment ) , gdje će biti prikazani broj tačnih pitanja i broj koliko je bilo pitanja te da li je iskoristio joker ili nije. </div> <img src="https://imgur.com/jMHlygL.png"> <br><br> <div style="text-align:justify"> Tu se nalazi i share ikona, koja nam da mogućnost da postignuti rezultat može biti podijeljen. Ukoliko na tom fragmentu kliknemo na dugme ( eng. button) koje se nalazi u sredini, dugme NEXT MATCH tada se opet prebacujemo na početni fragment gdje možemo iznova birati težinu i broj pitanja te igrati dati kviz ponovo, ukoliko, npr. nismo bili zadovoljni rezultatom, smatramo da znamo bolje ili pak želimo ponovo da igramo, jer nam se mnogo svidjela aplikacija ( nadam se da je ovakvih mnogo ljudi te da će se većini svidjeti moja verzija date aplikacije). U nastavku će biti objašnjenje detaljno. Također apikacija je lokalizirana na 2 jezika, maternji – bosanski te engleski. Ukoliko je mobitel podešen na engleskom jeziku ,onda će aplikacija automatski biti postavljena na engleskom jeziku. Jednom kada promjenimo jezik s engleskog na bosanski, ukoliko je mobitel naravno podešen na engleski jezik, aplikacija će automatski biti prikazana na Bosanskom jeziku. </div> # Manifest <div style="text-align:justify"> U ovom file- u ,osim defaultni code koji android studio sam generiše, dodao sam da tražim dozvolu: <uses-permission android:name="android.permission.CALL_PHONE"/> tj. da tražim dozvolu da mogu napraviti poziv, kojeg ću koristiti za jokera. Osim toga, u mojoj glavnoj aktivnosti ( MainActivity ) tag dodao sam liniju code-a: android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" koja nam služi da ne bi došlo do gubitka neke od informacija tokom rotiranja aplikacije, promjene veličine ekrana itd.. Prema dokumentaciji: „ If your application doesn't need to update resources during a specific configuration change and you have a performance limitation that requires you to avoid the activity restart, then you can declare that your activity handles the configuration change itself which prevents the system from restarting your activity. To declare that your activity handles a configuration change, edit the appropriate <activity> element in your manifest file to include the android:configChanges attribute with a value that represents the configuration you want to handle. Possible values are listed in the documentation for the android:configChanges attribute. The most commonly used values are "orientation", "screenSize", "screenLayout", and "keyboardHidden": • The "orientation" value prevents restarts when the screen orientation changes. • The "screenSize" value also prevents restarts when orientation changes, but only for Android 3.2 (API level 13) and above. • The "screenLayout" value is necessary to detect changes that can be triggered by devices such as foldable phones and convertible Chromebooks. • The "keyboardHidden" value prevents restarts when the keyboard availability changes. If you want to manually handle orientation changes in your app you must declare the "orientation", "screenSize", and "screenLayout" values in the android:configChanges attributes. You can declare multiple configuration values in the attribute by separating them with a pipe | character.” Te onda mogu override - ati funkciju: onConfigurationChanged(newConfig: Configuration) i tu mogu napisati code koji želim da se izvrši kada promijenim npr. orijentaciju, što je bilo potrebno u ovom slučaju , jer sam želio da se prikaže drugi , tj. horizontalni layout (landscape layout). </div> <hr> # Layout folder ## 1. activity_main.xml <div style="text-align:justify"> Ovdje se definiše glavni layout gdje će biti definisan NavigationView , te fragment view , na kojem mjestu će se tačno prikazati jedan od sljedećih navedenih fragmenata: TitleFragment ( početni ) , AboutFragment , RulesFragment , GameFragment , GameWonFragment . </div> ## 2. fragment_title.xml <div style="text-align:justify"> Ovdje se prvo prikaže slika , ispod nje nalazi se Radio group u kojem su sadržana 3 Radio button -a (dugmeta) , koji imaju uz sebe prikazan text „easy“, „medium“ i „advanced“ redom – to predstavlja težinu pitanja koja će biti prikazana. Također se tu nalazi , ispod ova tri radio Button – a jedan EditText ,gdje se unosi tačan broj koliko pitanja korisnik želi da mu bude prikazano u kvizu. Uz to, na samom kraju layout –a , ispod EditText –a , nalazi se dugme, na kojeg kad se pritisne, trenutna igra se počinje i prelazi se na sljedeći fragment poslije toga. Za ovaj fragment imam i drugi layout,horizontalni, koji će se prikazati za landscape mode . </div> ## 3. fragment_game.xml <div style="text-align:justify"> Kako imam 2 tipa pitanja, u zavisnosti na vrstu , tj. broj odgovora ( 0 za tekstualne odgovore, 1 za višestruke odgovore) , onda view-s koji se prikazuju na ekranu nam zavise od tipa tih istih pitanja. Ukoliko je pitanje tipa tekstualni odgovor, onda će ono da bude prikazano kao EditText za unošenje odgovora te LinearLayout , koji je sastavljen od 4 checkBox-a neće biti prikazan na ekranu . U suprutom , ukoliko je riječ o pitanju, koje je tipa višestruki odgovor, onda će ono da bude prikazano kao LinearLayout koji sadrži 4 checkBox-a ,da bismo mogli sami izabrati tačne odgovore ( da je riječ o radio button -ima, onda bi pitanje imalo tačno jedan odgovor, to jeste, mogao bi se samo jedan odgovor na pitanje dati) . Dodatno, EditText, u kojem bi se inače unosio tekstualni odgovor, neće biti prikazan na ekranu . Također , imamo i TextView , koji sadrži tekst Joker, klikom na njega, taj TextView prikazuje se AlertDialog , kojim se postavlja pitanje da li smo sigurni da želimo iskoristiti jedini Joker baš za to pitanje, jedini joker kojeg imamo kod sebe tj. pozvati neku osobu , jer se može desiti da neko tokom igre slučajno pritisne na to polje te time izgubi mogućnost da mu neko pomogne oko idućeg pitanja. Imamo također i dugme Submit , uz pomoću kojeg , kada kliknemo na njega , mi prelazimo na sljedeće pitanje , ukoliko postoji još neprikazanih pitanja od izabranit , te ukoliko nema više neprikazanih pitanja , onda se prelazi na fragment GameWonFragmnt , gdje će nam biti prikazani rezultati, tačni broj pitanja te ćemo nakon toga znati jesmo li dobro uradili kviz ili nismo . </div> ## 4. fragment_game_won.xml <div style="text-align:justify"> Fragment koji će biti prikazan kad se kviz ( igrica ) završi. Tu se nalazi slika , koju samo prikazujem, ispod nje se nalazi TextView , gdje je pisano koliko pitanja sam tačno odgovorio i koliki je ukupan broj pitanja, te dugme ( button) - NEXT MATCH koja mi omoguća da započnem kviz ispočetka. Također, tu se nalazi i share menu , koji nam daje mogućnost dijeljenja rezultata u drugim aplikacijama , ukoliko to želimo. Također i za taj fragment postoji i drugi, horizontalni layout , koji će se prikazati u landscape mode-u. </div> ## 5. fragment_rules.xml <div style="text-align:justify"> Tu se samo nalaze slika i tekst, koji je prethodno zadan. </div> ## 6. fragment_about.xml <div style="text-align:justify"> Ista kao fragment_rules, u njoj se samo nalaze slika i tekst ,koji su ,također, zadani unaprijed. </div> ## 7. nav_header.xml <div style="text-align:justify"> Ovdje se nalazi samo jedna sliku , koja je prikazana u NavigationView. Naravno, pored slike moguće je dodati i drugih stvari,kao što su tekst, još dodatnih slika itd.. </div> <hr> # menu folder ## 1. navdrawer_menu.xml <div style="text-align:justify"> Tu se nalaze 2 elementa: Rules i About ,koji će biti prikazani u NavigationView , ispod slike. </div> ## 2. options_menu.xml <div style="text-align:justify"> Tu se jedino nalazi jedan element , a to je About , koji će biti prikazan kad se klikne na 3 vertikalne tačke, u Action bar –u desno, u gornjem ćošku. </div> ## 3. winner_menu.xml <div style="text-align:justify"> Tu se nalazi samo jedan element ,a to je Share koji će biti prikazan kad se klikne na znak share u Action bar desno , u fragment_game_won -u . </div> <hr> # navigation folder ## navigation.xml <div style="text-align:justify"> Ovaj file služi nam kao preglednik za našu aplikaciju, tu definišem svih 5 fragmenata, relacije i akcije između njih te potrebne argumente itd.. </div> # Kotlin folder ## 1. MainActivtiy <div style="text-align:justify"> U funkciji onCreate (savedInstanceState : Buindle? ) definišem drawerLayout, koji je tipa DrawerLayout te navController koji je tipa NavController koji su neophodni za kreiranje NavigationUI . Također je i neizostavna funkcija onSupportNavigateUp () : Boolean { } , pomoću koje nam se prikazuje NavigationUI , onda kad se klikne na tu ikonu u Action baru lijevo. Funkcija useJoken ( view : View ) - ona će se izvršiti onda kada korisnik zatraži da iskoristi joker – a , pri tome se pozove i privatna funckija showDialog () , koja će prikazati Alert Dialog sa naslovom „ Make a call „ i porukum „ Are you sure you want to use the Joker ? „. Ukoliko se pritisne No, to jeste, ukoliko se odbije joker, onda se ništa ne desi, ukoliko se pritisne Yes , tek tada se vrši poziv iduće funckije checkPermission () , koja je funkcija koja provjerava da li data aplikacija ima dozvolu za korištenje mobitela da pozove nekoga iz kontakata ili ne, ukoliko nema dozvolu onda se traži od korisnika da dozvoli aplikaciji da napravi poziv, ukoliko data aplikacija već ima dozvolu , onda se pozove privatna funkcija callPhone () ,koja ažurira vrijednost jokera na 0 ( tj. iskoristili smo sada taj joker i više ne možemo) ,onda se kreira intent , gdje će se otvoriti phone da korisnik može nazvati na određeni broj. </div> ## 2. TitleFragment <div style="text-align:justify"> Kad se klikne na dugme Play , uzima se vrijednost, koja se nalazi u input-u za broj pitanja koji korisnik želi, ukoliko taj broj nije validan, onda se prikazuje Toast sa porukom sadržaja „ Enter a valid number „ , ukoliko jeste validan onda tražim koji je aktivan Radiobutton od ona tri, koja određuju težinu pitanja , tj. koji level je korisnik izabrao ( po defultu bude „ easy “ level ). Nakon toga prelazi se na sljedeći fragment ,tj. GameFragment. U tom fragmentu ( TitleFragment ) također override -am funkciju onCreateOptionMenu () , koja će mi kreirati option menu. Također override -am i funkciju onConfigurationChanged () ,koja će se pozvati kad se promjeni orijentacija ekrana, tada želim da mi bude prikazan landscape layout , ukoliko je orijentacija landscape - horizontalna, te Portraid ukoliko je orijentacija portraid - vertikalna. </div> ## 3. GameFragment <div style="text-align:justify"> Prvo definišem klasu Question, koja ima sljedeće atribute: text ( tekst pitanje ) , answers ( lista koja sadrži odgovora ) , type ( 0 ukoliko je riječ o tekstualnom odgovoru i 1 ukoliko je riječ o višestrukomi odgovoru ) , indexCorrect ( lista koja sadrži index tačnih odgovora – prazna je ,ukoliko je tip pitanja0 tj. ako je tekstualni odgovor u pitanju ) , level ( koja je težina pitanje ). Onda definišem listu pitanja u varijabli questions ( trenutno imam 12 pitanja ) . U onCreateView ( inflater : LayoutInflater , container : ViewGroup? , savedInstanceState : Bundle? ) : View? pozove se funkcija chooseQuestions ( ) koja će kreirati finalnu listu pitanje , onda ću ih korisniku prikazati i to je na sljedeći način: prvo provjeravam koliko imam pitanja za određeni level, kojeg je korisnik izabrao i dodam ta pitanja u varijablu finalQuestionsList . Na kraju, ukoliko je broj pitanja koji korisnik tražio veći nego broj pitanja koji sam našao, onda mu se prikaže Toast da će max broj pitanja biti broj pitanja koje trenutno imam. Ukoliko broj pitanja koji korisnik tražio je manji nego broj pitanja koje trenutno imam, onda od te liste uzmem prvih n pitanja ( neka je n broj pitanja koji je korisnik tražio ). Onda pozovem funckiju showQuestion ( ) , koja će prikazati pitanju i ažurirati tekst u Action bar-u. Ukoliko je tip 0 tj. tekstualni odgovor onda ću prikazati EditText i skloniti RelativeLayout koji sadrži 4 checkBox-a , u suprotnom, prikažem taj RelativeLayout i sklonim EditText. Jos mi ostane šta će se desiti kada korisnik pritisne na dugme Submit. Tada prvo provjeravam tip trenutnog pitanja, ukoliko je tip 0 onda provjeravam da li tekst ( odgovor ) koji je korisnik napisao je sadržan u odgovorima trenutnih pitanja i ukoliko jeste, onda povećam score za 1 tj score ++ . Ukoliko je tip 1 tj. višestroki odgovori onda u listu checked dodam index svih check button-a koji su čekirani i provjeravam da li ta lista jednaka listi tačnih odgovora trenutnih pitanja, ukoliko jeste onda povećam score za 1 tj score ++ . Nakon toga povečćam index trenutnih pitanja za 1 i ukoliko nisam došao do kraja onda pozovem ponovo funkciju showQuestion ( ) , koja će mi ovog puta prikaziti sljedećeu pitanje. Ukolio sam došao do kraja, onda idem na fragment GameWonFragment gdje će rezultat biti prikazan. </div> ## 4. GameWonFragment <div style="text-align:justify"> Tu override-am funkciju onCreateOptionsMenu ( menu : Menu , inflater : MenuInflater ), koja će mi kreirati share menu. Ukoliko kliknem na share menu, tada će se pozvati funkcija shareSuccess ( ) ,koja će mi početi intent koji kreira funkcija getSharedIntent ( ) , ta funckija će mi kreirati i poruku, koja će se dijeliti ( share-ovati) . Također override-am i funkciju onConfigurationChanged () ,koja će se pozvati kad se promjeni orijentacija ekrana, tada želim da mi bude prikaženo landscape layout ukoliko je orijentacija landscape, te Portraid ukoliko je orijentacija portraid. Sada imamo onCreateView ( inflater : LayoutInflater , container : ViewGroup? , savedInstanceState : Bundle? ) : View? gdje generišem tekst koji će biti prikazan u textView tj. koliko tačnih pitanja od koliko ukupno pitanja i da li je korisnik iskoristio joker ili nije . Ukoliko pritisnem na dugme Next Match, onda idem na TitleFragment i tu mogu izabrati težinu pitanja te broj pitanja i početi igru ponovo. </div> ## 5. RulesFragment <div> Ovdje nisam dodao nista. </div> ## 6. AboutFragment <div> Ovdje također nisam dodao nista. </div>