Version 0.9.1-2: Fix npm installation and pause button behavior

Critical Fixes:
- FIXED: npm installation verification added
  * Now explicitly checks if npm is installed after nodejs
  * Falls back to installing npm separately if missing
  * Displays npm version after installation
  * Prevents "npm: command not found" error during Electron install

- FIXED: Pause button now appears only on user interaction
  * Hidden by default (display:none)
  * Shows on mousedown/touchstart/keydown events
  * Similar behavior to keyboard icon
  * Throttled to check every 5 seconds
  * Better UX - less visual clutter

- FIXED: Pause button hidden on manual sites (duration=0)
  * Main process checks site duration when visibility requested
  * Sends pause-button-visibility message to views
  * attachView() function controls visibility on tab switch
  * Prevents confusion on sites where return-to-home popup appears

Implementation:
- Added 'request-pause-button-visibility' IPC message
- Main process responds with 'pause-button-visibility' based on duration
- Pause button automatically hidden/shown when switching tabs
- User interaction triggers visibility check
This commit is contained in:
Claude
2025-11-18 16:29:35 +00:00
parent 7e1809faa6
commit f65e99c8fb
+82 -10
View File
@@ -3280,7 +3280,15 @@ first_time_install() {
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
fi
# Verify npm is installed
if ! command -v npm &>/dev/null; then
echo "⚠ npm not found, attempting to install..."
sudo apt install -y npm
fi
echo "Node.js: $(node -v)"
echo "npm: $(npm -v)"
echo "[7-10/27] Core configuration..."
configure_touch_controls
@@ -3706,25 +3714,30 @@ function rotateToNextSite(){
function attachView(i){
closeHTMLKeyboard();
if(!mainWindow||!views[i]||showingHidden)return;
currentIndex=i;
mainWindow.setTopBrowserView(views[i]);
const[w,h]=mainWindow.getContentSize();
views[i].setBounds({x:0,y:0,width:w,height:h});
const tabIdx=viewIndexToTabIndex(i);
if(tabIdx>=0&&tabs[tabIdx]){
const configuredUrl=tabs[tabIdx].url;
const currentUrl=views[i].webContents.getURL();
if(currentUrl&&!currentUrl.startsWith(configuredUrl)){
programmaticNavigation=true;
views[i].webContents.loadURL(configuredUrl);
}
// Control pause button visibility based on site duration
const siteDuration=parseInt(tabs[tabIdx].duration)||0;
const shouldShow=siteDuration!==0; // Hide on manual sites (duration=0)
views[i].webContents.send('pause-button-visibility',shouldShow);
}
views[i].webContents.focus();
siteStartTime=Date.now();
}
@@ -4219,6 +4232,27 @@ function createWindow(){
ipcMain.on('close-keyboard',()=>{closeHTMLKeyboard();});
ipcMain.on('keyboard-activity',()=>{markKeyboardActivity();});
ipcMain.on('show-pause-dialog',()=>{showPauseDialog();});
// Handle pause button visibility request
ipcMain.on('request-pause-button-visibility',()=>{
const currentTabIdx=viewIndexToTabIndex(currentIndex);
let shouldShow=true;
if(currentTabIdx>=0&&tabs[currentTabIdx]){
const siteDuration=parseInt(tabs[currentTabIdx].duration)||0;
// Hide pause button on manual sites (duration=0)
if(siteDuration===0){
shouldShow=false;
}
}
// Send visibility state to all views
views.forEach(v=>{
if(v&&v.webContents){
v.webContents.send('pause-button-visibility',shouldShow);
}
});
});
ipcMain.on('keyboard-type',(event,key)=>{
markKeyboardActivity();
@@ -5125,6 +5159,7 @@ window.addEventListener('DOMContentLoaded',()=>{
// Pause button functionality
let pauseButton=null;
let pauseButtonVisible=false;
function createPauseButton(){
if(pauseButton)return;
@@ -5136,7 +5171,7 @@ window.addEventListener('DOMContentLoaded',()=>{
pauseButton.style.cssText=`
position:fixed;bottom:20px;left:20px;width:60px;height:60px;
background:rgba(230,126,34,0.95);border:3px solid rgba(255,255,255,0.9);
border-radius:50%;display:flex;align-items:center;justify-content:center;
border-radius:50%;display:none;align-items:center;justify-content:center;
font-size:32px;cursor:pointer;z-index:999999;
box-shadow:0 4px 12px rgba(0,0,0,0.4);user-select:none;
`;
@@ -5150,10 +5185,47 @@ window.addEventListener('DOMContentLoaded',()=>{
document.body.appendChild(pauseButton);
}
// Create pause button on page load
setTimeout(()=>{
createPauseButton();
},1000);
function showPauseButton(){
if(!pauseButton)createPauseButton();
pauseButton.style.display='flex';
pauseButtonVisible=true;
}
function hidePauseButton(){
if(pauseButton){
pauseButton.style.display='none';
pauseButtonVisible=false;
}
}
// Listen for pause button visibility control from main process
ipcRenderer.on('pause-button-visibility',(event,visible)=>{
if(visible){
showPauseButton();
}else{
hidePauseButton();
}
});
// Show pause button on user interaction (but not on manual sites)
let lastPauseButtonCheck=0;
const PAUSE_BUTTON_THROTTLE=5000;
function checkAndShowPauseButton(){
const now=Date.now();
if(now-lastPauseButtonCheck>PAUSE_BUTTON_THROTTLE){
lastPauseButtonCheck=now;
ipcRenderer.send('request-pause-button-visibility');
}
}
// Show pause button on any user interaction
const pauseButtonTriggers=['mousedown','touchstart','keydown'];
pauseButtonTriggers.forEach(eventType=>{
document.addEventListener(eventType,()=>{
checkAndShowPauseButton();
},{passive:true,capture:true});
});
function isTextInput(el){
if(!el)return false;