Improve chat UI for secure channel creation pages

Fix iOS PWA installation and improve cross-platform compatibility

- Fix manifest.json paths (use relative paths with ./ for iOS)
- Update Apple Touch Icons structure to use organized folders
- Add missing 180x180px icon requirement for iOS
- Fix apple-mobile-web-app meta tags configuration
- Add viewport-fit=cover for iPhone X+ notch support

- Fix missing showInstallButton() method causing TypeError
- Add complete showInstallBanner() and createInstallBanner() methods
- Implement proper hideInstallPrompts() functionality
- Add iOS-specific installation instructions modal
- Fix event handling for install prompt dismissal

- Restructure PWA icons into platform-specific folders:
  - ./logo/pwa/ios/ for Apple Touch Icons
  - ./logo/pwa/android/ for Android launcher icons
  - ./logo/pwa/windows11/ for Microsoft Tiles
- Update manifest.json to reference correct icon paths
- Add browserconfig.xml for Windows 11 tile configuration

- Improve PWA registration script without conflicts
- Add proper error handling for offline functionality
- Integrate with existing PWA modules (install prompt, offline manager)
- Add update notifications for new app versions

- Enhanced detection for iOS Safari vs other browsers
- Improved installation flow for different platforms
- Better user feedback for unsupported installation methods
- Added fallback instructions for manual installation

- Add comprehensive PWA support detection
- Implement proper iOS standalone mode detection
- Add console logging for installation status tracking
- Include developer utilities for PWA management

Tested on: iOS Safari, Chrome, Edge, Firefox
Resolves iOS PWA installation issues and improves overall PWA experience."
This commit is contained in:
lockbitchat
2025-08-19 21:54:17 -04:00
parent 91ea88503e
commit 94ca53f6ca
18 changed files with 460 additions and 257 deletions

View File

@@ -1,6 +1,6 @@
# Security Disclaimer and Terms of Use # Security Disclaimer and Terms of Use
## 🔒 SecureBit.chat Enhanced Security Edition v4.01.212 ## 🔒 SecureBit.chat Enhanced Security Edition v4.01.222
### Important Legal Notice ### Important Legal Notice
@@ -203,6 +203,6 @@ This software is created to:
--- ---
*Last Updated: 08.07.2025* *Last Updated: 08.07.2025*
*Version: Enhanced Security Edition v4.01.212* *Version: Enhanced Security Edition v4.01.222*
**USE AT YOUR OWN RISK AND RESPONSIBILITY** **USE AT YOUR OWN RISK AND RESPONSIBILITY**

View File

@@ -24,45 +24,43 @@
<!-- PWA Meta Tags --> <!-- PWA Meta Tags -->
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="SecureBit"> <meta name="apple-mobile-web-app-title" content="SecureBit">
<meta name="application-name" content="SecureBit"> <meta name="application-name" content="SecureBit">
<meta name="msapplication-TileColor" content="#ff6b35"> <meta name="msapplication-TileColor" content="#ff6b35">
<meta name="msapplication-config" content="/browserconfig.xml"> <meta name="msapplication-config" content="/browserconfig.xml">
<!-- iOS Splash Screens --> <!-- iOS Splash Screens - МИНИМАЛЬНЫЙ НАБОР -->
<link rel="apple-touch-startup-image" href="./splash/launch-640x1136.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"> <link rel="apple-touch-startup-image" href="./splash/launch-640x1136.png"
<link rel="apple-touch-startup-image" href="./splash/launch-750x1334.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"> media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="./splash/launch-1242x2208.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"> <link rel="apple-touch-startup-image" href="./splash/launch-750x1334.png"
<link rel="apple-touch-startup-image" href="./splash/launch-1125x2436.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"> media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="./splash/launch-1536x2048.png" media="(min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)"> <link rel="apple-touch-startup-image" href="./splash/launch-1125x2436.png"
media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="./splash/launch-1242x2688.png"
media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<!-- Apple Touch Icons --> <!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="./logo/pwa/ios/57.png" sizes="57x57"> <link rel="apple-touch-icon" href="./logo/icon-180x180.png">
<link rel="apple-touch-icon" href="./logo/pwa/ios/60.png" sizes="60x60"> <link rel="apple-touch-icon" sizes="57x57" href="./logo/icon-57x57.png">
<link rel="apple-touch-icon" href="./logo/pwa/ios/72.png" sizes="72x72"> <link rel="apple-touch-icon" sizes="60x60" href="./logo/icon-60x60.png">
<link rel="apple-touch-icon" href="./logo/pwa/ios/76.png" sizes="76x76"> <link rel="apple-touch-icon" sizes="72x72" href="./logo/icon-72x72.png">
<link rel="apple-touch-icon" href="./logo/pwa/ios/114.png" sizes="114x114"> <link rel="apple-touch-icon" sizes="76x76" href="./logo/icon-76x76.png">
<link rel="apple-touch-icon" href="./logo/pwa/ios/120.png" sizes="120x120"> <link rel="apple-touch-icon" sizes="114x114" href="./logo/icon-114x114.png">
<link rel="apple-touch-icon" href="./logo/pwa/ios/144.png" sizes="144x144"> <link rel="apple-touch-icon" sizes="120x120" href="./logo/icon-120x120.png">
<link rel="apple-touch-icon" href="./logo/pwa/ios/152.png" sizes="152x152"> <link rel="apple-touch-icon" sizes="144x144" href="./logo/icon-144x144.png">
<link rel="apple-touch-icon" href="./logo/pwa/ios/180.png" sizes="180x180"> <link rel="apple-touch-icon" sizes="152x152" href="./logo/icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="./logo/icon-180x180.png">
<!-- Microsoft Tiles --> <!-- Microsoft Tiles -->
<meta name="msapplication-TileImage" content="./logo/pwa/windows11/Square150x150Logo.scale-100.png"> <meta name="msapplication-TileColor" content="#ff6b35">
<meta name="msapplication-square70x70logo" content="./logo/pwa/windows11/SmallTile.scale-100.png"> <meta name="msapplication-TileImage" content="./logo/icon-144x144.png">
<meta name="msapplication-square150x150logo" content="./logo/pwa/windows11/Square150x150Logo.scale-100.png"> <meta name="msapplication-config" content="./browserconfig.xml">
<meta name="msapplication-wide310x150logo" content="./logo/pwa/windows11/Wide310x150Logo.scale-100.png">
<meta name="msapplication-square310x310logo" content="./logo/pwa/windows11/LargeTile.scale-100.png">
<!-- Theme colors -->
<!-- PWA Theme Colors -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="SecureBit">
<meta name="application-name" content="SecureBit">
<meta name="theme-color" content="#ff6b35"> <meta name="theme-color" content="#ff6b35">
<meta name="msapplication-navbutton-color" content="#ff6b35">
<!-- Security Headers for PWA --> <!-- Security Headers for PWA -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://unpkg.com https://cdn.tailwindcss.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com https://cdnjs.cloudflare.com https://fonts.googleapis.com; font-src 'self' https://cdnjs.cloudflare.com https://fonts.gstatic.com; connect-src 'self' https: wss: ws:; img-src 'self' data: https:; media-src 'none'; object-src 'none'; frame-src 'none'; worker-src 'self';"> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://unpkg.com https://cdn.tailwindcss.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com https://cdnjs.cloudflare.com https://fonts.googleapis.com; font-src 'self' https://cdnjs.cloudflare.com https://fonts.gstatic.com; connect-src 'self' https: wss: ws:; img-src 'self' data: https:; media-src 'none'; object-src 'none'; frame-src 'none'; worker-src 'self';">
@@ -163,7 +161,7 @@
icon: "fas fa-shield-halved", icon: "fas fa-shield-halved",
color: "orange", color: "orange",
title: "12-Layer Military Security", title: "12-Layer Military Security",
description: "Revolutionary defense system with ECDH P-384 + AES-GCM 256 + ECDSA. Enhanced Security Edition v4.01.212 provides military-grade protection exceeding government standards." description: "Revolutionary defense system with ECDH P-384 + AES-GCM 256 + ECDSA. Enhanced Security Edition v4.01.222 provides military-grade protection exceeding government standards."
}, },
{ {
icon: "fas fa-bolt", icon: "fas fa-bolt",
@@ -513,7 +511,7 @@
Enhanced Security Edition Comparison Enhanced Security Edition Comparison
</h3> </h3>
<p className="text-secondary max-w-2xl mx-auto mb-4"> <p className="text-secondary max-w-2xl mx-auto mb-4">
SecureBit.chat v4.01.212 Enhanced Security Edition vs leading secure messengers SecureBit.chat v4.01.222 Enhanced Security Edition vs leading secure messengers
</p> </p>
<div className="inline-flex items-center px-4 py-2 bg-yellow-500/10 border border-yellow-500/20 rounded-lg"> <div className="inline-flex items-center px-4 py-2 bg-yellow-500/10 border border-yellow-500/20 rounded-lg">
<span className="text-yellow-400 mr-2">🏆</span> <span className="text-yellow-400 mr-2">🏆</span>
@@ -659,7 +657,7 @@
<div className="p-6 bg-gradient-to-r from-orange-500/10 to-yellow-500/10 border border-orange-500/20 rounded-xl"> <div className="p-6 bg-gradient-to-r from-orange-500/10 to-yellow-500/10 border border-orange-500/20 rounded-xl">
<h4 className="text-xl font-bold text-orange-400 mb-4 flex items-center"> <h4 className="text-xl font-bold text-orange-400 mb-4 flex items-center">
<i className="fas fa-trophy mr-3" /> <i className="fas fa-trophy mr-3" />
SecureBit.chat v4.01.212 Enhanced Security Edition Summary SecureBit.chat v4.01.222 Enhanced Security Edition Summary
</h4> </h4>
<p className="text-secondary leading-relaxed text-lg mb-4"> <p className="text-secondary leading-relaxed text-lg mb-4">
SecureBit.chat dominates in 11 out of 15 security categories, establishing itself as the most secure P2P messenger available. SecureBit.chat dominates in 11 out of 15 security categories, establishing itself as the most secure P2P messenger available.
@@ -2004,7 +2002,7 @@
React.createElement('i', { React.createElement('i', {
className: 'fas fa-check-circle mr-2' className: 'fas fa-check-circle mr-2'
}), }),
'Encrypted invitation created! Send the code and password to your contact.:' 'Encrypted invitation created! Send the code and password to your contact:'
]), ]),
offerPassword && React.createElement('div', { offerPassword && React.createElement('div', {
key: 'password-display', key: 'password-display',
@@ -2051,63 +2049,63 @@
]), ]),
// Step 2 - Session Type Selection // Step 2 - Session Type Selection
// showOfferStep && React.createElement('div', {
// key: 'step2',
// className: "card-minimal rounded-xl p-6"
// }, [
// React.createElement('div', {
// key: 'step-header',
// className: "flex items-center mb-4"
// }, [
// React.createElement('div', {
// key: 'number',
// className: "w-8 h-8 bg-green-500 text-white rounded-lg flex items-center justify-center font-semibold text-sm mr-3"
// }, '2'),
// React.createElement('h3', {
// key: 'title',
// className: "text-lg font-medium text-primary"
// }, "Select session type")
// ]),
// React.createElement('p', {
// key: 'description',
// className: "text-secondary text-sm mb-4"
// }, "Choose a session plan or use limited demo mode for testing."),
// React.createElement(SessionTypeSelector, {
// key: 'session-selector',
// onSelectType: (sessionType) => {
// // Save the selected session type
// setSelectedSessionType(sessionType);
// console.log('🎯 Session type selected:', sessionType);
// // FIX: For demo sessions, we immediately call automatic activation
// if (sessionType === 'demo') {
// console.log('🎮 Demo session selected, scheduling automatic activation...');
// // Delay activation for 2 seconds to stabilize
// setTimeout(() => {
// if (sessionManager) {
// console.log('🚀 Triggering demo session activation from selection...');
// handleDemoVerification();
// }
// }, 2000);
// }
// // Open a modal payment window
// if (typeof window.showPaymentModal === 'function') {
// window.showPaymentModal(sessionType);
// } else {
// // Fallback - show session information
// console.log('Selected session type:', sessionType);
// }
// },
// onCancel: resetToSelect,
// sessionManager: window.sessionManager
// })
// ]),
// Step 3 - Waiting for response
showOfferStep && React.createElement('div', { showOfferStep && React.createElement('div', {
key: 'step2', key: 'step2',
className: "card-minimal rounded-xl p-6" className: "card-minimal rounded-xl p-6"
}, [
React.createElement('div', {
key: 'step-header',
className: "flex items-center mb-4"
}, [
React.createElement('div', {
key: 'number',
className: "w-8 h-8 bg-green-500 text-white rounded-lg flex items-center justify-center font-semibold text-sm mr-3"
}, '2'),
React.createElement('h3', {
key: 'title',
className: "text-lg font-medium text-primary"
}, "Select session type")
]),
React.createElement('p', {
key: 'description',
className: "text-secondary text-sm mb-4"
}, "Choose a session plan or use limited demo mode for testing."),
React.createElement(SessionTypeSelector, {
key: 'session-selector',
onSelectType: (sessionType) => {
// Save the selected session type
setSelectedSessionType(sessionType);
console.log('🎯 Session type selected:', sessionType);
// FIX: For demo sessions, we immediately call automatic activation
if (sessionType === 'demo') {
console.log('🎮 Demo session selected, scheduling automatic activation...');
// Delay activation for 2 seconds to stabilize
setTimeout(() => {
if (sessionManager) {
console.log('🚀 Triggering demo session activation from selection...');
handleDemoVerification();
}
}, 2000);
}
// Open a modal payment window
if (typeof window.showPaymentModal === 'function') {
window.showPaymentModal(sessionType);
} else {
// Fallback - show session information
console.log('Selected session type:', sessionType);
}
},
onCancel: resetToSelect,
sessionManager: window.sessionManager
})
]),
// Step 3 - Waiting for response
showOfferStep && React.createElement('div', {
key: 'step3',
className: "card-minimal rounded-xl p-6"
}, [ }, [
React.createElement('div', { React.createElement('div', {
key: 'step-header', key: 'step-header',
@@ -2116,7 +2114,7 @@
React.createElement('div', { React.createElement('div', {
key: 'number', key: 'number',
className: "w-8 h-8 bg-blue-500 text-white rounded-lg flex items-center justify-center font-semibold text-sm mr-3" className: "w-8 h-8 bg-blue-500 text-white rounded-lg flex items-center justify-center font-semibold text-sm mr-3"
}, '3'), }, '2'),
React.createElement('h3', { React.createElement('h3', {
key: 'title', key: 'title',
className: "text-lg font-medium text-primary" className: "text-lg font-medium text-primary"
@@ -3794,36 +3792,175 @@ console.log('✅ Global timer management functions loaded');
<script src="./src/pwa/offline-manager.js"></script> <script src="./src/pwa/offline-manager.js"></script>
<link rel="stylesheet" href="./src/styles/pwa.css"> <link rel="stylesheet" href="./src/styles/pwa.css">
<script> <script>
// PWA Registration Script // PWA Service Worker Registration
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => { window.addEventListener('load', async () => {
try { try {
const registration = await navigator.serviceWorker.register('./sw.js'); const registration = await navigator.serviceWorker.register('./sw.js', {
console.log('✅ PWA: Service Worker registered'); scope: './'
});
console.log('✅ PWA: Service Worker registered successfully');
console.log('📡 SW Scope:', registration.scope);
// Store registration for use in other modules
window.swRegistration = registration;
// Listen for updates
registration.addEventListener('updatefound', () => {
console.log('🔄 PWA: Service Worker update found');
const newWorker = registration.installing;
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
console.log('🆕 PWA: New version available');
showUpdateNotification();
}
});
});
} catch (error) { } catch (error) {
console.error('❌ PWA: Service Worker registration failed:', error); console.error('❌ PWA: Service Worker registration failed:', error);
// Show fallback notification
if (window.DEBUG_MODE) {
setTimeout(() => {
showServiceWorkerError(error);
}, 2000);
}
} }
}); });
} }
// Handle PWA install prompt if ('serviceWorker' in navigator) {
let deferredPrompt; navigator.serviceWorker.ready.then(registration => {
window.addEventListener('beforeinstallprompt', (e) => { console.log('🎯 PWA: Service Worker ready');
e.preventDefault();
deferredPrompt = e;
showInstallButton();
});
function showInstallButton() { if (window.pwaInstallPrompt && window.pwaInstallPrompt.setServiceWorkerRegistration) {
// Show install button in your UI window.pwaInstallPrompt.setServiceWorkerRegistration(registration);
console.log('💿 PWA: Install prompt available'); }
if (window.pwaOfflineManager && window.pwaOfflineManager.setServiceWorkerRegistration) {
window.pwaOfflineManager.setServiceWorkerRegistration(registration);
}
});
} }
// Handle app installation function showUpdateNotification() {
window.addEventListener('appinstalled', () => { const notification = document.createElement('div');
console.log('✅ PWA: App installed successfully'); notification.className = 'fixed top-4 left-1/2 transform -translate-x-1/2 bg-blue-500 text-white p-4 rounded-lg shadow-lg z-50 max-w-sm';
deferredPrompt = null; notification.innerHTML = `
<div class="flex items-center space-x-3">
<i class="fas fa-download text-lg"></i>
<div class="flex-1">
<div class="font-medium">Update Available</div>
<div class="text-sm opacity-90">A new version of SecureBit.chat is ready</div>
</div>
<button onclick="window.location.reload()"
class="bg-white/20 hover:bg-white/30 px-3 py-1 rounded text-sm font-medium transition-colors">
Update
</button>
</div>
`;
document.body.appendChild(notification);
setTimeout(() => {
if (notification.parentElement) {
notification.remove();
}
}, 30000);
}
function showServiceWorkerError(error) {
const errorNotification = document.createElement('div');
errorNotification.className = 'fixed bottom-4 right-4 bg-red-500/90 text-white p-4 rounded-lg shadow-lg z-50 max-w-sm backdrop-blur-sm';
errorNotification.innerHTML = `
<div class="flex items-start space-x-3">
<i class="fas fa-exclamation-triangle text-lg mt-0.5"></i>
<div class="flex-1">
<div class="font-medium">PWA Setup Issue</div>
<div class="text-sm opacity-90 mt-1">
Service Worker registration failed. Some offline features may not work.
</div>
<details class="mt-2">
<summary class="text-xs cursor-pointer opacity-75">Technical details</summary>
<code class="text-xs opacity-60 block mt-1 break-all">${error.message}</code>
</details>
</div>
<button onclick="this.parentElement.remove()"
class="text-white/70 hover:text-white transition-colors">
<i class="fas fa-times"></i>
</button>
</div>
`;
document.body.appendChild(errorNotification);
setTimeout(() => {
if (errorNotification.parentElement) {
errorNotification.remove();
}
}, 15000);
}
function checkPWASupport() {
const support = {
serviceWorker: 'serviceWorker' in navigator,
installPrompt: 'BeforeInstallPromptEvent' in window,
standalone: 'standalone' in navigator,
manifest: document.querySelector('link[rel="manifest"]') !== null
};
console.log('🔍 PWA Support Check:', support);
if (window.DEBUG_MODE) {
if (!support.serviceWorker) {
console.warn('⚠️ Service Workers not supported');
}
if (!support.manifest) {
console.warn('⚠️ Manifest not found');
}
}
return support;
}
document.addEventListener('DOMContentLoaded', () => {
checkPWASupport();
}); });
window.PWAUtils = {
forceUpdate: () => {
if (window.swRegistration) {
window.swRegistration.update();
}
},
checkForUpdates: async () => {
if (window.swRegistration) {
await window.swRegistration.update();
console.log('🔄 Checked for PWA updates');
}
},
getInstallStatus: () => {
if (window.pwaInstallPrompt) {
return window.pwaInstallPrompt.getInstallStatus();
}
return { isInstalled: false, canPrompt: false };
},
showInstallPrompt: () => {
if (window.pwaInstallPrompt) {
window.pwaInstallPrompt.showInstallPrompt();
} else {
console.warn('⚠️ PWA Install Prompt not initialized');
}
}
};
console.log('✅ PWA Registration and utilities loaded');
</script> </script>
</body> </body>
</html> </html>

BIN
logo/icon-128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
logo/icon-152x152.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
logo/icon-180x180.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
logo/icon-192x192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
logo/icon-256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
logo/icon-384x384.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
logo/icon-512x512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
logo/icon-72x72.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
logo/icon-96x96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -2,65 +2,88 @@
"name": "SecureBit.chat - Enhanced Security Edition", "name": "SecureBit.chat - Enhanced Security Edition",
"short_name": "SecureBit", "short_name": "SecureBit",
"description": "P2P messenger with military-grade cryptography and Lightning Network payments", "description": "P2P messenger with military-grade cryptography and Lightning Network payments",
"start_url": "/", "start_url": "./",
"display": "standalone", "display": "standalone",
"background_color": "#1a1a1a", "background_color": "#1a1a1a",
"theme_color": "#ff6b35", "theme_color": "#ff6b35",
"orientation": "portrait-primary", "orientation": "portrait-primary",
"scope": "/", "scope": "./",
"lang": "en", "lang": "en",
"dir": "ltr", "dir": "ltr",
"categories": ["communication", "security", "productivity"], "categories": ["communication", "security", "productivity"],
"iarc_rating_id": "",
"prefer_related_applications": false, "prefer_related_applications": false,
"icons": [ "icons": [
{ {
"src": "logo/icon-72x72.png", "src": "./logo/icon-72x72.png",
"sizes": "72x72", "sizes": "72x72",
"type": "image/png", "type": "image/png",
"purpose": "maskable any" "purpose": "any"
}, },
{ {
"src": "logo/icon-96x96.png", "src": "./logo/icon-96x96.png",
"sizes": "96x96", "sizes": "96x96",
"type": "image/png", "type": "image/png",
"purpose": "maskable any" "purpose": "any"
}, },
{ {
"src": "logo/icon-128x128.png", "src": "./logo/icon-128x128.png",
"sizes": "128x128", "sizes": "128x128",
"type": "image/png", "type": "image/png",
"purpose": "maskable any" "purpose": "any"
}, },
{ {
"src": "logo/icon-144x144.png", "src": "./logo/icon-144x144.png",
"sizes": "144x144", "sizes": "144x144",
"type": "image/png", "type": "image/png",
"purpose": "maskable any" "purpose": "any"
}, },
{ {
"src": "logo/icon-152x152.png", "src": "./logo/icon-152x152.png",
"sizes": "152x152", "sizes": "152x152",
"type": "image/png", "type": "image/png",
"purpose": "maskable any" "purpose": "any"
}, },
{ {
"src": "logo/icon-192x192.png", "src": "./logo/icon-180x180.png",
"sizes": "180x180",
"type": "image/png",
"purpose": "any"
},
{
"src": "./logo/icon-192x192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png", "type": "image/png",
"purpose": "maskable any" "purpose": "any"
}, },
{ {
"src": "logo/icon-384x384.png", "src": "./logo/icon-256x256.png",
"sizes": "256x256",
"type": "image/png",
"purpose": "any"
},
{
"src": "./logo/icon-384x384.png",
"sizes": "384x384", "sizes": "384x384",
"type": "image/png", "type": "image/png",
"purpose": "maskable any" "purpose": "any"
}, },
{ {
"src": "logo/icon-512x512.png", "src": "./logo/icon-512x512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png", "type": "image/png",
"purpose": "maskable any" "purpose": "any"
},
{
"src": "./logo/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "./logo/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
} }
], ],
"shortcuts": [ "shortcuts": [
@@ -68,11 +91,12 @@
"name": "Create Channel", "name": "Create Channel",
"short_name": "Create", "short_name": "Create",
"description": "Create a new secure channel", "description": "Create a new secure channel",
"url": "/?action=create", "url": "./?action=create",
"icons": [ "icons": [
{ {
"src": "logo/icon-96x96.png", "src": "./logo/icon-96x96.png",
"sizes": "96x96" "sizes": "96x96",
"type": "image/png"
} }
] ]
}, },
@@ -80,45 +104,14 @@
"name": "Join Channel", "name": "Join Channel",
"short_name": "Join", "short_name": "Join",
"description": "Join an existing secure channel", "description": "Join an existing secure channel",
"url": "/?action=join", "url": "./?action=join",
"icons": [ "icons": [
{ {
"src": "logo/icon-96x96.png", "src": "./logo/icon-96x96.png",
"sizes": "96x96" "sizes": "96x96",
"type": "image/png"
} }
] ]
} }
], ]
"screenshots": [
{
"src": "screenshots/desktop-1.png",
"sizes": "1280x720",
"type": "image/png",
"form_factor": "wide",
"label": "SecureBit.chat main interface"
},
{
"src": "screenshots/mobile-1.png",
"sizes": "414x896",
"type": "image/png",
"form_factor": "narrow",
"label": "SecureBit.chat mobile interface"
}
],
"related_applications": [],
"protocol_handlers": [
{
"protocol": "web+securebit",
"url": "/?invite=%s"
}
],
"share_target": {
"action": "/share",
"method": "GET",
"params": {
"title": "title",
"text": "text",
"url": "url"
}
}
} }

View File

@@ -497,7 +497,7 @@ const EnhancedMinimalHeader = ({
React.createElement('p', { React.createElement('p', {
key: 'subtitle', key: 'subtitle',
className: 'text-xs sm:text-sm text-muted hidden sm:block' className: 'text-xs sm:text-sm text-muted hidden sm:block'
}, 'End-to-end freedom. v4.01.212') }, 'End-to-end freedom. v4.01.222')
]) ])
]), ]),

View File

@@ -374,12 +374,7 @@ const SessionTypeSelector = ({ onSelectType, onCancel, sessionManager }) => {
onClick: onCancel, onClick: onCancel,
className: 'px-6 py-3 bg-gray-600 hover:bg-gray-500 text-white rounded-lg transition-all' className: 'px-6 py-3 bg-gray-600 hover:bg-gray-500 text-white rounded-lg transition-all'
}, 'Cancel'), }, 'Cancel'),
React.createElement('button', {
key: 'refresh',
onClick: updateDemoInfo,
className: 'px-3 py-3 bg-blue-600 hover:bg-blue-500 text-white rounded-lg transition-all',
title: 'Refresh demo status'
}, React.createElement('i', { className: 'fas fa-sync-alt' }))
]) ])
]); ]);
}; };

View File

@@ -1,6 +1,3 @@
// PWA Install Prompt Manager for SecureBit.chat
// Enhanced Security Edition v4.01.212
class PWAInstallPrompt { class PWAInstallPrompt {
constructor() { constructor() {
this.deferredPrompt = null; this.deferredPrompt = null;
@@ -21,11 +18,16 @@ class PWAInstallPrompt {
this.createInstallButton(); this.createInstallButton();
this.loadInstallPreferences(); this.loadInstallPreferences();
if (this.isIOSSafari() && !this.isInstalled && this.shouldShowPrompt()) {
setTimeout(() => {
this.showIOSInstallInstructions();
}, 3000);
}
console.log('✅ PWA Install Prompt initialized'); console.log('✅ PWA Install Prompt initialized');
} }
checkInstallationStatus() { checkInstallationStatus() {
// Check if app is already installed
if (window.matchMedia('(display-mode: standalone)').matches || if (window.matchMedia('(display-mode: standalone)').matches ||
window.navigator.standalone === true) { window.navigator.standalone === true) {
this.isInstalled = true; this.isInstalled = true;
@@ -34,17 +36,24 @@ class PWAInstallPrompt {
return true; return true;
} }
// Check for iOS Safari specific installation
if (this.isIOSSafari()) { if (this.isIOSSafari()) {
this.isInstalled = window.navigator.standalone === true; this.isInstalled = window.navigator.standalone === true;
if (this.isInstalled) {
console.log('📱 iOS PWA detected');
document.body.classList.add('pwa-installed', 'ios-pwa');
}
} }
document.body.classList.add(this.isInstalled ? 'pwa-installed' : 'pwa-browser'); document.body.classList.add(this.isInstalled ? 'pwa-installed' : 'pwa-browser');
if (this.isIOSSafari()) {
document.body.classList.add('ios-safari');
}
return this.isInstalled; return this.isInstalled;
} }
setupEventListeners() { setupEventListeners() {
// Capture the install prompt event
window.addEventListener('beforeinstallprompt', (event) => { window.addEventListener('beforeinstallprompt', (event) => {
console.log('💿 Install prompt event captured'); console.log('💿 Install prompt event captured');
event.preventDefault(); event.preventDefault();
@@ -55,7 +64,6 @@ class PWAInstallPrompt {
} }
}); });
// Handle successful installation
window.addEventListener('appinstalled', () => { window.addEventListener('appinstalled', () => {
console.log('✅ PWA installed successfully'); console.log('✅ PWA installed successfully');
this.isInstalled = true; this.isInstalled = true;
@@ -63,35 +71,45 @@ class PWAInstallPrompt {
this.showInstallSuccess(); this.showInstallSuccess();
this.saveInstallPreference('installed', true); this.saveInstallPreference('installed', true);
// Update UI for installed state
document.body.classList.remove('pwa-browser'); document.body.classList.remove('pwa-browser');
document.body.classList.add('pwa-installed'); document.body.classList.add('pwa-installed');
}); });
// Handle iOS installation detection
if (this.isIOSSafari()) { if (this.isIOSSafari()) {
let wasStandalone = window.navigator.standalone;
window.addEventListener('visibilitychange', () => { window.addEventListener('visibilitychange', () => {
if (document.hidden) return; if (document.hidden) return;
setTimeout(() => { setTimeout(() => {
if (window.navigator.standalone && !this.isInstalled) { const isStandalone = window.navigator.standalone;
if (isStandalone && !wasStandalone && !this.isInstalled) {
console.log('✅ iOS PWA installation detected');
this.isInstalled = true; this.isInstalled = true;
this.hideInstallPrompts(); this.hideInstallPrompts();
this.showInstallSuccess(); this.showInstallSuccess();
document.body.classList.remove('pwa-browser');
document.body.classList.add('pwa-installed', 'ios-pwa');
} }
wasStandalone = isStandalone;
}, 1000); }, 1000);
}); });
} }
} }
createInstallButton() { createInstallButton() {
// Create floating install button
this.installButton = document.createElement('button'); this.installButton = document.createElement('button');
this.installButton.id = 'pwa-install-button'; this.installButton.id = 'pwa-install-button';
this.installButton.className = 'hidden fixed bottom-6 right-6 bg-gradient-to-r from-orange-500 to-orange-600 hover:from-orange-600 hover:to-orange-700 text-white px-6 py-3 rounded-full shadow-lg transition-all duration-300 z-50 flex items-center space-x-3 group'; this.installButton.className = 'hidden fixed bottom-6 right-6 bg-gradient-to-r from-orange-500 to-orange-600 hover:from-orange-600 hover:to-orange-700 text-white px-6 py-3 rounded-full shadow-lg transition-all duration-300 z-50 flex items-center space-x-3 group';
const buttonText = this.isIOSSafari() ? 'Install App' : 'Install App';
const buttonIcon = this.isIOSSafari() ? 'fas fa-share' : 'fas fa-download';
this.installButton.innerHTML = ` this.installButton.innerHTML = `
<i class="fas fa-download transition-transform group-hover:scale-110"></i> <i class="${buttonIcon} transition-transform group-hover:scale-110"></i>
<span class="font-medium">Install App</span> <span class="font-medium">${buttonText}</span>
<div class="absolute -top-1 -right-1 w-3 h-3 bg-green-400 rounded-full animate-pulse"></div> <div class="absolute -top-1 -right-1 w-3 h-3 bg-green-400 rounded-full animate-pulse"></div>
`; `;
@@ -109,23 +127,27 @@ class PWAInstallPrompt {
this.installBanner.id = 'pwa-install-banner'; this.installBanner.id = 'pwa-install-banner';
this.installBanner.className = 'pwa-install-banner fixed bottom-0 left-0 right-0 transform translate-y-full transition-transform duration-300 z-40'; this.installBanner.className = 'pwa-install-banner fixed bottom-0 left-0 right-0 transform translate-y-full transition-transform duration-300 z-40';
this.installBanner.innerHTML = ` this.installBanner.innerHTML = `
<div class="content"> <div class="bg-gray-800/95 backdrop-blur-sm border-t border-gray-600/30 p-4">
<div class="icon"> <div class="max-w-4xl mx-auto flex items-center justify-between">
<i class="fas fa-shield-halved text-2xl"></i> <div class="flex items-center space-x-4">
<div class="w-12 h-12 bg-orange-500/10 border border-orange-500/20 rounded-lg flex items-center justify-center">
<i class="fas fa-shield-halved text-orange-400 text-xl"></i>
</div>
<div>
<div class="font-medium text-white">Install SecureBit.chat</div>
<div class="text-sm text-gray-300">Get the native app experience with enhanced security</div>
</div>
</div>
<div class="flex items-center space-x-3">
<button class="install-btn bg-orange-500 hover:bg-orange-600 text-white px-4 py-2 rounded-lg font-medium transition-colors" data-action="install">
<i class="fas fa-download mr-2"></i>
Install
</button>
<button class="dismiss-btn text-gray-400 hover:text-white px-3 py-2 rounded-lg transition-colors" data-action="dismiss">
Later
</button>
</div>
</div> </div>
<div class="text">
<div class="title">Install SecureBit.chat</div>
<div class="subtitle">Get the native app experience with enhanced security</div>
</div>
</div>
<div class="actions">
<button class="install-btn" data-action="install">
<i class="fas fa-download mr-2"></i>
Install
</button>
<button class="dismiss-btn" data-action="dismiss">
Later
</button>
</div> </div>
`; `;
@@ -146,11 +168,11 @@ class PWAInstallPrompt {
showInstallOptions() { showInstallOptions() {
if (this.isInstalled) return; if (this.isInstalled) return;
// For mobile devices, show banner if (this.isIOSSafari()) {
if (this.isMobileDevice()) { this.showInstallButton();
} else if (this.isMobileDevice()) {
this.showInstallBanner(); this.showInstallBanner();
} else { } else {
// For desktop, show floating button
this.showInstallButton(); this.showInstallButton();
} }
} }
@@ -179,6 +201,7 @@ class PWAInstallPrompt {
if (this.installBanner && !this.isInstalled) { if (this.installBanner && !this.isInstalled) {
setTimeout(() => { setTimeout(() => {
this.installBanner.classList.add('show'); this.installBanner.classList.add('show');
this.installBanner.style.transform = 'translateY(0)';
}, 1000); }, 1000);
console.log('💿 Install banner shown'); console.log('💿 Install banner shown');
@@ -192,12 +215,13 @@ class PWAInstallPrompt {
if (this.installBanner) { if (this.installBanner) {
this.installBanner.classList.remove('show'); this.installBanner.classList.remove('show');
this.installBanner.style.transform = 'translateY(100%)';
} }
} }
async handleInstallClick() { async handleInstallClick() {
if (this.isIOSSafari()) { if (this.isIOSSafari()) {
this.showIOSInstructions(); this.showIOSInstallInstructions();
return; return;
} }
@@ -210,7 +234,6 @@ class PWAInstallPrompt {
try { try {
console.log('💿 Showing install prompt...'); console.log('💿 Showing install prompt...');
// Show the install prompt
const result = await this.deferredPrompt.prompt(); const result = await this.deferredPrompt.prompt();
console.log('💿 Install prompt result:', result.outcome); console.log('💿 Install prompt result:', result.outcome);
@@ -223,7 +246,6 @@ class PWAInstallPrompt {
this.handleInstallDismissal(); this.handleInstallDismissal();
} }
// Clear the deferred prompt
this.deferredPrompt = null; this.deferredPrompt = null;
} catch (error) { } catch (error) {
@@ -232,42 +254,73 @@ class PWAInstallPrompt {
} }
} }
showIOSInstructions() { showIOSInstallInstructions() {
const modal = document.createElement('div'); const modal = document.createElement('div');
modal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4'; modal.className = 'fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4 backdrop-blur-sm';
modal.innerHTML = ` modal.innerHTML = `
<div class="bg-gray-800 rounded-xl p-6 max-w-sm w-full text-center"> <div class="bg-gray-800 rounded-xl p-6 max-w-sm w-full text-center">
<div class="w-16 h-16 bg-blue-500/10 rounded-full flex items-center justify-center mx-auto mb-4"> <div class="w-16 h-16 bg-blue-500/10 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fab fa-apple text-blue-400 text-2xl"></i> <i class="fab fa-apple text-blue-400 text-2xl"></i>
</div> </div>
<h3 class="text-xl font-semibold text-white mb-4">Install on iOS</h3> <h3 class="text-xl font-semibold text-white mb-4">Install on iOS</h3>
<div class="space-y-3 text-left text-sm text-gray-300">
<div class="flex items-center space-x-3"> <div class="space-y-4 text-left text-sm text-gray-300 mb-6">
<div class="w-6 h-6 bg-blue-500 rounded text-white flex items-center justify-center text-xs font-bold">1</div> <div class="flex items-start space-x-3">
<span>Tap the Share button <i class="fas fa-share text-blue-400"></i></span> <div class="w-8 h-8 bg-blue-500 rounded-full text-white flex items-center justify-center text-sm font-bold flex-shrink-0 mt-0.5">1</div>
<div class="flex-1">
<div class="font-medium text-white mb-1">Tap the Share button</div>
<div class="flex items-center text-blue-400">
<i class="fas fa-share mr-2"></i>
<span>Usually at the bottom of Safari</span>
</div>
</div>
</div> </div>
<div class="flex items-center space-x-3">
<div class="w-6 h-6 bg-blue-500 rounded text-white flex items-center justify-center text-xs font-bold">2</div> <div class="flex items-start space-x-3">
<span>Select "Add to Home Screen"</span> <div class="w-8 h-8 bg-blue-500 rounded-full text-white flex items-center justify-center text-sm font-bold flex-shrink-0 mt-0.5">2</div>
<div class="flex-1">
<div class="font-medium text-white mb-1">Find "Add to Home Screen"</div>
<div class="text-gray-400">Scroll down in the share menu</div>
</div>
</div> </div>
<div class="flex items-center space-x-3">
<div class="w-6 h-6 bg-blue-500 rounded text-white flex items-center justify-center text-xs font-bold">3</div> <div class="flex items-start space-x-3">
<span>Tap "Add" to install</span> <div class="w-8 h-8 bg-blue-500 rounded-full text-white flex items-center justify-center text-sm font-bold flex-shrink-0 mt-0.5">3</div>
<div class="flex-1">
<div class="font-medium text-white mb-1">Tap "Add"</div>
<div class="text-gray-400">Confirm to install SecureBit.chat</div>
</div>
</div> </div>
</div> </div>
<button onclick="this.parentElement.parentElement.remove()"
class="w-full bg-blue-500 hover:bg-blue-600 text-white py-3 px-4 rounded-lg font-medium transition-colors mt-6"> <div class="bg-orange-500/10 border border-orange-500/20 rounded-lg p-3 mb-4">
Got it <p class="text-orange-300 text-xs">
</button> <i class="fas fa-info-circle mr-1"></i>
After installation, open SecureBit from your home screen for the best experience.
</p>
</div>
<div class="flex space-x-3">
<button onclick="this.parentElement.parentElement.remove(); localStorage.setItem('ios_install_shown', Date.now());"
class="flex-1 bg-blue-500 hover:bg-blue-600 text-white py-3 px-4 rounded-lg font-medium transition-colors">
Got it
</button>
<button onclick="this.parentElement.parentElement.remove(); localStorage.setItem('ios_install_dismissed', Date.now());"
class="flex-1 bg-gray-600 hover:bg-gray-500 text-white py-3 px-4 rounded-lg font-medium transition-colors">
Later
</button>
</div>
</div> </div>
`; `;
document.body.appendChild(modal); document.body.appendChild(modal);
this.saveInstallPreference('ios_instructions_shown', Date.now());
} }
showFallbackInstructions() { showFallbackInstructions() {
const modal = document.createElement('div'); const modal = document.createElement('div');
modal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4'; modal.className = 'fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4 backdrop-blur-sm';
modal.innerHTML = ` modal.innerHTML = `
<div class="bg-gray-800 rounded-xl p-6 max-w-md w-full text-center"> <div class="bg-gray-800 rounded-xl p-6 max-w-md w-full text-center">
<div class="w-16 h-16 bg-orange-500/10 rounded-full flex items-center justify-center mx-auto mb-4"> <div class="w-16 h-16 bg-orange-500/10 rounded-full flex items-center justify-center mx-auto mb-4">
@@ -307,6 +360,11 @@ class PWAInstallPrompt {
showInstallSuccess() { showInstallSuccess() {
const notification = document.createElement('div'); const notification = document.createElement('div');
notification.className = 'fixed top-4 right-4 bg-green-500 text-white p-4 rounded-lg shadow-lg z-50 max-w-sm transform translate-x-full transition-transform duration-300'; notification.className = 'fixed top-4 right-4 bg-green-500 text-white p-4 rounded-lg shadow-lg z-50 max-w-sm transform translate-x-full transition-transform duration-300';
const successText = this.isIOSSafari() ?
'iOS App installed! Open from home screen.' :
'SecureBit.chat is now on your device';
notification.innerHTML = ` notification.innerHTML = `
<div class="flex items-center space-x-3"> <div class="flex items-center space-x-3">
<div class="w-8 h-8 bg-white/20 rounded-full flex items-center justify-center"> <div class="w-8 h-8 bg-white/20 rounded-full flex items-center justify-center">
@@ -314,23 +372,51 @@ class PWAInstallPrompt {
</div> </div>
<div> <div>
<div class="font-medium">App Installed!</div> <div class="font-medium">App Installed!</div>
<div class="text-sm opacity-90">SecureBit.chat is now on your device</div> <div class="text-sm opacity-90">${successText}</div>
</div> </div>
</div> </div>
`; `;
document.body.appendChild(notification); document.body.appendChild(notification);
// Animate in
setTimeout(() => { setTimeout(() => {
notification.classList.remove('translate-x-full'); notification.classList.remove('translate-x-full');
}, 100); }, 100);
// Auto-remove after 4 seconds
setTimeout(() => { setTimeout(() => {
notification.classList.add('translate-x-full'); notification.classList.add('translate-x-full');
setTimeout(() => notification.remove(), 300); setTimeout(() => notification.remove(), 300);
}, 4000); }, 5000);
}
shouldShowPrompt() {
const preferences = this.loadInstallPreferences();
if (this.isInstalled) return false;
if (this.isIOSSafari()) {
const lastShown = preferences.ios_instructions_shown;
const lastDismissed = localStorage.getItem('ios_install_dismissed');
if (lastShown && Date.now() - lastShown < 24 * 60 * 60 * 1000) {
return false;
}
if (lastDismissed && Date.now() - parseInt(lastDismissed) < 7 * 24 * 60 * 60 * 1000) {
return false;
}
return true;
}
if (preferences.dismissed >= this.maxDismissals) return false;
const lastDismissed = preferences.lastDismissed;
if (lastDismissed && Date.now() - lastDismissed < 24 * 60 * 60 * 1000) {
return false;
}
return true;
} }
dismissInstallPrompt() { dismissInstallPrompt() {
@@ -351,12 +437,11 @@ class PWAInstallPrompt {
this.saveInstallPreference('dismissed', this.dismissedCount); this.saveInstallPreference('dismissed', this.dismissedCount);
if (this.dismissedCount < this.maxDismissals) { if (this.dismissedCount < this.maxDismissals) {
// Show reminder after some time
setTimeout(() => { setTimeout(() => {
if (!this.isInstalled && this.shouldShowPrompt()) { if (!this.isInstalled && this.shouldShowPrompt()) {
this.showInstallButton(); this.showInstallButton();
} }
}, 300000); // 5 minutes }, 300000);
} }
} }
@@ -390,24 +475,6 @@ class PWAInstallPrompt {
}, 10000); }, 10000);
} }
shouldShowPrompt() {
const preferences = this.loadInstallPreferences();
// Don't show if already installed
if (this.isInstalled) return false;
// Don't show if dismissed too many times
if (preferences.dismissed >= this.maxDismissals) return false;
// Don't show if recently dismissed (less than 24 hours)
const lastDismissed = preferences.lastDismissed;
if (lastDismissed && Date.now() - lastDismissed < 24 * 60 * 60 * 1000) {
return false;
}
return true;
}
saveInstallPreference(action, value) { saveInstallPreference(action, value) {
const preferences = this.loadInstallPreferences(); const preferences = this.loadInstallPreferences();
preferences[action] = value; preferences[action] = value;
@@ -439,12 +506,16 @@ class PWAInstallPrompt {
isIOSSafari() { isIOSSafari() {
const userAgent = navigator.userAgent; const userAgent = navigator.userAgent;
return /iPad|iPhone|iPod/.test(userAgent) && /Safari/.test(userAgent) && !/CriOS|FxiOS/.test(userAgent); const isIOS = /iPad|iPhone|iPod/.test(userAgent);
const isSafari = /Safari/.test(userAgent) && !/CriOS|FxiOS|EdgiOS/.test(userAgent);
return isIOS && isSafari;
} }
// Public API methods // Public API methods
showInstallPrompt() { showInstallPrompt() {
if (this.deferredPrompt && !this.isInstalled) { if (this.isIOSSafari()) {
this.showIOSInstallInstructions();
} else if (this.deferredPrompt && !this.isInstalled) {
this.handleInstallClick(); this.handleInstallClick();
} else { } else {
this.showFallbackInstructions(); this.showFallbackInstructions();
@@ -459,6 +530,7 @@ class PWAInstallPrompt {
return { return {
isInstalled: this.isInstalled, isInstalled: this.isInstalled,
canPrompt: !!this.deferredPrompt, canPrompt: !!this.deferredPrompt,
isIOSSafari: this.isIOSSafari(),
dismissedCount: this.dismissedCount, dismissedCount: this.dismissedCount,
shouldShowPrompt: this.shouldShowPrompt() shouldShowPrompt: this.shouldShowPrompt()
}; };
@@ -469,6 +541,12 @@ class PWAInstallPrompt {
this.saveInstallPreference('dismissed', 0); this.saveInstallPreference('dismissed', 0);
console.log('💿 Install dismissals reset'); console.log('💿 Install dismissals reset');
} }
// Method for setting service worker registration
setServiceWorkerRegistration(registration) {
this.swRegistration = registration;
console.log('📡 Service Worker registration set for PWA Install Prompt');
}
} }
// Export for module use // Export for module use

View File

@@ -1,5 +1,5 @@
// PWA Offline Manager for SecureBit.chat // PWA Offline Manager for SecureBit.chat
// Enhanced Security Edition v4.01.212 // Enhanced Security Edition v4.01.222
// Handles offline functionality, data synchronization, and user experience // Handles offline functionality, data synchronization, and user experience
class PWAOfflineManager { class PWAOfflineManager {

View File

@@ -164,11 +164,11 @@ main {
border: 1px solid rgba(75, 85, 99, 0.2); border: 1px solid rgba(75, 85, 99, 0.2);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
} }
.card-minimal:hover { /* .card-minimal:hover {
border-color: rgba(249, 115, 22, 0.3); border-color: rgba(249, 115, 22, 0.3);
transform: translateY(-1px); transform: translateY(-1px);
transition: all 0.2s ease; transition: all 0.2s ease;
} } */
.status-dot { .status-dot {
width: 8px; width: 8px;

4
sw.js
View File

@@ -1,5 +1,5 @@
// SecureBit.chat Service Worker // SecureBit.chat Service Worker
// Enhanced Security Edition v4.01.212 // Enhanced Security Edition v4.01.222
const CACHE_NAME = 'securebit-v4.0.3'; const CACHE_NAME = 'securebit-v4.0.3';
const STATIC_CACHE = 'securebit-static-v4.0.3'; const STATIC_CACHE = 'securebit-static-v4.0.3';
@@ -352,4 +352,4 @@ self.addEventListener('unhandledrejection', (event) => {
console.error('❌ Service Worker unhandled rejection:', event.reason); console.error('❌ Service Worker unhandled rejection:', event.reason);
}); });
console.log('🔧 SecureBit.chat Service Worker loaded - Enhanced Security Edition v4.01.212'); console.log('🔧 SecureBit.chat Service Worker loaded - Enhanced Security Edition v4.01.222');