Tarefas concluídas, movidas do
To-Do.md. Revisão técnica original: 2026-06-11 (base v1.3.4). Tudo abaixo foi entregue na v1.4.0 (2026-06-12) — commits8841494+70c90a4.
- Aviso de vazamento de DNS nunca era capturado — ✅ 2026-07-10: descoberta ao reconectar manualmente e ver
Warning: System DNS could not be configuredno CLI, nunca exposto no plugin.AdGuardVpnParsers.jsagora detecta a linha emparseStatusOutput(dnsWarning),AdGuardVpnService.qmlexpõednsWarning: bool(resetado em todo branch de status),AdGuardVpnWidget.qmlmostra banner persistente no hero (mesmo padrão visual do banner "Sessão não iniciada"). 2 testes novos emscripts/test-parsers.mjs(28/28 passando). Chaves i18ndns.leak_warning_title/dns.leak_warning_bodyem en+pt_BR (paridade estrita mantida). - Detecção de "disconnected" agressiva demais — ✅ 2026-07-10:
disconnectPattern(AdGuardVpnParsers.js) testavafirstLineOUfullOutputinteiro; qualquer linha auxiliar com "disconnected"/"stopped" derrubava o estado mesmo com "Connected to …" na primeira linha. Teste restrito só aofirstLine— todos os formatos suportados (connected/disconnected/key-value) já colocam o sinal decisivo ali, confirmado pelos 29 testes existentes. Teste de regressão novo prova que "Connected to Frankfurt..." + linha auxiliar "...was stopped..." continuaconnected: true. -
openTunnelLogsem guard contra dupla invocação — ✅ 2026-07-10: novoproperty bool tunnelLogOpeningemAdGuardVpnService.qml, setado antes doProc.runCommande resetado no callback (sucesso e erro); clique duplo/rápido agora só reexibe o toast "Opening tunnel log..." em vez de lançar terminal/spawn duplicado. Botão "Open Log" no widget desabilita enquantotunnelLogOpeningétrue(defesa em duas camadas: UI + Service). -
popoutHeight: 760fixo estourava em telas baixas — ✅ 2026-07-10:popoutHeightagora é um binding que usaroot.parentScreen || Screen(mesmo fallback usado internamente peloPluginComponent.qmldo DMS) eroot.barThickness, clampando entrepopoutMinHeight(420) epopoutMaxHeight(760) —Math.max(420, Math.min(760, screenHeight - barThickness - 96)). Sem regressão em 1080p (resultado idêntico a 760); em 768p com barra o popout cabe com margem. - Capitalização quebrada em nomes de localização com acento (
SãO PAULO) — ✅ 2026-07-10: quirk confirmado como bug do próprioadguardvpn-cli(hex dump mostrouãminúsculo dentro de string em bold/uppercase), mascarado cosmeticamente comformatLocationName()novo emAdGuardVpnWidget.qml(lowercase + capitalize por palavra/hífen) aplicado no bar pill e no hero title. Verificado visualmente: badge agora mostra "São Paulo". - Indicador visual de ping — ✅ 2026-07-10:
pingToneColor()novo emAdGuardVpnWidget.qml(verdeTheme.success<80ms, amareloTheme.warning<150ms, vermelhoTheme.error≥150ms, neutroTheme.surfaceVariantTextquando ping desconhecido/-1) aplicado no fundo (alpha 0.12) e borda (alpha 0.4) do badge de ping em cada card de localização, sem alterar o texto/formatação existente.
- Input de localização é apagado enquanto o usuário digita — ✅ 2026-06-11 (v2): refatorado para
readonly property savedDefaultLocation(binding reativo apluginData) + seed por abertura de popout + sync externo só quando o campo não está focado. Elimina a corrida de init que deixava o campo vazio mesmo com padrão salvo (verificado visualmente via screenshot). - Cascata pesada a cada save de setting — ✅ 2026-06-11:
loadSettings()só chamarestartTimers()serefreshIntervalSec/autoRefreshLocationsmudaram echeckCliAvailability()só seadguardBinarymudou (ou primeiro load). - Fallback do parser de localização aceita palavras minúsculas como ISO — ✅ 2026-06-11: removida flag
/ideplainIsoMatch,bracketIsoMatchedashedMatch;tryColumnsvalida maiúsculas antes dotoUpperCase(). - Timeout de comandos — ✅ 2026-06-11: descoberta: assinatura real é
Proc.runCommand(id, cmd, cb, debounceMs, timeoutMs)— o 4º arg que o plugin passava (100/300) era debounce, não timeout; tudo rodava com timeout default de 10s (exit 124).runCliagora passa debounce 0 +timeoutMsreal: default 15s,license30s,disconnect30s, connects 60s (viaoptions.timeoutMsnorunAction). Exit 124 ganhou mensagem própria (toast.command_timeout, en+pt_BR). Bônus:openTunnelLoglança terminais blocking em background (launch_bg+kill -0) — antes o timeout de 10s matava oshe gerava toast de erro falso com a janela de log aberta.
- Lista de localizações limitada a 8 itens sem indicação — ✅ 2026-06-11:
locationsDisplayLimitprogressivo (8 inicial, +12 por clique em "Mostrar mais ({count} ocultas)"), reset ao mudar a busca; label "Showing X/Y" agora reporta o nº realmente renderizado. - Auto-reconnect tenta uma única vez — ✅ 2026-06-11:
reconnectPending+ backoff 5s/15s/45s (máx. 3 tentativas), toast de desistência (toast.reconnect_giveup); reset em sucesso ou disconnect manual. - Polling sem backoff com CLI indisponível — ✅ 2026-06-11:
statusPollIntervalMs()— poll de recuperação a ≥30s enquantocliAvailable === false, volta ao intervalo configurado viaonCliAvailableChanged. -
refreshAllduplicado no startup — ✅ 2026-06-11: Widget só chamarefreshAll(true)seAdGuardVpnService.lastRefreshMsainda for 0. - Migração de favoritos legados nunca persiste — ✅ 2026-06-11:
loadSettings()gravafavoriteLocationTargetsquando migra defavoriteLocationIsos. - Strings de estado não re-traduzem ao trocar idioma — ✅ 2026-06-11 (mínimo):
Connectionsno Service observaAdGuardVpnI18n.normalizedLocalee forçarefreshStatus()(ou re-traduzstatus.cli_unavailable). Ideal (chaves+params em binding) fica como refino futuro.
- Acessibilidade zero nos botões — ✅ 2026-06-11:
VpnActionButton, cards de localização e estrela de favorito ganharamactiveFocusOnTab,Keys.onReturn/Enter/Space,Accessible.role/name/descriptione borda de foco funcional. - Estado "não logado" sem CTA — ✅ 2026-06-11:
AdGuardVpnService.loginRequired(setado pelo parse delicense) + banner no hero com comando{adguardBinary} logine botão "Copiar comando" (copyToClipboardviawl-copy/xclip). - Largura fixa de 140px no texto da barra — ✅ 2026-06-11:
Math.min(implicitWidth, 140). - Inputs inconsistentes — ✅ 2026-06-11 (v2): busca e destino migrados para
DankTextField(leftIconName, clear button na busca) e empilhados em largura total — o layout antigo de 2 colunas (Column+Layout.fillWidth+ filhoswidth: parent.widthdentro deRowLayout) colapsava a coluna da busca (campo invisível em produção, confirmado em screenshots antes/depois). ImportQtQuick.Controlsremovido (não usado). Verificado visualmente: ambos os campos renderizam com ícone e placeholder. - Dados parseados nunca exibidos — ✅ 2026-06-11 (parcial): chips no hero para
tunnelInterface(conectado) eSOCKS host:port(modo socks).routingMode/changeSystemDnsficam para uma futura seção Diagnostics. -
Enternão conecta — ✅ 2026-06-11:onAcceptedno campo destino disparaconnectToLocation. - Erro multi-linha cru no hero — ✅ 2026-06-11: linha
DBG:separada emlastErrorDebug(não exibida no hero); zerada no início de cada ação. -
formatTimestampignora idioma do plugin — ✅ 2026-06-11:toLocaleTimeString(Qt.locale(AdGuardVpnI18n.normalizedLocale), Locale.ShortFormat). - Flickable
contentWidthincoerente — ✅ 2026-06-11:contentWidth: width; depois evoluído paraDankFlickable(momentum + scrollbar overlay auto-hide) com canal reservado à direita para a scrollbar nunca cobrir conteúdo. - Botão de protocolo "Autom..." truncado em pt-BR — ✅ 2026-06-12: label literal "Auto" (achado na verificação visual).
- Testes unitários dos parsers — ✅ 2026-06-11:
scripts/test-parsers.mjs(26 testes, sem dependências, carrega a lib vianode:vm): status (4 formatos), license (3 variantes), config (parcial/clamp/fallback), locations (5 estratégias de coluna + emoji de bandeira), regressões do P0-3 (palavras minúsculas ≠ ISO). Integrado ao CI (quality.yml).
- README: tabela de settings desatualizada (EN e PT-BR) — ✅ 2026-06-12:
bypassMultiRouteCheckdocumentada nas duas tabelas. - README: exemplo de publish com tag velha — ✅ 2026-06-12: placeholder
vX.Y.Z. - README vendável — ✅ 2026-06-12: capa nova (
docs/cover.png, SVG autoral renderizado, tema navy+âmbar da UI), badges (CI, versão, DMS, i18n, testes, licença),docs/screenshot.pngrefeito com capturas reais do popout atual (2 painéis compostos com sombra/fundo on-brand), tabelas de features EN/PT atualizadas com acessibilidade, retry e testes. - Documentar cap de exibição da lista / retry único — ✅ obsoleto em 2026-06-12: o cap virou paginação "Mostrar mais" e o retry ganhou backoff — não há mais limitação a documentar.
- CI: rodar testes de parser — ✅ 2026-06-11: step "Run parser tests" no
quality.yml. - Release v1.4.0 — ✅ 2026-06-12:
plugin.json1.4.0, CHANGELOG (EN+PT),docs/releases/v1.4.0.md, tagv1.4.0, GitHub Release publicado, CI verde, registry validado (sem PR necessário — o registry não versiona; screenshot raw demainjá propaga).
- Paridade i18n:
check-i18n-keys.mjspassa (base en.js, 22 locales; pt_BR com paridade estrita). - Escapes bash em template literals JS (
openTunnelLog,prepareDisconnectedRuntime) corretos conforme regra do projeto. - Lógica multi-rota (menor métrica + filtro de interfaces virtuais + bypass toggle) consistente entre código, CHANGELOG v1.3.3 e COMMANDS.md.
connectToLocationpassa input do usuário como argv (sem shell) — sem injeção.- Preflight usa
adguardBinaryconfigurado (fix v1.3.4 confirmado no código). - Auto-connect no startup espera
startupStatusKnown && startupConfigKnown(fix v1.3.4 confirmado). asBooltrata strings"false"/"0"/"off"/"no"(fix v1.3.4 confirmado).- Dependências de binding do
filteredLocationscapturamfavoriteLocationTargetsviaisFavoriteLocation(QML rastreia leituras de propriedade dentro de funções chamadas no binding).