8 Commits
Author SHA1 Message Date
lgcosta cccba68036 chore(release): bump v0.4.1 (versionCode 8)
fix(sync) 5xx -> Transient com retry; runSync trata Failed/NotConfigured;
SSE multilinha; ApiClient sem imports mortos.

Verificado: testDebugUnitTest + assembleDebug + assembleRelease limpos
(JDK 21 / AGP 8.13.2 / SDK 36).
2026-11-06 10:38:08 -03:00
lgcosta 81e945b490 build: toolchain AGP 8.13.2 + Kotlin 2.2.20 + SDK 36 (v0.4.0)
- Gradle wrapper 8.11.1 -> 8.13 (exigido pelo AGP 8.13)
- AGP 8.7.3 -> 8.13.2; Kotlin 2.0.21 -> 2.2.20; KSP -> 2.2.20-2.0.4
- compileSdk/targetSdk 35 -> 36 (Android 16 como alvo real)
- Compose BOM 2025.06 -> 2026.06 (material3 1.4.0 estável; Expressive
  completo segue beta em 1.5.x e fica de fora a pedido: só estável)
- activity-compose 1.10.1, navigation-compose 2.9.0, lifecycle 2.9.0
- Room 2.6.1 -> 2.8.3; WorkManager 2.9.1 -> 2.10.1; DataStore 1.1.7
- kotlinx-serialization 1.8.1; coroutines 1.10.2
- versionCode 7 / versionName 0.4.0

Verificado: testes unitários verdes; APKs debug+release OK; em Android 16
(API 36, Pixel 6) upgrade in-place, criar nota -> autosave -> Room -> lista,
editor e chips de modo/formato sem crashes. README atualizado.
2026-11-06 08:48:16 -03:00
lgcosta 641c374a03 fix(build): restaurar targetSdk=35 perdido no bump da v0.2.2
Sem targetSdkVersion no manifest, o AGP usou minSdk (26) como alvo:
o instalador do Android 16 (One UI 8) bloqueia o APK como 'versão
antiga do Android'. Restore targetSdk=35 + versionCode 6 / 0.3.1.

Verificado em emulador Android 16 (API 36, Pixel 6): install sem
bloqueio, boot limpo, fluxo config -> lista -> status/busca/empty state.
2026-11-05 22:09:50 -03:00
lgcosta a8c8a5a998 feat(ui): modernização visual Material 3 (v0.3.0)
- Edge-to-edge (enableEdgeToEdge) com Scaffold/insets em todas as telas
- Compose BOM 2024.12 -> 2025.06; tipografia e tema com dynamic color
- SyncBanner colorido removido -> SyncStatusRow compacto com chips M3
  acionáveis (sync agora / abrir config / erro em errorContainer)
- Lista: busca por título/conteúdo/tag (filterNotes testado),
  pull-to-refresh, animateItem, contentType, estado vazio com CTA
- Ícones no lugar de emoji (pasta, presença, exclusão, aviso)
- Editor: chip de presença acessível; imports limpos
- Teste unitário de busca (NoteSearchTest)
- versionCode 5 / versionName 0.3.0
2026-11-05 21:48:16 -03:00
codeall 8561ae2f8b fix: robustez de sync e cancelamento (v0.2.2)
- SyncEngine: CancellationException volta a propagar (não vira erro falso)
- SyncWorker: Failed (4xx/5xx) agora é failure, só NetworkDown retenta
- ApiClient: métodos suspend com delay() em vez de Thread.sleep
- SseClient: cancelamento fecha o socket; parse tolera 'data:' sem espaço
- Room v3: migração real 2->3 (índice único outbox) sem apagar a fila
- versionCode 4 / versionName 0.2.2
2026-11-05 21:02:10 -03:00
lgcosta 57edfbe4df feat: exclusão de notas na UI (lista e editor) com confirmação e sync
- Botão 🗑 no card da lista e na barra do editor; AlertDialog de confirmação
  explicando o efeito (remoto sobe na sync; local-only some direto)
- Exclusões já eram enfileiradas (pendingDelete + op delete) e o engine já
  tratava 404; propagação via SSE 'deleted' para outras sessões
- versionCode 3 / versionName 0.2.1; README atualizado
- Testado no emulador: delete pela lista → servidor 0 notas; delete pelo
  editor → idem, com volta à lista; pull de nota da Web e exclusão seguinte ok
2026-11-05 07:48:57 -03:00
lgcosta 400ab066b2 chore: versionCode 2 / versionName 0.2.0 (release v0.2.0) 2026-11-04 20:56:08 -03:00
lgcosta 2f63c7a2f5 feat: cliente Android offline-first (Kotlin + Jetpack Compose)
- Room (notes/outbox/categories/meta): edição 100% local, fila FIFO de mutações
- SyncEngine bidirecional: push (create/update com base_hash/delete, rekey de id
  local→servidor) + pull (categorias, notas divergentes, exclusões remotas)
- Conflito 409: servidor vence a nota + texto local preservado em cópia
  "Título (conflito)" enfileirada como create — nada perdido, sem relógios
- WorkManager: periódico 1h (rede + backoff exponencial), runNow único REPLACE
  em gatilhos (pós-save, rede restabelecida, boot, config, botão manual)
- OkHttp com timeout/retry em IOException; kotlinx.serialization; DataStore
- UI Compose: tela Servidor (URL+token+teste), Lista com banner de status
  (Offline/Sincronizando/Sincronizado/Erro/401 + pendências + conflitos),
  Editor com autosave por ociosidade (10 s) e categorias multi-seleção
- Build validado: assembleDebug (AGP 8.7.3/Kotlin 2.0.21/SDK 35, JDK 21) —
  app-debug.apk 17,6 MB; gradle-wrapper.jar fora do commit (regenerável com
  `gradle wrapper`, documentado no README)
2026-11-04 17:55:50 -03:00