# Dokumentacija
# Opši koncepti Android frameworka
# Jetpack Compose
#### Jetpack Compose je moderni set alata za jednostavnije kreiranje Android UI-a. Komponente pojednostavljuju i ubrzavaju razvoj UI-a na Androidu sa manje koda, moćnijim alatima, i intuitivnim Kotlin mogućnostima. Sa komponentama, možemo kreirati svoj UI tako što definišemo set funkcija, koje zovemo composable funkcije, koje uzimaju podatke i prikazuju UI elemente.
# UI Aplikacije
#### UI aplikacije je sve što vidimo ns ekranu: tekst, slike, dugmiće/buttone, i razne druge elemente, i kako su oni raspoređeni po ekranu. To je ustavri način na koji aplikacija pokazuje stvari korisniku i način na koji korisnik ima interakciju sa aplikacijom. Svaki od navedenih elemenata se nazivaju UI komponente. Skoro sve što vidimo na ekranu naše aplikacije je UI element tj komponenta. Mogu biti interaktivne, mogu imati mogućnost da se klikne na njih kao što dugmići, ili ih možemo uređivati kao što su input polja.
# Composable funkcije
#### A composable funkcije su osnovni gradivni blok UI. Composable funckije: opisuju jedan dio našeg UI, ne vraćaju ništa, uzimaju neki input i generišu šta se treba prikazati na ekranu, te mogu prikazat više UI elemenata.Što znači da za kreiranje UI pišemo composable funkcije, to su samo obične funkcije sa anotacijom @Composable, koja govori composu da doda posebnu podršku funkciju za updatovanje i održavanje našeg UI tokom vremena. Anotacija znači da dodajemo neke dodatne informacije kodu. Ta informacija pomaže alatima kao što Jetpack Compose compiler, i drugim developerima da razumiju kod.
# UI Hijerarhija
#### UI Hijerarhija je bazirana na tome da jedna komponenta može sadržavati jednu ili više drgih komponenata, pa tako ponekad koristimo izraze roditelj i dijete.Što znači da roditeljskii UI elemnt može imati jedno ili više djece odnosno UI elemenata. Tri glavna standardna layout elementa su Column, Row i Box, koji se mogu ponašati kao rodiljeski UI elementi.
#### Column će sve svoje elemente poravnati odnosno poredati vertikalno, dok će Row sve svoje elmente poravnati odnosno poredati horizontalno.
# Layout Modifajeri
#### Modifajeri se koriste da uredimo i dodamo neke osobine kako će se Jetpack Compose UI elemet ponašati. Naprimjer pomoću njih možemo dodati pozadinu, padding, ili neke akcije na redove, tekst ili dugmiće. Da bi uopšte mogli postaviti i korsitit Modifajere, ta komponenta ili layout moraju prihvatiti modifajer kao svoj parametar.
# LazyColumn
#### Sa dolaskom Jetpack composa, došla je i lazy column, koja je deklarativni UI alat. LazyColumn je komponenta vertikalne liste koju možemo skrolati.
#### Napravljena je tako da efikasno rukuje velikim listama(listama koje imaju mnogo stavki/item-a) tako što renda/iscrtava samo vidljive stavke/item-e na ekranu, što pomaže u optimizaciji memorije i performansi. Koristeći LazyColumn, možetemo efikasno prikazati duge liste podataka bez potrebe da učitavate i prikazujete sve stavke odjednom.
# Jetpack Compose podržava MVVM.
#### MVVM je skraćenica za Model-View-ViewModel. To je softverski patern koji se obično koristi u razvoju user interface (UI), posebno u kontekstu grafičkih user interface (GUI) i web aplikacija.
### U MVVM paternu, aplikacija je podijeljena u tri glavne komponente:
#### Model: Model predstavlja podatke i poslovnu logiku aplikacije. On enkapsulira podatke i operacije/akcije koje se izvode nad podacima. Drugim riječima, model definira strukturu i ponašanje podataka koji se koriste u aplikaciji.
#### View: View je odgovoran za predstavljanje user interface-a korisniku. Definiše vizualne elemente i izgled user interface-a.
#### ViewModel: ViewModel djeluje kao posrednik između view-a i modela. Sadrži logiku prezentacije i izlaže podatke iz modela na način koji je lahko iskoristiti u pogledu. ViewModel također upravlja interakcijama korisnika i u zavisnoti od tih interkacija ažurira model. Pruža mehanizme povezivanja podataka kako bi view/pogled i model bili sinhronizirani.
#### Jedna od glavnih prednosti MVVM-a je njegova mogućnost da povezuje podatke, što omogućava da se promjene u ViewModelu automatski reflektuju u view-u, i obrnuto, bez eksplicitnih poziva ažuriranja. Ovo pojednostavljuje razvoj user interface-a i smanjuje količinu standardnog koda(boiler plate code-a) potrebnog za sinhronizaciju.
### Imamo tri sloja: UI Layer, Domain Layer(on je opcionalan) i Data layer.
## UI Layer
#### Uloga UI Layera je da prikaže podatke aplikacije na ekranu. Kada god se podaci promjene, prilikom korisnikove interakcije sa aplikacijom, kao što je naprimjer klik na dugme UI treba da update-a te promjene. UI layer/sloj se sastoji od: UI elemenata to su komponente koje rednaju/iscrtavaju podatke na ekran, a mi pravimo ove komponente koristeći Jetpack compose. State holders to je komponenta koja "drži" podatke i prikazuje ih na UI te se bavi logikom aplikacije to je naprimjer ViewModel.
#### ViewModel pohranjuje podatke u vezi aplikacije koje se ne uništavaju kada se aktivnost uništi i ponovo kreira od strane Android frameworka. ViewModdel objekti se ne unište. Aplikacije automatski zadržava ViewModel objekte tokom promjena konfiguracije, tako da su podaci koje oni drže dostupni odmah nakon rekompozicije.
## UI elemeni zajedno sa UI Stateom čine UI.
#### UI je ono što korisnik vidi, a UI State je ono što aplikacija kaže da trebaju vidjeti UI je ustvari vizuelni prikaz UI Statea. Bilo koja promjena UI statea odmah se reflektuje na UI.
#### StateFlow je data holder("drži podatke") obervable flow koji prikazuje trenutne i nove update. Vrijednost njegovog propertija se reflektuje na vrijednost trenutnog stanja, da bi updateovali stanje i poslali ga u flow koristimo klasu Mutablesate flow.
#### UDF undirectional data flow: state flow down, event flow up
# Lifecycle aktivnosti
#### Lifecycle aktivnosti je skup stanja kroz koje prolazi aktivnost. Životni ciklus aktivnost počinje kada Android OS prvi put kreira aktivnost, a završava kada OS uništi aktivnost.
#### Kada user navigira između aktivnosti, unutar ili van naše aplikacije, svaka aktivnost se pomjera iz stanja u stanje lifecycle. Svako stanje lifecyle ima odgovrajuću callback metodu, koju možemo i override u Activity klasi. Osnovni skup lifecyle metoda su: onCreate(),onRestart(),onStart(),onResume(),onPause(),onStop(),onDestroy().Da bi dodali ponašanje koje će se desiti kada aktivnost pređe u drugo stanje, trebamo override callback metodu.
### Detaljniji opis gore navedenih metoda:
#### onCreate(): Ova metoda se poziva kada se aktivnost prvi put kreira.
#### onRestart(): Ova metoda se poziva kada se aktivnost ponovo pokreće nakon što je zaustavljena. Slijedi onStop() i poziva se prije onStart(). Omogućava nam da izvršimo sve potrebne radnje za ponovno pokretanje aktivnosti, kao što je osvježavanje podataka ili ponovno pokretanje komponenti.
#### onStart(): Ova metoda se poziva kada aktivnost postane vidljiva korisniku. Priprema aktivnost za ulazak u prvi plan.
#### onResume(): Ova metoda se poziva kada aktivnost započne interakciju s korisnikom. To je posljednja metoda koja se poziva prije nego što aktivnost postane aktivna u prvom planu. Koristi se za nastavak svih operacija/akcija ili resursa koji su pauzirani ili zaustavljeni u onPause().
#### onPause(): Ova metoda se poziva kada aktivnost više nije u prvom planu i izgubi fokus. Obično se koristi za pauziranje ili oslobađanje resursa, spremanje korisničkih podataka ili obavljanje bilo kojeg drugog potrebnog čišćenja prije nego što aktivnost pređe u pozadinu.
#### onStop(): Ova metoda se poziva kada aktivnost više nije vidljiva korisniku. Obično se koristi za oslobađanje resursa koji nisu potrebni dok aktivnost nije vidljiva.
#### onDestroy(): Ova metoda se poziva kada se aktivnost uništava ili zatvara. To je konačna metoda koja se pozove u životnom ciklusu aktivnosti. Obično se koristi za oslobađanje svih resursa koji se tiču aktivnosti.
#### Ove metode nam omogućavaju upravljanje životnim ciklusom i stanjem naše aktivnosti, omogućavaju nam da kontrolišemo njeno ponašanje u različitim fazama. Implementacijom ovih metoda možemo osigurati da se naša aktivnost ponaša ispravno i efikasno tokom svog životnog ciklusa.
# Lifecycle of composable
#### U ovom slučaju imamo dva bitna pojma Initial/početna Composition i Recomposition.Kada Jetpack Compose run/pokrene naše komponente prvi put tokom inicijalne/početne kompozicije,i voidt će računa o komponentama koje smo pozvali da opišemo naš user interface. Kada se stanje naše aplikacije promjeni Jetpack Compose će odraditi rekompoziciju, rekompozicija je kada Jetpack Compose ponovo izvrši funkcije koje su se promjenile i onda će se updatovati i te promjene će se odraziti na UI.
# Configuration Changes
#### Promjena konfiguracije se dešava kada se stanje uređaja promjeni toliko da je najlakši način na sistem riješi promjenu je da uništi i ponovno izgraditi aktivnost. Najčešći primjer je kada korisnik roitra uređaj ili se promjeni jezik uređaja. kada dođe do promjene konfiguarcije, Android poziva sve povratne pozive za isključivanje lifecyle. Android zatim ponovo pokreće aktivnost ispočetka. Kada Android zbog promjene konfiguracije on ponovno pokreće aktivnost pomoću metode onCreate().Da bi sačuvali promjene koje trebaju da prežive promjenu kofiguarcije, te varijable deklariramo sa RememberSavebale.
# Navigacija
#### Navigaciona komponenta ima tri glavna dijela:navController, navHost i navGraph.
#### navController je zadužen za navigaciju između destinacija odnosno ekrana u našoj aplikaciji, te da se brine o backstacku i state/stanju composable ekrana. Sljedeći dio je NavGraph, NavHost on djeluje kao kontejener za prikaz trenutnog odredišta NavGrapha,njegova uloga je da definiše navigacioni graf, drugim riječima u navHostu ćemo definisati sve naše ekrane, rute, argumente i sve ostalo što je potrebno da bi navigacija radila kako treba.
#### Jedan od osnovnih koncepata navigacije u Compose aplikaciji je ruta. Ruta odgovoara odredištu. Ova ideja je slična konceptu URL-a. Baš kao što različiti URL-ovi mapiraju tj. odvode nas na drugu stranicu na web aplikaciji, i u ovom slučaju ruta nas odvodi na destianciju i služi kao jedinstveni indetifikator.
#### Destinacija/odredište je obično jedan Composable ili grupa više Composable koji odogovara onom što korisnik vidi.
#### U aplikaciji postoji konačan broj ekrana/screenova, tako da postoji i konačan broj ruta.
#### Rute možemo i zapravo ih definiramo u enum klasi ili sealed klasi. Enum klase u Kotlinu imaju name property koji vraća string sa tim name propertijem. U Kotlinu,sealed klasa je posebna vrsta klase koja predstavlja ograničenu hijerarhiju klasa ili stanja. Koristi se za definiranje zatvorenog skupa potklasa koje su poznate u vrijeme kompajliranja.
#### NavHost je composable koji prikazuje druge composable destinacije/odredišta, na osnovu date rute.
#### navController je instanca NavHostController klase, onda možemo koristit ovaj objekat da navigiramo to jeste da se krećemo između ekrana, tako što pozovemo navigate() metodu i time navigiramo na drugu destinaciju/odredište. Možemo dobiti NavHostController tako što pozovemo rememberNavController() iz composable funkcije.
#### startDestination to je string ruta koja definira destinaciju koja se prikazuje po defaultu kada aplikacija prvi put prikaže NavHost.
#### Unutar sadržaja funkcije NavHost-a, pozivamo composable() funkciju. Composable funkcija prima dva parametra.
#### routa - string koji je korespondan sa imenom rute, ovo može biti bilo koji jedinstveni string. Koristit ćemo one name propertije iz enum klase.
#### content- ovdje mmožemo pozvati composable koje želimo prikazati na datoj ruti.
#### composable() funkciju pozivamo za svaku rutu.
#### remeberNavController() je odgovoran za navigiranje između ruta.
# Opis rada aplikacije sa slikama
## Prikaz uvodnog dijela
# 
#### Početni ekran se sastoji od jedne slike, dva tekstualna polja, i jednog dugmića. Drugim riječima roditeljska komponeneta u ovom slučaju je Column, unutar nje se nalati Image() komponenta, dvije Text() komponenta i jedan Button() koji nas vodi na Meni ekran. Komponenta Column prima modifier koji kaže da će ova komponenta zauzeti cijelu širinu i visinu ekrana, i da će njena djeca, tj komponente unutar nje biti centrirane.
# 
#### Bočni ili side menu, se u našem slučaju sastoji od četiri itema koji nas vode na određene rute, tačnije na Home, Listu gradova, Računanje najkraćeg puta, i Opće informacije o aplikaciji. Za ovaj side meni prvo smo napravili Appbar composable funkciju, koja prima tekst u našem slučaju naziv aplikacije, i tu smo definisali da kliknom na Icon.Menu (odnosno ikonicu koja se nalazi u lijevom ćošku) prikaže side meni. Zatim smo kreirali još dvije composable funkcije DrawerHeader i DrawerBody, u njima smo definirali izgled našeg drawer odnosno side menija. Za DrawerBody korisitli smo LazyColumn u slučaju da imamo više item-a. Drawer-u tj. side meniju možemo pristupiti sa svakog ekrana naše aplikacije.
#### Za ekran sa menijem kreirali smo MenuScreen composable funkciju koja se sastoji od jedne Column komponente, a u njoj se nalazi jedno tekstualno polje i dva dugmića. Column komponenta prima modifier koji kaže da će ova komponeta zauzeti cijeli širinu i visinu ekrana, i da će djeca odnosno komponente unutar nje biti centrirane.
# 
#### Prvo šta možemo odabrati sa menija je da nam se prikaže lista gradova.
# 
#### Za kreiranje ova liste koristili smo LazyColumn. Prije svega kreirali smo data class City u kojoj se nalaze varijable od kojih se sastoji jedan grad. Zatim imamo class CityRepository, u kojoj imamo funkciju koja nam vraća listu naših gradova(sa svim podacima). Sljedeće što nam je potrebno sa ovu listu je da kreiramo jednu composable funkciju koju smo nazvali CostomItem, koja predstavlja jedan item naše liste. U ovom slučaju roditeljska komponenta je Row, prvo što imamo je Image() komponenta koja se nalazi u lijevom dijelu, zatim unutar Row komponente stavljamo Column() komponentu u koju smještamo ime grada i koordinate i na kraju izvan Column() komponente a unutar Row() komponente smještamo button koji će nas odvesti na ekran na kojem je prikazano više detalja o svakom pojedinačnom gradu.
# Kao što vidimo svaki item ove liste ima button "see more" koji nas vodi na sljedeći ekran na kojem možemo vidjeti detalje o svakom pojedinačnom gradu(detalji koji se ne nalaze u listi).
# 
#### Pored toga na ovom ekranu imamo dva button-a jedan nas vodi na prikaz grada na karti, a drugi na ekran na kojem će aplikacija za nas računati najkraću udaljenost između svoh gradova.
# 
# 
#### Na ovom ekranu imamo dugme koje pokreće algoritam. Rezultat algoritma vidimo na sljedećem ekranu.
# 
#### Također možemo vidjeti rutu i na karti.
# 
# OPIS ALGORITMA
#### data class City opisuje naš grad, između ostalog imamo podatak o longituditi i landitudi grada izražene naravno u stepenima, da bi ova dva podatka iskoristli za naš algoritam prvo te vrijednosti pretvorili u radijane, tj. za to imamo funkciju URadijane(), zatim smo prešli na računanje udaljenosti između dva grada koristeći Haversine formulu. Kotlin klasa Algoritam je naša glavna klasa u kojoj se odvija cijeli algoritam, imamo konstrukotr koji uzima kao parametar id grada iz kojeg trgovački putnik polazi, na početku imamo dvije varijable trenutnaNajmanjaUdaljenost koja je tipa Double i postavimo je na 0.0, druga varijabla je lista trenutnaNajkracaRuta (lista je mutable).
#### U konstruktorovom init bloku u varijablu gradovi se smještaju svi gradovi koristeći CityRepository().getAllData() metodu (koju smo ranije implementirali), a u varijablu grad smještamo početni grad do kojeg smo došli preko id-a. Ako početni grad postoji odnosno ako je vrijednost različita od null, računamo ukupnu udaljenost pozivajući izracunajUkupnuUdaljenost() metodu tako što joj proslijedimo listu gradova to je trenutnaNajmanjaUdaljenost. Zatim listu svih gradova dodjelimo varijabli trenutnaNajkracaRuta.
#### Sljedeće što algoritam radi je da mijenja početni grad sa prvim sljedećim gradom u listi tako što pozovemo zamjeniElemente() metodu. I na kraju se radi proces permutacije pozivanje metode permutacije() koja prima trenutnaNajkracaRuta, index 1, trenutnaNajmanjaUdaljenost, trenutnaNajkracaRuta.
## Detaljni opis rada metoda
#### Metoda "izracunajUkupnuUdaljenost" računa ukupnu udaljenost odeređene rute tako što iteriramo kroz listu gradova.Iteracija počinje od prvog grada i sabira udaljenosti između uzastopnih gradova metodom "izracunajUdaljenost" iz klase City i naravno vraća nam ukupnu udaljenost.
#### Metoda "zamijeniElemente" mijenja dva elementa na listi gradova. Uzima listu gradova i indekse elemenata za zamjenu i vrši zamjenu koristeći privremenu varijablu.
#### Metoda "permutacije" je rekurzivna funkcija koja generiše sve moguće permutacije gradova. Koristi vraćanje unazad za istraživanje različitih kombinacija.
#### Ako je trenutni indeks jednak veličini liste (svi gradovi su uzeti u obzir), izračunava se ukupna udaljenost trenutne rute.
#### Ako je izračunata udaljenost manja od trenutne najkraće udaljenosti, ažurira se trenutna najkraća udaljenost i ruta.Zatim se vraća iz trenutnog koraka rekurzije. U suprotnom, ponavlja se od trenutnog indeksa do kraja liste i radi sljedeće korake: mijenja trenutni element sa elementom u trenutnom indeksu pozivanjem metode "zamijeniElemente", vrši rekurzivni poziv metodi "permutacije", povećavajući indeks za 1.
#### Nakon rekurzivnog poziva, mijenja elemente nazad na njihove prvobitne pozicije kako bi održao redoslijed. Rekurzija se nastavlja sve dok se ne generišu sve moguće permutacije.
#### U konačnici,ovaj algoritam pokušava sve moguće permutacije gradova i izračunava ukupnu udaljenost za svaku permutaciju. Prati trenutnu najkraću udaljenost i odgovarajuću rutu. Algoritam traži sve permutacije kako bi pronašao najkraći put za dati skup gradova. Međutim, ovaj pristup postaje neefikasan za veći broj gradova zbog vremenske složenosti generisanja svih permutacija.
#### Drugi button koji možemo odabrati sa menija odvodi nas na sljedeći ekran.
# 
#### Na ovom ekranu su prikazane opće informacije o aplikaciji. U svrhu ovog ekrana napravili smo još jednu composable funkciju DetailScreen. Roditeljska kompoenta je opet Column, što je specifično za ovu fuknciju je što imamo uslov kada je orijentacija ekrana portrait i u tom slučaju definisan raspored elemenata na ekranu, i također za slučaj kada je orijentacija landscpace(to smo uradili preko when uslova, što možemo vidjeti na slici ispod). Još jedan stvar vezana za ovaj ekran je što je njegov tekst preveden na bosanski jezik, ukoliko u postavkama našeg uređaja promjenimo jezik sa engleskog na bosanski, tekst sa ovog ekrana će se također promjeniti.
# 
#### Pored ostalog sa svako ekrana smo u mogućnosti korisiti share button iz app bara.
#### Implemntaciju share button-a uradili smo na sljedeći način, u Appbar komponenti dodali smo ikonicu za share, i omogućili da se klikom na tu ikonu pozove funkcija onShareClick(). Za dijeljennje informacija koristeći neke vanjske aplikacije koristimo intente, postoje dvije vrste eksplicitni i implicitni, mi smo u ovom slučaju korsitili eksplicitni.