Este documento é o Manual de Execução Técnica do Crossbar. Ele traduz a visão do original_plan.md em tarefas de engenharia atômicas, granulares e verificáveis.
Status Atual: v1.14.0 (Build tooling & quality gates standardization) Próximo Ciclo: v1.14.1+ (Tray Icon Phases 2-3)
Nota: Epics completadas foram movidas para
ROADMAP.archive.done.md.
Antes de avançar, reconhecemos o que existe e o que falta para atingir a promessa do "Write Once, Run Everywhere".
- Core Architecture:
PluginManagereScriptRunnerfuncionam bem. - Documentation:
CODEBASE.mdprovides a comprehensive architectural guide. - Refresh Engine:
RefreshServiceunificado gerencia atualizações periódicas, manuais e background de forma consistente. - CLI Foundation: Estrutura de comandos e parser de argumentos robustos.
- UI Desktop: Janela principal e abas implementadas.
- Tray: Fixes for initialization race conditions and support for multi-icon SNI.
- Configuration Engine: Persistência, UI e injeção de variáveis implementados.
- Configuration Engine v1.1: Campos avançados de schema (
date,time,datetime,url,path,textarea,slider) suportados na UI com validação. - Mobile Widgets: Integração nativa com Android (XML/Receiver) e iOS (WidgetKit/SwiftUI) via
home_widget. - Mobile Stability: Cache persistente do
crossbar.webno mobile e proteção contra varreduras vazias de plugins. - Lua API: Helpers
web/env/config/jsonintegrados nos plugins de exemplo. - Lua-First Samples: Todos os 26 sample plugins são Lua-only (ADR-014), UI simplificada sem dropdown de linguagem.
- Marketplace: Sistema de busca e instalação via GitHub implementado (
MarketplaceService).
- Tray Avançado: Modos "Smart Collapse" e "Overflow" são apenas enums sem lógica.
- API Gaps: Comando
--location(geocoding) não tem lógica implementada.
Objetivo: Permitir que plugins declarem configurações (JSON), o usuário preencha (UI), e o sistema injete (ENV vars) com segurança.
- Criar Service:
lib/services/plugin_config_service.dart.- Implementar
loadValues(pluginId)lendo de~/.crossbar/configs/. - Implementar
saveValues(pluginId, map)escrevendo JSON. - Integrar
flutter_secure_storagepara detectar chaves definidas comotype: passwordno schema e salvar separadamente.
- Implementar
- Vincular Plugin: Em
lib/core/plugin_manager.dart:- No método
_createPluginFromFile, verificar existência de[plugin].config.json. - Parsear JSON para
PluginConfigobject. - Adicionar campo
PluginConfig? configao modelPlugin.
- No método
- Teste Unitário:
test/unit/services/plugin_config_service_test.dartcobrindo criptografia e I/O.
- Update Runner: Em
lib/core/script_runner.dart:- Injetar
PluginConfigServiceno construtor. - No método
run, chamarloadValues. - Mesclar valores carregados ao mapa
environmentpassado paraProcess.start.
- Injetar
- Teste Funcional: Criar
test/functional/fixtures/env_dump.she validar se variáveis salvas aparecem no STDOUT.
- Plugins Tab: Em
lib/ui/tabs/plugins_tab.dart:- Adicionar botão "Configurar" (ícone engrenagem) se
plugin.config != null. - Carregar valores atuais antes de abrir o dialog.
- Chamar
saveValuesno callbackonSavedoPluginConfigDialog.
- Adicionar botão "Configurar" (ícone engrenagem) se
Objetivo: Transformar o Crossbar em um cidadão de primeira classe no Android e iOS, usando o package home_widget corretamente.
- Layouts: Criar arquivos XML em
android/app/src/main/res/layout/:-
widget_layout_small.xml(1x1: Ícone + Texto curto). -
widget_layout_medium.xml(2x1: Ícone + Texto + 1 Ação). -
widget_layout_large.xml(Lista/Grid para menu items).
-
- Kotlin Provider: Criar
CrossbarWidgetProvider.ktestendendoHomeWidgetProvider.- Implementar lógica de atualização via
RemoteViews. - Mapear dados do JSON (salvo pelo Flutter) para os IDs do layout XML.
- Implementar lógica de atualização via
- Manifest: Registrar o receiver e o provider no
AndroidManifest.xml.
- XCode Target: Adicionar target "Widget Extension" ao projeto iOS.
- App Groups: Configurar App Groups no XCode (Runner + Widget) para compartilhamento de dados
UserDefaults. - SwiftUI View: Implementar
CrossbarWidget.swift.- Criar TimelineProvider que lê JSON do
UserDefaults(viahome_widget). - Desenhar View adaptativa (family: .systemSmall, .systemMedium).
- Criar TimelineProvider que lê JSON do
- Serialização: Em
lib/services/widget_service.dart:- Implementar
updateWidget(pluginId, output). - Serializar
PluginOutputpara formato plano (chave/valor) que ohome_widgetconsome. - Chamar
HomeWidget.updateWidgetcom o nome correto do provider.
- Implementar
- Background Sync: Implementado via WorkManager para atualização de widgets em background (Android).
- Criado
lib/services/background_service.dartcomcallbackDispatcher - Tarefa periódica de 15 minutos para atualizar widgets
- Suporta plugins Lua, YAML e Dart (sem dependências externas)
- Criado
Objetivo: Polimento da experiência desktop e gerenciamento avançado de ícones de bandeja.
- Dependência:
hotkey_manager: ^0.2.3adicionado aopubspec.yaml. - Implementação: Em
lib/services/window_service.dart:- Registrar
Ctrl+Alt+C(ouCmd+Alt+Cno macOS) viaregisterGlobalHotkey(). - Handler faz toggle de
show()/hide().
- Registrar
- Settings: Adicionar opção na aba Settings para customizar/desativar o atalho.
- Lógica: Em
lib/services/tray_service.dart:- Implementar lógica para
TrayDisplayMode.smartOverflow(All Separate vs All Unified based on threshold). - Implementar lógica para
TrayDisplayMode.smartCollapse(First N separate, rest in Unified menu). - Se
plugins.length > threshold, renderizar apenas 1 ícone genérico na tray (smartOverflow behavior). - Renderizar o menu de contexto contendo submenus para cada plugin ativo.
- Implementar lógica para
- Menu Builder: Refatorar a construção do menu para suportar aninhamento dinâmico (Plugin A -> [Output, Actions]).
- Persistência: Em
lib/services/window_service.dart:- Salvar
Rect(posição e tamanho) e estado maximizado noshared_preferencesao fechar/ocultar/blur/maximize. - Restaurar
Recte estado maximizado ao iniciar o app (evitar que abra sempre no centro ou tamanho default). - Adicionar testes completos para persistência e restauração de estado.
- Salvar
Objetivo: Preencher as lacunas nos comandos CLI e tornar o Marketplace funcional.
- Geolocation: Implementado em
lib/cli/commands/location_command.dart(LocationCommand).- IP geolocation via ipapi.co com fallback ip-api.com (sem dependência de geolocator/Flutter).
- Geocoding (endereço -> coordenadas) via Nominatim/OpenStreetMap.
- Reverse geocoding (coordenadas -> endereço) via Nominatim/OpenStreetMap.
- Suporte a --json e --xml output.
- QR Code: Implementado em
lib/cli/commands/qr_command.dart(QrCommand).- Gera QR code em ASCII (Unicode blocks) para terminal.
- Gera PNG base64 com flag
--image. - Tamanho customizável via
--size. Suporte a JSON/XML output.
- Screenshot: API multiplataforma implementada em
lib/core/api/utils_api.dart.- Linux:
gnome-screenshot,scrot,spectacle(fallback chain). - Windows: PowerShell snippet para captura.
- macOS:
screencapture. - Expor como comando CLI (
crossbar screenshot [path] [--clipboard]).
- Linux:
- GitHub API: Em
lib/services/marketplace_service.dart:- Implementar busca real usando
api.github.com/repos/{owner}/{repo}/contents/plugins. - Implementar cache de resultados para evitar rate limiting.
- Implementar busca real usando
- Instalação: Melhorar
InstallCommand:- Clonar/Baixar plugin.
- Validar integridade do arquivo.
- Copiar para
~/.crossbar/plugins. - Executar
chmod +xautomaticamente.
Objetivo: Permitir título customizado por usuário com fallback automático para o nome padrão (UI e widgets).
- Adicionar override de título salvo por usuário e propagar para UI/Widgets. (Commit hash: 969c394)
Objetivo: Resolver dívidas técnicas identificadas no code review dos commits 32faafb..73d8515, focando em prevenção de memory leaks, robustez de recursos e cobertura de testes.
Context: Code review identificou áreas críticas que precisam de melhorias para garantir estabilidade em execuções longas e edge cases.
-
LRU Cache para
_webCache: Empackages/crossbar_core/lib/src/core/lua_runner.dart:- Implementar limite de tamanho para
Map<String, dynamic> _webCache - Adicionar estratégia LRU (Least Recently Used) ou limitar a 100 entradas
- Adicionar métrica de hit/miss rate para monitoramento
- Teste: Validar que cache não cresce indefinidamente após 500+ requests
- Implementar limite de tamanho para
-
Rotação de Logs Android: Em
android/app/src/main/kotlin/com/verseles/crossbar/WidgetLogStore.kt:- Limite e FIFO já implementados (
MAX_LINES = 200) -
clear()já existe - Expor contador de logs descartados na UI de debug
- Teste: Verificar que logs não excedem limite após 1000+ entradas
- Limite e FIFO já implementados (
-
Empty Discovery Guard Documentation: Em
lib/core/plugin_manager.dart:- Documentar lógica do
_emptyDiscoveryStreak >= 2com comentário inline - Considerar tornar threshold configurável via
SettingsService - Teste: Validar comportamento em cenário "diretório realmente vazio"
- Documentar lógica do
-
Output Parser Edge Cases: Em
test/unit/core/output_parser_test.dart:- Adicionar teste: Strings com pipes escapados (
text | inner=pipe\|here) - Adicionar teste: Atributos multi-valor com quotes (
bash="/bin/sh -c 'echo test'") - Adicionar teste: Atributos com espaços e caracteres especiais
- Adicionar teste: Parsing de atributos vazios ou malformados
- Target: Aumentar coverage de
output_parser.dartpara 99%+
- Adicionar teste: Strings com pipes escapados (
-
Widget Tests para Plugins Tab: Criar
test/widget/tabs/plugins_tab_test.dart:- Testar filtro "Enabled only" com lista mista de plugins
- Testar ordenação por nome, interval, status
- Testar busca/search functionality
- Testar ações de enable/disable via UI
- Target: Aumentar coverage de
plugins_tab.dartde 10% para 60%+
-
Integration Test: Web Cache Persistence: Criar
test/integration/web_cache_persistence_test.dart:- Validar que cache sobrevive a restart do app
- Validar estratégia stale-while-revalidate em caso de erro de rede
- Validar limpeza de cache obsoleto (>7 dias)
-
Mover
customTitleKeypara Core: Empackages/crossbar_core/lib/src/models/plugin_config.dart:- Mover constante
customTitleKeydePluginConfigServiceparaPluginConfig - Adicionar documentação sobre convenção de chaves reservadas (prefixo
_crossbar_) - Atualizar referências em
plugin_config_service.dart
- Mover constante
-
Avaliar Compressão de Cache: Em
packages/crossbar_core/lib/src/core/lua_runner.dart:- Medir tamanho médio de cache em disco após 1 semana de uso
- Se > 10MB, implementar compressão gzip para arquivos
.jsondo cache - Adicionar métrica de espaço em disco salvo na UI de debug
-
Refactor: Widget Log Storage Abstraction: Em
lib/services/widget_log_store.dart:- Criar interface
LogStorecom implementaçõesMemoryLogStoreeFileLogStore - Permitir switch entre in-memory (rápido) e persistente (diagnóstico)
- Adicionar toggle na UI de Settings
- Criar interface
- ✅ Zero memory leaks detectados em execução de 24h+ (Android Profiler)
- ✅ Coverage geral aumentado para 42%+ (atualmente 40.7%)
- ✅ Todos os testes de edge cases do
output_parserpassando - ✅ Widget tests para
plugins_tab.dartimplementados - ✅ Documentação inline adicionada para lógicas complexas
Para cada Epic, a seguinte "Definition of Done" deve ser respeitada:
- Código: Implementado seguindo
flutter_lints. - Testes Unitários: Classes de lógica (Services, ViewModels) com >90% coverage.
- Testes de Integração: Pelo menos 1 teste end-to-end para o fluxo crítico (ex: Salvar config -> Executar Plugin -> Verificar Output).
- Multi-plataforma: Verificar se a implementação não quebra o build em Linux/Android (CI matrix).
Coverage atual: 44.3% (meta: 35%)
-
output_parser.dart- 97.5% -
refresh_service.dart- 96.5% -
plugin_output.dart- 96.6% -
cli_handler.dart- 95.3% -
lua_runner.dart- 90.1% -
plugin_config.dart- 85.3% -
plugin_config_service.dart- 87.5% -
script_runner.dart- 80.3% -
plugin_manager.dart- 77.2% -
scheduler_service.dart- 75.0% -
declarative_runner.dart- 71.0% -
logger_service.dart- 70.1%
-
plugins_tab.dart- 10.0% -
marketplace_service.dart- 21.9% -
android_native_bridge.dart- 7.3% -
utils_api.dart- 2.7% - Comandos CLI de hardware (audio, bluetooth, screen, etc.)
- Refatorar
scheduler_service_test.dartpara usar classe real - Adicionar testes de widget/UI para
plugins_tab.dart(ver Epic v1.9.1) - Adicionar edge cases para
output_parser.dart(ver Epic v1.9.1) - Excluir arquivos
l10n/*do cálculo de coverage (gerados automaticamente)
Nota: Melhorias detalhadas de testes estão documentadas no Epic v1.9.1: Code Quality & Robustness.
Objetivo: Padronizar ícones de tray (bandeja do sistema) para funcionar corretamente em todas as plataformas: Linux, macOS, Windows e Android.
Status: 🟢 Fase 1 Concluída
Documento Detalhado: ROADMAP.feat013-tray-icons.md - contém pesquisa completa, especificações técnicas e plano de implementação.
- Linux - Reaplicar ícone ao trocar tema: Corrigido
_onThemeChanged()para chamarsetIcon()após recalcular path via novo método_updateIconForTheme() - Linux - gsettings monitor: Adicionado
gsettings monitor org.gnome.desktop.interface color-schemepara detecção confiável de mudança de tema no GNOME (o callbackonPlatformBrightnessChangeddo Flutter não dispara no Linux) - Android - Monochrome Icon: Adicionado
adaptive_icon_monochromeno pubspec.yaml + geração automática no Makefile para Material You (Android 13+) - Android - Notification Small Icon: Geração de
ic_stat_crossbar.pngmonocromático (branco+transparente) em 5 densidades + referência emnotification_service.dartpara status bar - Makefile - dart build cli: Migrado compilação do tray daemon de
dart compile exeparadart build cli(compatibilidade com build hooks do Dart 3.10+)
- Linux - Freedesktop IconName: Migrar para ícone simbólico SVG que respeita tema do shell
- macOS - Template Image: Validar/corrigir
isTemplate: truepara adaptação automática - Windows - Detecção de Tema: (Opcional) Ler registry para trocar ícone conforme tema
- Android Widgets - ImageView: Migrar de TextView para ImageView com tint dinâmico
- iOS Widgets - SF Symbols: Suporte a prefixo
sf:para ícones nativos
Objetivo: Tornar menu items de plugins acessíveis no mobile via widgets e notificações configuráveis.
Status: 🟢 Concluído
- NotificationStyle enum: Adicionado em
SettingsServicecom valorescombined,individual,bothe persistência via SharedPreferences - Settings UI: Seção "System Tray" substituída por "Notifications" no mobile (Android/iOS) com dialog de estilo. Toggle "Keep on Background" movido de Behavior para Notifications no mobile. Desktop mantém System Tray inalterado.
- i18n: Chaves adicionadas em
app_en.arbeapp_pt.arb(notificationStyle,notificationStyleCombined, etc.)
- ic_more_vert.xml: Vector drawable (3 pontos verticais, branco) para botão de menu
- Layouts atualizados: Botão menu adicionado em small (end|bottom), medium (stacked vertical com edit), large (20dp por plugin row)
- WidgetMenuActivity.kt: Activity Kotlin pura, dialog-themed, UI programática com bottom-sheet, dark mode, submenus inline, href abre browser, bash desabilitado
- CrossbarWidgetBase.kt:
hasMenuItems()verifica menu,setupMenuClickHandler()configura PendingIntent com offsets diferenciados - AndroidManifest.xml: WidgetMenuActivity registrada
- NotificationService:
showCombinedNotification()(InboxStyle, até 6 linhas) eshowIndividualNotification()(BigTextStyle com menu items expandidos) - SchedulerService: Integrado com
NotificationStyle— chama método apropriado após cada output de plugin - Grouping: Usa
setGroup("crossbar_plugins_group")para agrupamento no Android 7+ - IDs estáveis:
pluginId.hashCodepara atualização sem duplicação