fix(ble): copyDiagLog usa modal + share em vez de clipboard API v1.10.8
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Bug v1.10.6/7: clicar 'Copiar log' fechava o app (crash WebView). Causa: navigator.clipboard.writeText em alguns Android skinned (Samsung One UI, Xiaomi MIUI) requer permissão extra que sem ela gera SecurityException nativa não capturada. Fix: substitui por modal full-screen com textarea readonly + selectable + botão Compartilhar (navigator.share, mais robusto). Removido document.execCommand (deprecado, também crashava). Karlão pode agora: (1) selecionar texto manualmente segurando na textarea, (2) tocar Compartilhar pra mandar via WhatsApp/email escolhendo o app no share sheet do Android. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6680f8b09b
commit
f3183b33d1
5 changed files with 88 additions and 36 deletions
|
|
@ -5794,24 +5794,50 @@ async function ensureBleNativeReady(){
|
||||||
_bleNativeInitialized=true;
|
_bleNativeInitialized=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copia log diagnóstico pro clipboard
|
// Mostra log num modal pro usuário copiar/compartilhar manualmente
|
||||||
async function copyDiagLog(){
|
// (navigator.clipboard crasha em alguns WebViews Capacitor / Samsung One UI)
|
||||||
|
function copyDiagLog(){
|
||||||
const el=document.getElementById('bt-diag');
|
const el=document.getElementById('bt-diag');
|
||||||
if(!el){toast('Log vazio');return}
|
if(!el){toast('Log vazio');return}
|
||||||
// Extrai texto puro (innerText preserva quebras de linha)
|
|
||||||
const txt=`Shivao v${APP_VERSION} · log diagnóstico\n\n`+(el.innerText||el.textContent||'').trim();
|
const txt=`Shivao v${APP_VERSION} · log diagnóstico\n\n`+(el.innerText||el.textContent||'').trim();
|
||||||
try{
|
let modal=document.getElementById('bt-log-modal');
|
||||||
if(navigator.clipboard?.writeText){
|
if(modal)modal.remove();
|
||||||
await navigator.clipboard.writeText(txt);
|
modal=document.createElement('div');
|
||||||
toast('✓ Log copiado · cole no chat');
|
modal.id='bt-log-modal';
|
||||||
}else{
|
modal.style.cssText='position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.85);display:flex;flex-direction:column;padding:16px;backdrop-filter:blur(8px)';
|
||||||
// Fallback: textarea hack
|
// safe escape
|
||||||
const ta=document.createElement('textarea');
|
const esc=txt.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||||
ta.value=txt;document.body.appendChild(ta);ta.select();
|
modal.innerHTML=`
|
||||||
document.execCommand('copy');ta.remove();
|
<div style="background:#0d2538;border:1px solid #06b6d4;border-radius:12px;padding:16px;display:flex;flex-direction:column;height:100%;max-height:95vh">
|
||||||
toast('✓ Log copiado');
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">
|
||||||
}
|
<h3 style="margin:0;color:#06b6d4;font-size:15px">📋 Log diagnóstico</h3>
|
||||||
}catch(e){toast('Erro ao copiar: '+e.message)}
|
<button onclick="document.getElementById('bt-log-modal').remove()" style="background:transparent;border:none;color:#fff;font-size:24px;cursor:pointer;padding:4px 12px">✕</button>
|
||||||
|
</div>
|
||||||
|
<p style="color:#b3c5d6;font-size:12px;margin:0 0 8px;line-height:1.4">Toque dentro da caixa e segure pra selecionar tudo. Ou toque ↗ Compartilhar pra enviar via WhatsApp.</p>
|
||||||
|
<textarea id="bt-log-textarea" readonly style="flex:1;width:100%;min-height:280px;background:#0a1f30;color:#e8f1f8;border:1px solid rgba(255,255,255,.15);border-radius:8px;padding:10px;font-family:'JetBrains Mono',monospace;font-size:11px;resize:none;-webkit-user-select:text;user-select:text;-webkit-touch-callout:default;outline:none">${esc}</textarea>
|
||||||
|
<div style="display:flex;gap:8px;margin-top:10px">
|
||||||
|
<button onclick="bmsShareLog()" style="flex:1;background:#10b981;color:#001a25;border:none;padding:12px;border-radius:8px;font-weight:600;cursor:pointer;font-size:14px">↗ Compartilhar</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
document.body.appendChild(modal);
|
||||||
|
// Auto-seleciona o texto
|
||||||
|
setTimeout(()=>{
|
||||||
|
const ta=document.getElementById('bt-log-textarea');
|
||||||
|
if(ta){ta.focus();try{ta.select()}catch{}}
|
||||||
|
},200);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function bmsShareLog(){
|
||||||
|
const ta=document.getElementById('bt-log-textarea');
|
||||||
|
if(!ta)return;
|
||||||
|
if(navigator.share){
|
||||||
|
try{
|
||||||
|
await navigator.share({title:'Shivao log diagnóstico',text:ta.value});
|
||||||
|
}catch(e){/* user cancelou */}
|
||||||
|
}else{
|
||||||
|
toast('Compartilhar não disponível · use seleção manual');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnóstico visível: mostra cada passo no card BLE
|
// Diagnóstico visível: mostra cada passo no card BLE
|
||||||
|
|
@ -6303,7 +6329,7 @@ async function removeBluetoothDevice(id){
|
||||||
renderBluetoothCard();
|
renderBluetoothCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP_VERSION='1.10.7';
|
const APP_VERSION='1.10.8';
|
||||||
function renderBluetoothCard(){
|
function renderBluetoothCard(){
|
||||||
const el=document.getElementById('bt-list');
|
const el=document.getElementById('bt-list');
|
||||||
const supportEl=document.getElementById('bt-support');
|
const supportEl=document.getElementById('bt-support');
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ android {
|
||||||
applicationId "br.com.pontualtech.shivao"
|
applicationId "br.com.pontualtech.shivao"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 23
|
versionCode 24
|
||||||
versionName "1.10.7"
|
versionName "1.10.8"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "shivao-mobile",
|
"name": "shivao-mobile",
|
||||||
"version": "1.10.7",
|
"version": "1.10.8",
|
||||||
"description": "Shivao app nativo (Capacitor wrapper Android/iOS)",
|
"description": "Shivao app nativo (Capacitor wrapper Android/iOS)",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
||||||
|
|
@ -5794,24 +5794,50 @@ async function ensureBleNativeReady(){
|
||||||
_bleNativeInitialized=true;
|
_bleNativeInitialized=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copia log diagnóstico pro clipboard
|
// Mostra log num modal pro usuário copiar/compartilhar manualmente
|
||||||
async function copyDiagLog(){
|
// (navigator.clipboard crasha em alguns WebViews Capacitor / Samsung One UI)
|
||||||
|
function copyDiagLog(){
|
||||||
const el=document.getElementById('bt-diag');
|
const el=document.getElementById('bt-diag');
|
||||||
if(!el){toast('Log vazio');return}
|
if(!el){toast('Log vazio');return}
|
||||||
// Extrai texto puro (innerText preserva quebras de linha)
|
|
||||||
const txt=`Shivao v${APP_VERSION} · log diagnóstico\n\n`+(el.innerText||el.textContent||'').trim();
|
const txt=`Shivao v${APP_VERSION} · log diagnóstico\n\n`+(el.innerText||el.textContent||'').trim();
|
||||||
try{
|
let modal=document.getElementById('bt-log-modal');
|
||||||
if(navigator.clipboard?.writeText){
|
if(modal)modal.remove();
|
||||||
await navigator.clipboard.writeText(txt);
|
modal=document.createElement('div');
|
||||||
toast('✓ Log copiado · cole no chat');
|
modal.id='bt-log-modal';
|
||||||
}else{
|
modal.style.cssText='position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.85);display:flex;flex-direction:column;padding:16px;backdrop-filter:blur(8px)';
|
||||||
// Fallback: textarea hack
|
// safe escape
|
||||||
const ta=document.createElement('textarea');
|
const esc=txt.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||||
ta.value=txt;document.body.appendChild(ta);ta.select();
|
modal.innerHTML=`
|
||||||
document.execCommand('copy');ta.remove();
|
<div style="background:#0d2538;border:1px solid #06b6d4;border-radius:12px;padding:16px;display:flex;flex-direction:column;height:100%;max-height:95vh">
|
||||||
toast('✓ Log copiado');
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">
|
||||||
}
|
<h3 style="margin:0;color:#06b6d4;font-size:15px">📋 Log diagnóstico</h3>
|
||||||
}catch(e){toast('Erro ao copiar: '+e.message)}
|
<button onclick="document.getElementById('bt-log-modal').remove()" style="background:transparent;border:none;color:#fff;font-size:24px;cursor:pointer;padding:4px 12px">✕</button>
|
||||||
|
</div>
|
||||||
|
<p style="color:#b3c5d6;font-size:12px;margin:0 0 8px;line-height:1.4">Toque dentro da caixa e segure pra selecionar tudo. Ou toque ↗ Compartilhar pra enviar via WhatsApp.</p>
|
||||||
|
<textarea id="bt-log-textarea" readonly style="flex:1;width:100%;min-height:280px;background:#0a1f30;color:#e8f1f8;border:1px solid rgba(255,255,255,.15);border-radius:8px;padding:10px;font-family:'JetBrains Mono',monospace;font-size:11px;resize:none;-webkit-user-select:text;user-select:text;-webkit-touch-callout:default;outline:none">${esc}</textarea>
|
||||||
|
<div style="display:flex;gap:8px;margin-top:10px">
|
||||||
|
<button onclick="bmsShareLog()" style="flex:1;background:#10b981;color:#001a25;border:none;padding:12px;border-radius:8px;font-weight:600;cursor:pointer;font-size:14px">↗ Compartilhar</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
document.body.appendChild(modal);
|
||||||
|
// Auto-seleciona o texto
|
||||||
|
setTimeout(()=>{
|
||||||
|
const ta=document.getElementById('bt-log-textarea');
|
||||||
|
if(ta){ta.focus();try{ta.select()}catch{}}
|
||||||
|
},200);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function bmsShareLog(){
|
||||||
|
const ta=document.getElementById('bt-log-textarea');
|
||||||
|
if(!ta)return;
|
||||||
|
if(navigator.share){
|
||||||
|
try{
|
||||||
|
await navigator.share({title:'Shivao log diagnóstico',text:ta.value});
|
||||||
|
}catch(e){/* user cancelou */}
|
||||||
|
}else{
|
||||||
|
toast('Compartilhar não disponível · use seleção manual');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnóstico visível: mostra cada passo no card BLE
|
// Diagnóstico visível: mostra cada passo no card BLE
|
||||||
|
|
@ -6303,7 +6329,7 @@ async function removeBluetoothDevice(id){
|
||||||
renderBluetoothCard();
|
renderBluetoothCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP_VERSION='1.10.7';
|
const APP_VERSION='1.10.8';
|
||||||
function renderBluetoothCard(){
|
function renderBluetoothCard(){
|
||||||
const el=document.getElementById('bt-list');
|
const el=document.getElementById('bt-list');
|
||||||
const supportEl=document.getElementById('bt-support');
|
const supportEl=document.getElementById('bt-support');
|
||||||
|
|
|
||||||
|
|
@ -347,7 +347,7 @@ app.get('/.well-known/assetlinks.json', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Atalho: /apk redireciona pra última APK release no Forgejo
|
// Atalho: /apk redireciona pra última APK release no Forgejo
|
||||||
const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.7/Shivao-v1.10.7.apk';
|
const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.8/Shivao-v1.10.8.apk';
|
||||||
app.get('/apk', (req, res) => res.redirect(302, LATEST_APK_URL));
|
app.get('/apk', (req, res) => res.redirect(302, LATEST_APK_URL));
|
||||||
|
|
||||||
// Página A4 imprimível com QR Code + instruções (cola no barco/marina)
|
// Página A4 imprimível com QR Code + instruções (cola no barco/marina)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue