Merge pull request #73 from outis1one/claude/fix-kiosk-issues-qlxTc

Add 30-second auto-dismiss timeout to secondary screens
This commit is contained in:
outis1one
2025-12-28 15:32:47 -05:00
committed by GitHub
+217 -22
View File
@@ -4038,6 +4038,8 @@ const VERSION='0.9.9.1';
let mainWindow,views=[],hiddenViews=[],tabs=[],currentIndex=0,showingHidden=false; let mainWindow,views=[],hiddenViews=[],tabs=[],currentIndex=0,showingHidden=false;
let pinWindow=null,promptWindow=null,pauseWindow=null,htmlKeyboardWindow=null; let pinWindow=null,promptWindow=null,pauseWindow=null,htmlKeyboardWindow=null;
let pinWindowTimer=null,pauseWindowTimer=null;
const DIALOG_TIMEOUT=30000; // 30 seconds for secondary screens
let tabIndexToViewIndex=[]; let tabIndexToViewIndex=[];
let currentHiddenIndex=0; let currentHiddenIndex=0;
@@ -4953,10 +4955,23 @@ function showPauseDialog(){
pauseWindow.loadFile(path.join(__dirname,'pause-dialog.html')); pauseWindow.loadFile(path.join(__dirname,'pause-dialog.html'));
pauseWindow.on('closed',()=>{ pauseWindow.on('closed',()=>{
if(pauseWindowTimer){clearTimeout(pauseWindowTimer);pauseWindowTimer=null;}
pauseWindow=null; pauseWindow=null;
}); });
// Set 30-second auto-dismiss timer
if(pauseWindowTimer){clearTimeout(pauseWindowTimer);}
pauseWindowTimer=setTimeout(()=>{
console.log('[PAUSE] Auto-dismissing dialog after 30 seconds');
if(pauseWindow&&!pauseWindow.isDestroyed()){
pauseWindow.close();
}
pauseWindow=null;
pauseWindowTimer=null;
},DIALOG_TIMEOUT);
ipcMain.once('pause-time-selected',(event,minutes)=>{ ipcMain.once('pause-time-selected',(event,minutes)=>{
if(pauseWindowTimer){clearTimeout(pauseWindowTimer);pauseWindowTimer=null;}
if(pauseWindow&&!pauseWindow.isDestroyed()){ if(pauseWindow&&!pauseWindow.isDestroyed()){
pauseWindow.close(); pauseWindow.close();
} }
@@ -5126,7 +5141,7 @@ function showPinEntry(){
pinWindow.focus(); pinWindow.focus();
return; return;
} }
pinWindow=new BrowserWindow({ pinWindow=new BrowserWindow({
width:500, width:500,
height:650, height:650,
@@ -5136,19 +5151,35 @@ function showPinEntry(){
modal:true, modal:true,
webPreferences:{nodeIntegration:true,contextIsolation:false} webPreferences:{nodeIntegration:true,contextIsolation:false}
}); });
pinWindow.loadFile(path.join(__dirname,'pin-entry.html')); pinWindow.loadFile(path.join(__dirname,'pin-entry.html'));
pinWindow.on('closed',()=>{pinWindow=null;}); pinWindow.on('closed',()=>{
if(pinWindowTimer){clearTimeout(pinWindowTimer);pinWindowTimer=null;}
pinWindow=null;
});
// Set 30-second auto-dismiss timer
if(pinWindowTimer){clearTimeout(pinWindowTimer);}
pinWindowTimer=setTimeout(()=>{
console.log('[PIN] Auto-dismissing after 30 seconds');
if(pinWindow&&!pinWindow.isDestroyed()){
pinWindow.close();
}
pinWindow=null;
pinWindowTimer=null;
},DIALOG_TIMEOUT);
ipcMain.once('pin-correct',()=>{ ipcMain.once('pin-correct',()=>{
if(pinWindowTimer){clearTimeout(pinWindowTimer);pinWindowTimer=null;}
if(pinWindow&&!pinWindow.isDestroyed()){ if(pinWindow&&!pinWindow.isDestroyed()){
pinWindow.close(); pinWindow.close();
} }
pinWindow=null; pinWindow=null;
showHiddenTab(currentHiddenIndex); showHiddenTab(currentHiddenIndex);
}); });
ipcMain.once('pin-cancelled',()=>{ ipcMain.once('pin-cancelled',()=>{
if(pinWindowTimer){clearTimeout(pinWindowTimer);pinWindowTimer=null;}
if(pinWindow&&!pinWindow.isDestroyed()){ if(pinWindow&&!pinWindow.isDestroyed()){
pinWindow.close(); pinWindow.close();
} }
@@ -5204,13 +5235,11 @@ function showPowerMenu(){
} }
} }
let ipInfo='Local: '+localIP; // For lockout mode, use native dialog (limited options, overlay not available)
if(vpnIP){
ipInfo+='\nVPN: '+vpnIP.trim();
}
if(isLockedOut){ if(isLockedOut){
console.log('[SECURITY] Showing limited power menu - system is locked out'); console.log('[SECURITY] Showing limited power menu - system is locked out');
let ipInfo='Local: '+localIP;
if(vpnIP){ipInfo+='\nVPN: '+vpnIP.trim();}
const targetWindow=(lockoutWindow&&!lockoutWindow.isDestroyed())?lockoutWindow:mainWindow; const targetWindow=(lockoutWindow&&!lockoutWindow.isDestroyed())?lockoutWindow:mainWindow;
const r=dialog.showMessageBoxSync(targetWindow,{ const r=dialog.showMessageBoxSync(targetWindow,{
type:'question', type:'question',
@@ -5226,18 +5255,15 @@ function showPowerMenu(){
return; return;
} }
const r=dialog.showMessageBoxSync(mainWindow,{ // For normal mode, use custom overlay with 30-second timeout
type:'question', console.log('[POWER] Showing custom power menu overlay');
buttons:['Shutdown','Restart','Reload','Cancel'], if(mainWindow&&!mainWindow.isDestroyed()){
defaultId:3, mainWindow.webContents.send('display-power-menu',{
title:'Power Options', version:VERSION,
message:'What would you like to do?\n\nVersion: '+VERSION+'\n'+ipInfo, localIP:localIP,
noLink:true vpnIP:vpnIP.trim()
}); });
}
if(r===0)exec('systemctl poweroff');
else if(r===1)exec('systemctl reboot');
else if(r===2){app.relaunch();app.quit();}
} }
function createWindow(){ function createWindow(){
@@ -5379,6 +5405,12 @@ function createWindow(){
ipcMain.on('swipe-left',()=>{nextTab();}); ipcMain.on('swipe-left',()=>{nextTab();});
ipcMain.on('swipe-right',()=>{prevTab();}); ipcMain.on('swipe-right',()=>{prevTab();});
ipcMain.on('show-power-menu',showPowerMenu); ipcMain.on('show-power-menu',showPowerMenu);
ipcMain.on('power-action',(event,action)=>{
console.log('[POWER] Action requested:',action);
if(action==='shutdown')exec('systemctl poweroff');
else if(action==='restart')exec('systemctl reboot');
else if(action==='reload'){app.relaunch();app.quit();}
});
ipcMain.on('toggle-hidden',toggleHidden); ipcMain.on('toggle-hidden',toggleHidden);
ipcMain.on('return-to-tabs',forceReturnToTabs); ipcMain.on('return-to-tabs',forceReturnToTabs);
ipcMain.on('user-activity',markActivity); ipcMain.on('user-activity',markActivity);
@@ -6781,6 +6813,169 @@ window.addEventListener('DOMContentLoaded',()=>{
} }
} }
// Power menu overlay (with 30-second auto-dismiss)
let powerMenu=null;
let powerMenuVisible=false;
let powerMenuTimer=null;
const POWER_MENU_TIMEOUT=30000;
let powerMenuInfo={version:'',localIP:'',vpnIP:''};
function createPowerMenu(){
if(powerMenu)return;
console.log('[POWER-MENU] Creating power menu');
powerMenu=document.createElement('div');
powerMenu.id='electron-power-menu';
powerMenu.style.cssText=`
position:fixed;top:0;left:0;width:100%;height:100%;
background:rgba(0,0,0,0.9);display:none;align-items:center;justify-content:center;
z-index:999998;pointer-events:auto;
`;
const content=document.createElement('div');
content.style.cssText=`
position:relative;background:rgba(44,62,80,0.98);border-radius:20px;padding:40px;
min-width:400px;max-width:90%;box-shadow:0 10px 40px rgba(0,0,0,0.5);text-align:center;
`;
const closeBtn=document.createElement('div');
closeBtn.innerHTML='✕';
closeBtn.style.cssText=`
position:absolute;top:10px;right:10px;font-size:32px;color:white;
cursor:pointer;width:40px;height:40px;display:flex;align-items:center;
justify-content:center;border-radius:50%;background:rgba(231,76,60,0.8);
user-select:none;
`;
closeBtn.addEventListener('click',(e)=>{
e.preventDefault();
e.stopPropagation();
hidePowerMenu();
});
content.appendChild(closeBtn);
const title=document.createElement('h2');
title.textContent='Power Options';
title.style.cssText='color:white;margin-bottom:20px;font-size:28px;';
content.appendChild(title);
const infoDiv=document.createElement('div');
infoDiv.id='power-menu-info';
infoDiv.style.cssText='color:#bdc3c7;margin-bottom:30px;font-size:14px;line-height:1.6;';
content.appendChild(infoDiv);
const buttonsDiv=document.createElement('div');
buttonsDiv.style.cssText='display:flex;flex-direction:column;gap:15px;';
const btnStyle=`
padding:20px 40px;font-size:20px;border:none;border-radius:10px;
cursor:pointer;font-weight:bold;transition:transform 0.2s,opacity 0.2s;
`;
const shutdownBtn=document.createElement('button');
shutdownBtn.textContent='⏻ Shutdown';
shutdownBtn.style.cssText=btnStyle+'background:#e74c3c;color:white;';
shutdownBtn.addEventListener('click',()=>{
hidePowerMenu();
ipcRenderer.send('power-action','shutdown');
});
const restartBtn=document.createElement('button');
restartBtn.textContent='↻ Restart';
restartBtn.style.cssText=btnStyle+'background:#f39c12;color:white;';
restartBtn.addEventListener('click',()=>{
hidePowerMenu();
ipcRenderer.send('power-action','restart');
});
const reloadBtn=document.createElement('button');
reloadBtn.textContent='⟳ Reload App';
reloadBtn.style.cssText=btnStyle+'background:#3498db;color:white;';
reloadBtn.addEventListener('click',()=>{
hidePowerMenu();
ipcRenderer.send('power-action','reload');
});
const cancelBtn=document.createElement('button');
cancelBtn.textContent='Cancel';
cancelBtn.style.cssText=btnStyle+'background:#7f8c8d;color:white;';
cancelBtn.addEventListener('click',()=>{
hidePowerMenu();
});
buttonsDiv.appendChild(shutdownBtn);
buttonsDiv.appendChild(restartBtn);
buttonsDiv.appendChild(reloadBtn);
buttonsDiv.appendChild(cancelBtn);
content.appendChild(buttonsDiv);
powerMenu.appendChild(content);
powerMenu.addEventListener('click',(e)=>{
if(e.target===powerMenu){
hidePowerMenu();
}
});
content.addEventListener('click',(e)=>{
e.stopPropagation();
});
document.body.appendChild(powerMenu);
}
function showPowerMenu(info){
console.log('[POWER-MENU] Showing power menu');
try{
if(!powerMenu)createPowerMenu();
// Update info display
const infoDiv=document.getElementById('power-menu-info');
if(infoDiv&&info){
let infoText='Version: '+info.version+'<br>Local: '+info.localIP;
if(info.vpnIP){
infoText+='<br>VPN: '+info.vpnIP;
}
infoDiv.innerHTML=infoText;
}
powerMenu.style.display='flex';
powerMenuVisible=true;
// Set 30-second auto-dismiss timer
if(powerMenuTimer){
clearTimeout(powerMenuTimer);
}
powerMenuTimer=setTimeout(()=>{
console.log('[POWER-MENU] Auto-dismissing after 30 seconds');
hidePowerMenu();
},POWER_MENU_TIMEOUT);
}catch(err){
console.error('[POWER-MENU] Error showing menu:',err);
}
}
function hidePowerMenu(){
console.log('[POWER-MENU] Hiding power menu');
try{
if(powerMenuTimer){
clearTimeout(powerMenuTimer);
powerMenuTimer=null;
}
if(powerMenu){
powerMenu.style.display='none';
}
powerMenuVisible=false;
}catch(err){
console.error('[POWER-MENU] Error hiding menu:',err);
}
}
// Listen for power menu display request from main process
ipcRenderer.on('display-power-menu',(event,info)=>{
showPowerMenu(info);
});
function loadSitesIntoNav(){ function loadSitesIntoNav(){
console.log('[NAV] Requesting config from main process'); console.log('[NAV] Requesting config from main process');
try{ try{