$cat ~/posts/check-in-binario

bilíngue · en / pt

← /blog

check-in binário


O Plano já tem um post aqui, com o porquê, o prazo e o preço em horas. Esse é sobre a ferramenta: o app Android que eu construí pra acompanhar aquilo todo dia, por que ele é do jeito que é, e uma ideia que sobrou no fim, quando eu já estava dentro do Kotlin e não queria mais sair.

por que planilha não segura isso

$ quote ~/posts/o-plano

Não construí isso pra mostrar pra ninguém. Construí porque planilha não segura esse tipo de disciplina, e eu precisava de alguma coisa que me encarasse todo dia com o número real.

O Plano2026-09-09pt

O problema da planilha não é ela ser simples demais. É ela ser obediente demais. Ela aceita qualquer número que eu digitar, inclusive os que eu digito de mau humor às onze da noite pra fechar a semana num lugar decente. Eu já tinha feito isso antes e sabia exatamente como termina: a planilha continua linda e o estudo não aconteceu.

O que eu precisava era de uma coisa que não negociasse. 492 horas até 30 de junho de 2027, espalhadas em 32 selos. Esse número não é motivacional, é aritmético, e a única função do app é deixar ele visível todo dia sem me deixar mexer nele.

estudei ou não estudei

O check-in é binário. Estudei na Coursera hoje, ou não estudei. Sem cronômetro, sem campo de duração, sem anotação, sem progresso parcial.

Isso foi a primeira decisão e é a que sustenta o resto. No minuto em que existe um campo de duração, ele vira negociação: quarenta minutos distraído com vídeo em 1.75x viram "uma hora", e uma hora dessas some no meio de outras trezentas. Binário não tem o que negociar. Ou o dia aconteceu ou não aconteceu.

A segunda decisão foi a janela: dá pra marcar e desmarcar o dia atual e os seis anteriores, e só. Sete dias é mais ou menos o quanto eu consigo lembrar com honestidade. Passou disso, virou reconstrução, e reconstrução de memória sempre sai generosa com quem reconstrói.

o Muro

A tela que eu mais uso chama Muro, e ela responde uma pergunta só: eu tô atrasado?

Ela mostra quanto falta das horas, o ritmo teórico pra fechar dentro do prazo, um semáforo, e um burn-down em escada. A conta em si não tem nada de esperto:

val restantes = totalPlanejado - concluidas - cortadas
val semanas = ChronoUnit.WEEKS.between(hoje, FIM)
val ritmo = restantes / max(1, semanas)

O que ela tem é de não poder ser editada por mim. E o gráfico é escada, não rampa, porque o progresso real é discreto: as horas do Muro só caem quando um curso é concluído. Check-in não derruba hora nenhuma. Sequência de trinta dias seguidos com zero curso fechado aparece exatamente como o que é, uma linha horizontal comprida, e é desconfortável do jeito certo.

Tem uma válvula, e ela é declarada: grupo_corte, no banco. Dá pra cortar um item planejado e as horas dele saem do Muro. Isso não é trapaça, é a mesma decisão que eu já tinha tomado na mão quando o boot.dev saiu da trilha principal por causa do prazo. A diferença é que agora o corte fica registrado como corte, em vez de virar uma meta que silenciosamente encolheu.

o que tem por baixo

Kotlin, Jetpack Compose, Material 3, Navigation 3. Room por baixo, Hilt pra injeção, StateFlow pro estado, WorkManager pro lembrete. minSdk 26, targetSdk 36, package dev.nuxyel.oplano, MIT, código no GitHub.

O banco, o_plano.db, tem sete tabelas: trilha, ordem, grupo_corte, item, selo, checkin e config. A modelagem espelha a estrutura d'O Plano em vez de inventar uma abstração genérica de hábito, e isso foi de propósito: o app não serve pra mais nada, não precisa fingir que serve.

A única parte que me deu trabalho de verdade foi a migração do Room preservando os dados da v1.0. É um app pessoal, com um usuário, e mesmo assim eu não podia dropar a tabela e recomeçar, porque o histórico é o produto. O valor daquilo ali não é o código, é a fileira de check-ins desde julho. Perder isso pra reorganizar schema seria perder a única coisa que o app tem.

As telas são quatro: Hoje (o item da vez, os sete dias editáveis, a sequência), Muro, Trilhas (com corte e restauro) e Selos, que é uma linha do tempo das credenciais. Mais o detalhe do item, que é onde mora a parte chata: carga planejada, datas, estado, conclusão.

o que eu não construí

Sem login, sem backend, sem telemetria, sem sincronização, sem acesso à rede. Sem export, sem import, backup automático do Android desligado.

Os dados existem só na instalação atual. Se eu perder o aparelho, perco o histórico inteiro, e eu decidi aceitar isso conscientemente em vez de resolver com um Firebase que me custaria uma tarde e um vínculo permanente. O app é pra mim, roda no meu aparelho, e a fronteira dele é o vidro.

a ideia que sobrou

Terminado o app, sobrou uma coisa que eu não esperava: vontade de continuar em Kotlin.

Não é sobre Android. É que fazia tempo que eu não escrevia numa linguagem tipada, compilada e chata no bom sentido, depois de meses em Python, e isso mexeu com uma pergunta que agora tá parada na minha cabeça como possível TCC: dá pra fazer machine learning e visão computacional em Kotlin nativo, sem lib externa? Sem TFLite, sem ML Kit, sem OpenCV, sem chamar nada em C++ por baixo. A convolução escrita na mão, a extração de features escrita na mão, tudo na JVM.

Eu não pesquisei a viabilidade disso. Nem um pouco. Não sei se é um TCC ou se é uma tarde de frustração com um benchmark trinta vezes mais lento que o baseline e nenhuma conclusão interessante no fim. Não sei se já existe literatura, não sei onde a JVM quebra em operação de matriz de verdade, não sei se o recorte certo é implementar do zero ou rodar on-device sem depender de terceiro. São perguntas diferentes e elas dão TCCs diferentes.

O que eu sei é por que a ideia me atrai, e é o mesmo motivo de sempre: é fundamento, não ferramenta. Chamar model.predict() não me ensina o que a convolução faz. Escrever a convolução ensina. Se no fim a resposta for "é inviável e aqui está o motivo", isso também é um resultado, e é um resultado que eu ia entender de ponta a ponta.

Fica registrado como o que é: uma ideia crua, com viabilidade não checada, anotada no dia em que ela apareceu. Daqui uns meses eu volto aqui e vejo se ela sobreviveu ao contato com a realidade.