====== 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]]