====== Jetpack Compose ====== > Jetpack Compose je predurčený pre tvorbu UI na platforme Android. > Využitie API Jetpack Compose pre Multiplatform popisuje článok: [[kotlin-compose-multiplatform|Compose Multiplatform]] ===== Úvod ===== Jetpack Compose je nástroj z produkcie **Google**. Používa sa pre tvorbu UI (GUI). Zároveň nahrádza pôvodnu deklaráciu formulárov a komponentov pôvodným XML definičnými súbormi za **deklaratívne** progromavanie, teda všetko je v jednom súbore a pomôcka je online zobrazovanie pri programovaní pomocou anotácie ''@Preview''. Postup tvorenia kódu je jednoduchý. Vzhľad používateľského rozhrania zobrazovaného na displeji sa postupne skladá z existujúcich, alebo vlastných komponentov. Vlastné komponenty taktiež prijímajú stavy a vysielajú udalosti pomocou Live dát, ktoré využívajú dátové modely. Coroutines následne umožňujú reťaziť zobrazenia a vstupy v krátkom kóde. > Komplexnosť komponentov ho predurčuje pre tvorbu [[kotlin-multiplatform|Multiplatform]] aplikácií pre Android, iOS, desktop, web (export projektu do Xcode, JVM, JavaScript). Príklad komponentov nástroja Jetpack Compose: tlačítka, textové polia a iné z Material Design 3. Jetpack Compose vyniká jednoduchosťou a dynamikou písaného kódu, rešpektuje modely dynamických dát, združuje kódy pod jeden jazyk - Kotlin a integruje pokročilé technológie: Room (DB), Hilt (vstrekovanie dát) a iné. developer.android : [[https://developer.android.com/develop/ui/compose/documentation|Ako začať s Jetpack Compose]] Príklad kódu, kde UI je v bloku ''setContent()'' : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text(text = "Hello World!") } } ===== Základné využitie - komponenty ===== Základné štrukturovanie kompozície je prvkami: * Column, FlowColumn * Row, FlowRow * Box **Modifikátory** umožňujú nastaviť rozmery, zarovnanie, odsadenie, interakcie a iné... Kompletná škála komponentov je na [[https://developer.android.com/develop/ui/compose/components|developer.android]] === Column() - komponenta === Zobrazí objekty pod sebou. Anotácia **@Preview** zabezpečí náhľad pre funkciu, ktorá by namala prijímať argumenty (okrem modifier) a odovzdávať hodnoty. @Preview @Composable fun ColumnTest() { Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth().background(Color.Cyan) ) { Text(text = "Hello") Text(text = "Android") } } === Row() - komponenta === Zobrazí objekty vedľa seba. Jednotka **dp** určuje veľkosť ktorá je nezávislá na hustote pizelov, **sp** sa škáluje na základe veľkosti textu zariadenia. @Preview @Composable fun RowTest() { Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().height(150.dp).background(Color.Cyan) ) { Text(text = "Hello") Text(text = "Android") } } === Card() - komponenta === Container pre ďalšie komponenty (Row(), ...) Card(modifier = modifier, colors = ...) { Row(...) { Icon(...) Column(...) { .. } } } === Iné komponenty === Link na developers je hore pod nadpisom... ↑ * ''Icon()'' - obrázok * ''Box() {}'' - kontajner pre iné komponenty * ''Button() {}'' - tlačítko s kontajnerom * ''TextButton() {}'' - tlačítko s kontajnerom * ''LazyColumn() {}'' - kontajner pre viditeľný zoznam položiek * ''item {}'' - definicia položiek pre ''LazyColumn()'' * ''OutlinedTextField()'' - orámovanie s menovkou * ''OutlinedButton(onclick = {...}, ...) {}'' - tlačítko s container pre TEXT() a iné * ''Checkbox()'' - zaškrtnutie voľby * ''Scaffold()'' - kontajner ==== Material Design ==== Jedná sa o designový jazyk. Tu je použitý **Material Design 3 (M3)**. V základe pre aplikáciu používame primárnu a sekundárn farbu - primárna farba je výraznejšia a použije sa pre hlavný prvok. Popis napríklad tlačítok používa aj on farby (v Theme.kt). Typologické pravidlá predpokladajú čo najmenšiu škálu použitých fontov. Pre výber vhodných fontov je možné využiť [[https://fonts.google.com/|Google Fonts]]. Pre zaoblené hrany komponentov sa využije **Modifier**. \\ Definície sú v: …/ui/theme/[Theme.kt, Color.kt, Type.kt] \\ Aplikovanie témy na kód: @Preview @Composable fun ColoredButton() { MyApkMaterialTheme { Button( onClick = { /*TODO*/ }, modifier = Modifier.clip(CutCornerShape(16.dp)), colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.primary) ) { Text( text = "Tlačítko", color = MaterialTheme.colors.onPrimary, modifier = Modifier.background(MaterialTheme.colors.primary) ) } } } ==== Stav aplikácie ==== Je akákoľvek hodnota, ktorá sa mení v čase, napríklad texty v textových komponentoch, dáta či anymácie. Stav v Compose sa ukladá príkazom **remember**, napríklad (takmer identické vyjadrenia): val mutableState = remember { mutableStateOf(value) } // i preferred var value by remember { mutableStateOf(value) } val (value, setValue) = remember { mutableStateOf(value) } === State hoisting === * Komponenta uchovávajúca stav aplikácie prijíma udalosti ([[https://developer.android.com/develop/ui/compose/state|Flow (Coroutines), LiveData, RxJava2, RxJava3, …]]) * Komponenta generujúca rozhranie prijíma stav aplikácie ┌──────────────────────────────────┐ │ Komponenta so stavom │ └──────────────────────────────────┘ ⬇ ⬆ Stav Udalosti ⬇ ⬆ ┌──────────────────────────────────┐ │ Komponenta vytvárajúca rozhranie │ └──────────────────────────────────┘ === Získanie stavu === val status = mutableState.value, príklad **získania stavu** v textovej komponente: OutlinedTextField( value = mutableState.value, label = { Text("your number") }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), onValueChange = { newInput -> mutableState.value = newInput } ) príklad **onClick** v tlačidle: fun OperationButton(modifier: Modifier = Modifier, text: String, onClick: () -> Unit = {}) { Button( onClick = { onClick() }, colors = ButtonDefaults.buttonColors(MaterialTheme.colors.secondary), modifier = modifier ) ... } ===== MVVM architektúra ===== Model-View-ViewModel je koncept pre udržateľné a škálovateľné (rôzne zdroje dát) aplikácie. Model oddeľuje používateľské rozhranie (GUI), dáta a iné komponenty. MVVM sa špecializuje na Android (inde je to MVC a podobne). **Vrstvy MVVM architektúry:** * **Model** - pre prácu s dátami (DB, YAML, …) * **View** - používateľské rozhranie (GUI), napríklad Compose * **ViewModel** - kontrolér, čiže prepojovacia vrstva medzi Model-View ┌──────┐ ┌───────────┐ ┌───────┐ │ View │◄-►│ ViewModel │◄-►│ Model │ └──────┘ └───────────┘ └───────┘ Compose Room ==== Plugin kapt pre SQL anotáci ==== Umožňuje používať anotácie pre metódy a vlastnosti SQL databáz. Modul **kapt je už nepraktický**, namiesto neho sa používa **ksp**. Knižnica **Room**, ktorá funguje s oboma modelmi. Pri potrebe použiť **ksp** odporúčam dohľadať príklady pre zápisy do: build.gradle.kts (prj) a build.gradle.kts (:app). \\ Link na migráciu z kapt na ksp: [[https://developer.android.com/build/migrate-to-ksp]] ==== Plugin ksp pre SQL anotácie ==== Umožňuje používať anotácie pre metódy a vlastnosti SQL databáz. === Inštalácia === aj napriek dostupným návodom s popisom manuálneho doplnenia buid súborov som testol možnosti správy modulov v projekte (AS) a funguje to spoľahlivo, nakoľko ponúka aktuálne knižnice, Teda zhruba tieto moduly treba nájsť a aplikovať: * menu settings -> Project structure -> Dependencies -> app -> + : pridať com.google.devtools.**ksp**.gradle.plugin:1.5.30-1.0.0, potom ho v libs.versions.toml uktualizovať na -> "2.2.0-2.0.2" -> SyncNow * ďalej pridať: **androidx.room**.gradle.plugin:2.8.0-alpha01 * taktiež sa v odporúča pridať: **androidx.room**.compiler ďalej upraviť: === build.gradle.kts (prj) === verzia musí byť zhodná s verziou Kotlin (v libs.version.toml) plugins { ... id("com.google.devtools.ksp") version "2.2.0-2.0.2" apply false } === build.gradle.kts (:app) === plugins { ... id("com.google.devtools.ksp") } compileOptions { // 17 is minimum sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = "17" } dependencies { ... ksp(libs.androidx.room.compiler.v272) } následne až v kóde budú použité metódy Room, tak potvrdiť import: @Entity => import room.common => build.gradle.kts(:app) \\ zárovaň sa upravuje automaticky aj blok dependencies {...} v build.gradle.kts(:app) a aj libs.versions.toml (kde občas treba potvriť vyššie verzie knižníc) ===== Knižnica Room ===== Je určená pre prácu s SQLite Android. Prevádza riadky na objekty a naopak. Základné komponenty knižnice: * **Entity** - riadok je objekt, stĺpec je atribút (vlastnosť, t.j hodnota) * **DAO** - (Data Access Object) operácie nad DB (INSERT, SELECT, UPDATE, DELETE, ...) * **Database Class** - objekt pre spojenie s DB. Obsahuje metódy pre získanie DAO a nastavenie parametrov Príklad použitia knižnice Room: import androidx.room.Entity import androidx.room.PrimaryKey /** 1. define data object and make entity : data/MyData.kt */ @Entity data class MyData( @PrimaryKey(autoGenerate = true) val recordId: Long? = null, // primary key val name: String ) // ... any functions for operations with entity /** 2. interface : data/MyDataDao.kt */ @Dao interface MyDataDao { @Query("SELECT * FROM MyData") fun getAll(): Flow> // Flow: see coroutines @Insert fun insert(myData: MyData) @Update fun update(myData: MyData) @Delete fun delete(myData: MyData) } /** 3. class of database : data/AppDatabase.kt */ @Database(entities = [MyData::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun myDataDao(): MyDataDao } /** 4. instance for all project : service/ServiceLocator.kt */ object ServiceLocator { private var _myDataDao: MyDataDao? = null val myDataDao: MyDataDao? get() = _myDataDao fun setMyDataDao(myDataDao: MyDataDao) { _myDataDao = myDataDao } } /** 5. application class : application/ExampleApplication.kt - need edit AndroidManifest.xml -> */ class ExampleApplication : Application() { override fun onCreate() { super.onCreate() val db = Room.databaseBuilder( applicationContext, AppDatabase::class.java, "myData-database" ).build() ServiceLocator.setMyDataDao(db.myDataDao()) } } Následne treba vytvoriť **ViewModel**, ktorý prepojí prezentačnú vrstvu s dátovou vrstvou (modelom), čím bude idea MVVM naplnená. Mal by obsahovať metódy nad dátami (získanie, vloženie, úpravu a mazanie) pomocou metód z rozhrania DAO. \\ Metódy nad dátami je vhodné realizovať v bloku ''init {...}'' pomocou coroutines: ''viewModelScope.launch {...}'' a uložiť do kolekcie(í). ===== Farby aplikácie ===== Postupy pre zmeny odporúča **Material Design 3**. Základný princíp je použitie **Primárnych** a ** Sekundárnych** farieb, ako pre svetlý, tak i pre tmavý režim zobrazenia. ==== Deklarácia farieb ==== Samotná deklarácia faireb je v ''ui/theme/Color.kt''. \\ Generovanie farieb môže zabezpečiť aj [[https://www.figma.com/community/plugin/1034969338659738588/material-theme-builder|Figma - Material Theme Builder]], alebo [[https://material-foundation.github.io/material-theme-builder/|Material Theme Builder]] na GitHub. ==== Deklarácia farebných schém ==== Samotná deklarácia tém je v ''ui/theme/Theme.kt''. \\ ==== Pridanie vlastných fontov ==== Ďalšie fonty je možné získať na [[https://fonts.google.com/specimen/Poppins?query=poppins|adrese Google]] \\ Pre ich použitie je treba stiahnuť zip a vytvoriť v AS: app -> new Android Resource Directory : font/font a doňho nakopírovať vybrané zo stiahnutého zip-u. \\ Samotná deklarácia tém je v ''ui/theme/Type.kt''. ---- ====== Linky ====== * https://www.jetbrains.com/compose-multiplatform/ * (original: https://www.jetbrains.com/lp/compose-desktop/) * https://www.jetbrains.com/kotlin-multiplatform/ * https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html * https://www.itnetwork.cz/kotlin/compose * developer.android.com - [[https://developer.android.com/courses/pathways/jetpack-compose-for-android-developers-1|video kurz]]