Criando aplicativos para Android Wear OS com Jetpack Compose
Tags: android, mobile, ptbr, jetpack
Published: 2022-06-25 22:33:00

# Jetpack Compose no Wear OS
A Google recentemente anunciou na [Google I/O](https://android-developers.googleblog.com/2022/05/announcing-compose-for-wear-os-beta.html) o beta do Jetpack Compose para o Wear OS, a versão do Android para Smartwatch. Um dos principais foco do Compose é a criação de interface de maneira rápida usando sintaxe declarativa, semelhante ao que há no iOS com SwiftUI, hoje demostrarei a criação de um simples aplicativo em poucos minutos utilizado o que há de mais moderno para desenvolvimento de aplicativos para Android.

## O Aplicativo
O aplicativo que vamos desenvolver consiste em controlar a quantidade de copos de água você tomou ao logo do dia, para isso vamos precisar da versão mais recente do Android Studio, no meu caso estou utilizado o [Android Studio Electric Eel (2022.1.1) Canary 5](https://developer.android.com/studio/archive)

## Iniciando um novo projeto
Com Android Studio aberto vamos em criar um novo projeto
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hl1fbradprucewxyfwjj.png)

Na lista de template vai ter um chamando Wear OS >> Empty Compose Activity, selecionaremos e vamos continuar.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h0zf8g6qnu7zugf1v2ny.png)

O próximo passo é configurar o nosso app com nome, id, localização do projeto, e versão mínima do Android Wear OS. Para esse exemplo utilizaremos a API Level 30, conforme na imagem acima.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/826cr3lcnmf6u7rltlb2.png)

Vai ser gerado as seguintes arquivos e pastas, a customização no Compose não acontecer via os arquivos de resources (RES) em formato XML, em vez disso para diminuir a curva de aprendizagem boa parte do app é feito usado Kotlin, como a personalização do app que agora fica localizado em `/theme`, por enquanto vamos apenas trocar as cores.

```kotlin
package com.tiagodanin.waterwearos.presentation.theme

import ...

val Blue700 = Color(0xFF1976d2)
val Blue900 = Color(0xFF0d47a1)
val DeepPurple200 = Color(0xFFb39ddb)
val DeepPurple400 = Color(0xFF512da8)

internal val wearColorPalette: Colors = Colors(
    primary = Blue700,
    primaryVariant = Blue900,
    secondary = DeepPurple200,
    secondaryVariant = DeepPurple400,
    error = Color.Red,
    onPrimary = Color.Black,
    onSecondary = Color.Black,
    onError = Color.Black
)
```

Para isso basta informar na referência da variável `primary`, por exemplo, a nova cor que deseja. Nesse caso vou usar um Azul pois remete a água.

OBS: A função `Color` é a representação da cor em ARGB, exemplo vermelho (FFFF0000), é representado como `Color(0xFFFF0000)`.

## Criando a Tela
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tw417u3m3lcskeh4nnt1.png)
 
A tela principal já é criada por padrão ele fica localizando no `MainActivity.kt`, se rodamos o app no emulador (ou dispositivo físico) vamos ter a seguinte tela:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j2gb3shcqxapys6bgfxz.png)
 
O primeiro passo agora é criarmos a tela principal do nosso jeito, mas antes de adicionarmos elementos relacionados ao nosso aplicativo, precisamos mostra elemento comuns do sistema, nos smartphones temos a StatusBar (onde mostrar a hora) e NavigationBar, no Wear OS também temos algo semelhante que pode mostrar horas, indicador de página entre outros aspectos, ele é conhecido como [Scaffold](https://developer.android.com/codelabs/compose-for-wear-os#7):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6e5bi1nrs0gsux3jcvln.png)
 
```kotlin
@OptIn(ExperimentalWearMaterialApi::class)
@Composable
fun WearApp() {
    WaterWearOSTheme {
        Scaffold(
            modifier = Modifier
                .fillMaxSize()
                .background(MaterialTheme.colors.background),
            timeText = {
                TimeText()
            },
        ) {}
    }
}
```

Nosso Layout principal é montado da seguinte maneira:

- `WaterWearOSTheme { UI Compose }` é o nosso utilitário para aplicar o tema em todos os elementos de UI que tem dentro dele
- `Scaffold(Props) { UI Compose}` criar uma estrutura base de layout
    - `modifier: Modifier` Modificadores de layout e elementos comuns
    - `timeText = { UI Compose }` informar qual relógio será mostrado no topo
- `TimeText()` É layout padrão do relógio que fica no topo

Uma das vantagens do Jetpack Compose é a fácil customização de elementos já existentes, uma das maneiras mais simples de fazer isso é usando os modificadores (`Modifier`) que estão disponíveis na maioria dos componentes, como no caso do `Scaffold`, onde foi definido que ele ocuparia o máximo da tela (`.fillMaxSize()`) e teria um fundo na cor preta (`.background(MaterialTheme.colors.background)`). O Resultado que vamos obter é: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1589hhbrf7ypvlmv8snd.png)

Podemos prosseguir agora o app, vamos criar uma nova função de Compose para uma barra de progresso de quantidade de água tomada no dia, mas antes é preciso importar ela dentro do corpo do Scaffold.

```kotlin
@OptIn(ExperimentalWearMaterialApi::class)
@Composable
fun WearApp() {
    WaterWearOSTheme {
        Scaffold(
            modifier = Modifier
                .fillMaxSize()
                .background(MaterialTheme.colors.background),
            timeText = {
                TimeText()
            },
        ) {
            ProgressIndicatorWater() // Corpo
        }
    }
}

@Composable
fun ProgressIndicatorWater() {} // Nova UI Compose
```

Como já é de esperado há uma maneira de fazer a barra de progresso usando os componentes padrão do Compose, assim como no Jetpack Compose para smartphone, o nome dela é [`CircularProgressIndicator`](https://developer.android.com/reference/kotlin/androidx/wear/compose/material/package-summary#CircularProgressIndicator(kotlin.Float,androidx.compose.ui.Modifier,kotlin.Float,kotlin.Float,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.unit.Dp), e o que diferencia no Wear são poucas coisas, uma delas e a disposição dos elementos sobre a tela.

Vamos olhar uma parte da assinatura desse componente que estamos usando, no momento estamos da seguinte maneira o codigo

```kotlin
@Composable
fun ProgressIndicatorWater() {
    CircularProgressIndicator(
        startAngle = 360f,
        endAngle = 0f,
        progress = 0.5f,
        strokeWidth = 5.dp,
        modifier = Modifier
            .fillMaxSize()
            .padding(all = 10.dp)
    )
}
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hpqqu9wr2mj7g1svws1d.png)

O que precisamos para criar a nossa barra é saber onde posicionar, para isso precisamos entender algumas das propriedades da nossa tela.
- `startAngle` Ângulo de começo da barra
- `endAngle ` Ângulo de fim da barra
- `progress` O progresso total, onde `1.0f` é `100%` e `0.0f` é `0%`

A disposição dos ângulos é dada da seguinte maneira:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/riomv4dhxyepf9bqrj52.png) 

Com base nisso podemos finalizar a barra antes do texto da hora, configurando da seguinte maneira `startAngle = 295f, endAngle = 245f`:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lp5j5m6v97ali2530fv8.png)

Estamos perto do final, agora precisamos adicionar informações (litros tomados) e ação (beber água) para cada copo de água, para isso vamos fazer uma nova função de UI Compose e usar um elemento de layout flexível para alinhamento:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5pvi1qw5dcpapaqploc.png)

Os três principais elementos são:
- Box: elementos dentro do outros / Sobrepostos 
- Column: Um em baixo do outro (Coluna)
- Row: Um do lado do outro (Linha)

Queremos a seguinte estrutura no `ProgressIndicatorWater`
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qgp4pzvl7zp4u8xv1kry.png)

Para isso podemos usar o Box.

```kotlin
@Composable
fun ProgressIndicatorWater() {
    // Box para centralizar
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        CircularProgressIndicator(
            startAngle = 295f,
            endAngle = 245f,
            progress = 0.5f,
            strokeWidth = 5.dp,
            modifier = Modifier
                .fillMaxSize()
                .padding(all = 10.dp)
        )
        InfoWater() // Importação do novo Compose
    }
}

@Composable
fun InfoWater() {}
```

Já dentro do `InfoWater` precisamos de algo como `Column`
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xziva6xw6o33edjg9y6s.png)

```kotlin
@Composable
fun InfoWater() {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {}
}
```

E por fim adicionaremos os dois elementos de composição que planejavamos, nada diferente do que já é no Android Mobile com Jetpack Compose. O Botão e o Texto.

```kotlin
@Composable
fun InfoWater() {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        // Nosso texto
        Text(
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 30.dp),
            textAlign = TextAlign.Center,
            color = MaterialTheme.colors.primary,
            text = "Você já bebeu 1 litro de água hoje" // Texto
        )

        // Nosso botão
        Button(
            modifier = Modifier.padding(top = 5.dp),
            onClick = {
                      // Ação do click
            },
        ) {
            Icon(
                painter = painterResource(id = R.drawable.cup_water),
                contentDescription = "Cup Water",
                modifier = Modifier
                    .size(ButtonDefaults.DefaultButtonSize)
                    .wrapContentSize(align = Alignment.Center),
            )
        }
    }
}
```

O ícone em questão que importei não é padrão do kit de desenvolvimento, você pode baixa ele por fora, eu utilizo o [Material Design Icons Community](https://materialdesignicons.com/).

Depois de feito o donwload do SVG dele, no menu de opções da pasta `res`, selecione:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bjait8w89zuehhrzn2cw.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mi9ru24frdapntv3vez5.png)
  
Lembrando de que para importar você pode usar o mesmo nome, exemplo `R.drawable.[nome]`.


## Lógica
É por fim a parte lógica, criaremos um estado para quantidade de litros: 
`private val count: MutableState<Float> = mutableStateOf(0f)`

e vamos modificar a nossa barra de progresso para levar em conta que 3 litros é o ideal.

```kotlin
@Composable
fun ProgressIndicatorWater() {
    val recomedByDay = 3.0f // 3 Litros
    // Progresso = Todal do dia / Recomendação
    val progressOfDay: Float = count.value / recomedByDay

    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        CircularProgressIndicator(
            startAngle = 295f,
            endAngle = 245f,
            progress = progressOfDay, // Valor do progresso
            strokeWidth = 5.dp,
            modifier = Modifier
                .fillMaxSize()
                .padding(all = 10.dp)
        )
        InfoWater()
    }
}
```

O mesmo com nosso texto e botão, vamos mostrar a quantidade e no evento do clique do botão considera 500ml água ingerida.

```
@Composable
fun InfoWater() {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 30.dp),
            textAlign = TextAlign.Center,
            color = MaterialTheme.colors.primary,
            text = "Você já bebeu ${count.value} litro de água hoje" // Resultado
        )
        Button(
            modifier = Modifier.padding(top = 5.dp),
            onClick = { count.value += 0.5f }, // Ação
        ) {
            Icon(
                painter = painterResource(id = R.drawable.cup_water),
                contentDescription = "airplane",
                modifier = Modifier
                    .size(ButtonDefaults.DefaultButtonSize)
                    .wrapContentSize(align = Alignment.Center),
            )
        }
    }
}
```

Se abrimos o app novamente vamos o seguinte resultado
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/igp5bx6q2wo7q72y3hwk.gif)

---

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8vgzyskeom93jo1srcf.png)
 
No desenvolvimento desse app foram usados alguns dos componentes disponíveis do Jetpack Compose para Wear OS, no link abaixo você pode conferir diversos outros UI Compose:

[developer.android.com/training/wearables/compose](https://developer.android.com/training/wearables/compose)

---

Você pode seguir as implementações adicionado novas funcionalidade como persitencia de dados😉

Link do repositório: [Github.com/TiagoDanin/WearOS-Count-Water-App](https://github.com/TiagoDanin/WearOS-Count-Water-App/)