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:
+217
-22
@@ -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{
|
||||||
|
|||||||
Reference in New Issue
Block a user