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."
@@ -1,6 +1,6 @@
|
||||
# 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
|
||||
|
||||
@@ -203,6 +203,6 @@ This software is created to:
|
||||
---
|
||||
|
||||
*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**
|
||||
343
index.html
@@ -24,45 +24,43 @@
|
||||
<!-- PWA Meta Tags -->
|
||||
<meta name="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-title" content="SecureBit">
|
||||
<meta name="application-name" content="SecureBit">
|
||||
<meta name="msapplication-TileColor" content="#ff6b35">
|
||||
<meta name="msapplication-config" content="/browserconfig.xml">
|
||||
|
||||
<!-- 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-750x1334.png" 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-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-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-1536x2048.png" media="(min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
|
||||
<!-- 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-750x1334.png"
|
||||
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-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 -->
|
||||
<link rel="apple-touch-icon" href="./logo/pwa/ios/57.png" sizes="57x57">
|
||||
<link rel="apple-touch-icon" href="./logo/pwa/ios/60.png" sizes="60x60">
|
||||
<link rel="apple-touch-icon" href="./logo/pwa/ios/72.png" sizes="72x72">
|
||||
<link rel="apple-touch-icon" href="./logo/pwa/ios/76.png" sizes="76x76">
|
||||
<link rel="apple-touch-icon" href="./logo/pwa/ios/114.png" sizes="114x114">
|
||||
<link rel="apple-touch-icon" href="./logo/pwa/ios/120.png" sizes="120x120">
|
||||
<link rel="apple-touch-icon" href="./logo/pwa/ios/144.png" sizes="144x144">
|
||||
<link rel="apple-touch-icon" href="./logo/pwa/ios/152.png" sizes="152x152">
|
||||
<link rel="apple-touch-icon" href="./logo/pwa/ios/180.png" sizes="180x180">
|
||||
<link rel="apple-touch-icon" href="./logo/icon-180x180.png">
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="./logo/icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="./logo/icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="./logo/icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="./logo/icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="./logo/icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="./logo/icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="./logo/icon-144x144.png">
|
||||
<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 -->
|
||||
<meta name="msapplication-TileImage" content="./logo/pwa/windows11/Square150x150Logo.scale-100.png">
|
||||
<meta name="msapplication-square70x70logo" content="./logo/pwa/windows11/SmallTile.scale-100.png">
|
||||
<meta name="msapplication-square150x150logo" content="./logo/pwa/windows11/Square150x150Logo.scale-100.png">
|
||||
<meta name="msapplication-wide310x150logo" content="./logo/pwa/windows11/Wide310x150Logo.scale-100.png">
|
||||
<meta name="msapplication-square310x310logo" content="./logo/pwa/windows11/LargeTile.scale-100.png">
|
||||
<meta name="msapplication-TileColor" content="#ff6b35">
|
||||
<meta name="msapplication-TileImage" content="./logo/icon-144x144.png">
|
||||
<meta name="msapplication-config" content="./browserconfig.xml">
|
||||
|
||||
|
||||
<!-- 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">
|
||||
<!-- Theme colors -->
|
||||
<meta name="theme-color" content="#ff6b35">
|
||||
<meta name="msapplication-navbutton-color" content="#ff6b35">
|
||||
|
||||
<!-- 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';">
|
||||
@@ -163,7 +161,7 @@
|
||||
icon: "fas fa-shield-halved",
|
||||
color: "orange",
|
||||
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",
|
||||
@@ -513,7 +511,7 @@
|
||||
Enhanced Security Edition Comparison
|
||||
</h3>
|
||||
<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>
|
||||
<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>
|
||||
@@ -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">
|
||||
<h4 className="text-xl font-bold text-orange-400 mb-4 flex items-center">
|
||||
<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>
|
||||
<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.
|
||||
@@ -2004,7 +2002,7 @@
|
||||
React.createElement('i', {
|
||||
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', {
|
||||
key: 'password-display',
|
||||
@@ -2051,63 +2049,63 @@
|
||||
]),
|
||||
|
||||
// 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', {
|
||||
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', {
|
||||
key: 'step3',
|
||||
className: "card-minimal rounded-xl p-6"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'step-header',
|
||||
@@ -2116,7 +2114,7 @@
|
||||
React.createElement('div', {
|
||||
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"
|
||||
}, '3'),
|
||||
}, '2'),
|
||||
React.createElement('h3', {
|
||||
key: 'title',
|
||||
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>
|
||||
<link rel="stylesheet" href="./src/styles/pwa.css">
|
||||
<script>
|
||||
// PWA Registration Script
|
||||
// PWA Service Worker Registration
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', async () => {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.register('./sw.js');
|
||||
console.log('✅ PWA: Service Worker registered');
|
||||
const registration = await navigator.serviceWorker.register('./sw.js', {
|
||||
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) {
|
||||
console.error('❌ PWA: Service Worker registration failed:', error);
|
||||
|
||||
// Show fallback notification
|
||||
if (window.DEBUG_MODE) {
|
||||
setTimeout(() => {
|
||||
showServiceWorkerError(error);
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle PWA install prompt
|
||||
let deferredPrompt;
|
||||
window.addEventListener('beforeinstallprompt', (e) => {
|
||||
e.preventDefault();
|
||||
deferredPrompt = e;
|
||||
showInstallButton();
|
||||
});
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
console.log('🎯 PWA: Service Worker ready');
|
||||
|
||||
function showInstallButton() {
|
||||
// Show install button in your UI
|
||||
console.log('💿 PWA: Install prompt available');
|
||||
if (window.pwaInstallPrompt && window.pwaInstallPrompt.setServiceWorkerRegistration) {
|
||||
window.pwaInstallPrompt.setServiceWorkerRegistration(registration);
|
||||
}
|
||||
|
||||
if (window.pwaOfflineManager && window.pwaOfflineManager.setServiceWorkerRegistration) {
|
||||
window.pwaOfflineManager.setServiceWorkerRegistration(registration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle app installation
|
||||
window.addEventListener('appinstalled', () => {
|
||||
console.log('✅ PWA: App installed successfully');
|
||||
deferredPrompt = null;
|
||||
function showUpdateNotification() {
|
||||
const notification = document.createElement('div');
|
||||
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';
|
||||
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>
|
||||
</body>
|
||||
</html>
|
||||
BIN
logo/icon-128x128.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
logo/icon-152x152.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
logo/icon-180x180.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
logo/icon-192x192.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
logo/icon-256x256.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
logo/icon-384x384.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
logo/icon-512x512.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
logo/icon-72x72.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
logo/icon-96x96.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
109
manifest.json
@@ -2,65 +2,88 @@
|
||||
"name": "SecureBit.chat - Enhanced Security Edition",
|
||||
"short_name": "SecureBit",
|
||||
"description": "P2P messenger with military-grade cryptography and Lightning Network payments",
|
||||
"start_url": "/",
|
||||
"start_url": "./",
|
||||
"display": "standalone",
|
||||
"background_color": "#1a1a1a",
|
||||
"theme_color": "#ff6b35",
|
||||
"orientation": "portrait-primary",
|
||||
"scope": "/",
|
||||
"scope": "./",
|
||||
"lang": "en",
|
||||
"dir": "ltr",
|
||||
"categories": ["communication", "security", "productivity"],
|
||||
"iarc_rating_id": "",
|
||||
"prefer_related_applications": false,
|
||||
"icons": [
|
||||
{
|
||||
"src": "logo/icon-72x72.png",
|
||||
"src": "./logo/icon-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "logo/icon-96x96.png",
|
||||
"src": "./logo/icon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "logo/icon-128x128.png",
|
||||
"src": "./logo/icon-128x128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "logo/icon-144x144.png",
|
||||
"src": "./logo/icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "logo/icon-152x152.png",
|
||||
"src": "./logo/icon-152x152.png",
|
||||
"sizes": "152x152",
|
||||
"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",
|
||||
"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",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "logo/icon-512x512.png",
|
||||
"src": "./logo/icon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"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": [
|
||||
@@ -68,11 +91,12 @@
|
||||
"name": "Create Channel",
|
||||
"short_name": "Create",
|
||||
"description": "Create a new secure channel",
|
||||
"url": "/?action=create",
|
||||
"url": "./?action=create",
|
||||
"icons": [
|
||||
{
|
||||
"src": "logo/icon-96x96.png",
|
||||
"sizes": "96x96"
|
||||
"src": "./logo/icon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -80,45 +104,14 @@
|
||||
"name": "Join Channel",
|
||||
"short_name": "Join",
|
||||
"description": "Join an existing secure channel",
|
||||
"url": "/?action=join",
|
||||
"url": "./?action=join",
|
||||
"icons": [
|
||||
{
|
||||
"src": "logo/icon-96x96.png",
|
||||
"sizes": "96x96"
|
||||
"src": "./logo/icon-96x96.png",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -497,7 +497,7 @@ const EnhancedMinimalHeader = ({
|
||||
React.createElement('p', {
|
||||
key: 'subtitle',
|
||||
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')
|
||||
])
|
||||
]),
|
||||
|
||||
|
||||
@@ -374,12 +374,7 @@ const SessionTypeSelector = ({ onSelectType, onCancel, sessionManager }) => {
|
||||
onClick: onCancel,
|
||||
className: 'px-6 py-3 bg-gray-600 hover:bg-gray-500 text-white rounded-lg transition-all'
|
||||
}, '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' }))
|
||||
|
||||
])
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// PWA Install Prompt Manager for SecureBit.chat
|
||||
// Enhanced Security Edition v4.01.212
|
||||
|
||||
class PWAInstallPrompt {
|
||||
constructor() {
|
||||
this.deferredPrompt = null;
|
||||
@@ -21,11 +18,16 @@ class PWAInstallPrompt {
|
||||
this.createInstallButton();
|
||||
this.loadInstallPreferences();
|
||||
|
||||
if (this.isIOSSafari() && !this.isInstalled && this.shouldShowPrompt()) {
|
||||
setTimeout(() => {
|
||||
this.showIOSInstallInstructions();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
console.log('✅ PWA Install Prompt initialized');
|
||||
}
|
||||
|
||||
checkInstallationStatus() {
|
||||
// Check if app is already installed
|
||||
if (window.matchMedia('(display-mode: standalone)').matches ||
|
||||
window.navigator.standalone === true) {
|
||||
this.isInstalled = true;
|
||||
@@ -34,17 +36,24 @@ class PWAInstallPrompt {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for iOS Safari specific installation
|
||||
if (this.isIOSSafari()) {
|
||||
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');
|
||||
|
||||
if (this.isIOSSafari()) {
|
||||
document.body.classList.add('ios-safari');
|
||||
}
|
||||
|
||||
return this.isInstalled;
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
// Capture the install prompt event
|
||||
window.addEventListener('beforeinstallprompt', (event) => {
|
||||
console.log('💿 Install prompt event captured');
|
||||
event.preventDefault();
|
||||
@@ -55,7 +64,6 @@ class PWAInstallPrompt {
|
||||
}
|
||||
});
|
||||
|
||||
// Handle successful installation
|
||||
window.addEventListener('appinstalled', () => {
|
||||
console.log('✅ PWA installed successfully');
|
||||
this.isInstalled = true;
|
||||
@@ -63,35 +71,45 @@ class PWAInstallPrompt {
|
||||
this.showInstallSuccess();
|
||||
this.saveInstallPreference('installed', true);
|
||||
|
||||
// Update UI for installed state
|
||||
document.body.classList.remove('pwa-browser');
|
||||
document.body.classList.add('pwa-installed');
|
||||
});
|
||||
|
||||
// Handle iOS installation detection
|
||||
if (this.isIOSSafari()) {
|
||||
let wasStandalone = window.navigator.standalone;
|
||||
|
||||
window.addEventListener('visibilitychange', () => {
|
||||
if (document.hidden) return;
|
||||
|
||||
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.hideInstallPrompts();
|
||||
this.showInstallSuccess();
|
||||
document.body.classList.remove('pwa-browser');
|
||||
document.body.classList.add('pwa-installed', 'ios-pwa');
|
||||
}
|
||||
|
||||
wasStandalone = isStandalone;
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
createInstallButton() {
|
||||
// Create floating install button
|
||||
this.installButton = document.createElement('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';
|
||||
|
||||
const buttonText = this.isIOSSafari() ? 'Install App' : 'Install App';
|
||||
const buttonIcon = this.isIOSSafari() ? 'fas fa-share' : 'fas fa-download';
|
||||
|
||||
this.installButton.innerHTML = `
|
||||
<i class="fas fa-download transition-transform group-hover:scale-110"></i>
|
||||
<span class="font-medium">Install App</span>
|
||||
<i class="${buttonIcon} transition-transform group-hover:scale-110"></i>
|
||||
<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>
|
||||
`;
|
||||
|
||||
@@ -109,23 +127,27 @@ class PWAInstallPrompt {
|
||||
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.innerHTML = `
|
||||
<div class="content">
|
||||
<div class="icon">
|
||||
<i class="fas fa-shield-halved text-2xl"></i>
|
||||
<div class="bg-gray-800/95 backdrop-blur-sm border-t border-gray-600/30 p-4">
|
||||
<div class="max-w-4xl mx-auto flex items-center justify-between">
|
||||
<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 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>
|
||||
`;
|
||||
|
||||
@@ -146,11 +168,11 @@ class PWAInstallPrompt {
|
||||
showInstallOptions() {
|
||||
if (this.isInstalled) return;
|
||||
|
||||
// For mobile devices, show banner
|
||||
if (this.isMobileDevice()) {
|
||||
if (this.isIOSSafari()) {
|
||||
this.showInstallButton();
|
||||
} else if (this.isMobileDevice()) {
|
||||
this.showInstallBanner();
|
||||
} else {
|
||||
// For desktop, show floating button
|
||||
this.showInstallButton();
|
||||
}
|
||||
}
|
||||
@@ -179,6 +201,7 @@ class PWAInstallPrompt {
|
||||
if (this.installBanner && !this.isInstalled) {
|
||||
setTimeout(() => {
|
||||
this.installBanner.classList.add('show');
|
||||
this.installBanner.style.transform = 'translateY(0)';
|
||||
}, 1000);
|
||||
|
||||
console.log('💿 Install banner shown');
|
||||
@@ -192,12 +215,13 @@ class PWAInstallPrompt {
|
||||
|
||||
if (this.installBanner) {
|
||||
this.installBanner.classList.remove('show');
|
||||
this.installBanner.style.transform = 'translateY(100%)';
|
||||
}
|
||||
}
|
||||
|
||||
async handleInstallClick() {
|
||||
if (this.isIOSSafari()) {
|
||||
this.showIOSInstructions();
|
||||
this.showIOSInstallInstructions();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -210,7 +234,6 @@ class PWAInstallPrompt {
|
||||
try {
|
||||
console.log('💿 Showing install prompt...');
|
||||
|
||||
// Show the install prompt
|
||||
const result = await this.deferredPrompt.prompt();
|
||||
console.log('💿 Install prompt result:', result.outcome);
|
||||
|
||||
@@ -223,7 +246,6 @@ class PWAInstallPrompt {
|
||||
this.handleInstallDismissal();
|
||||
}
|
||||
|
||||
// Clear the deferred prompt
|
||||
this.deferredPrompt = null;
|
||||
|
||||
} catch (error) {
|
||||
@@ -232,42 +254,73 @@ class PWAInstallPrompt {
|
||||
}
|
||||
}
|
||||
|
||||
showIOSInstructions() {
|
||||
showIOSInstallInstructions() {
|
||||
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 = `
|
||||
<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">
|
||||
<i class="fab fa-apple text-blue-400 text-2xl"></i>
|
||||
</div>
|
||||
<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="w-6 h-6 bg-blue-500 rounded text-white flex items-center justify-center text-xs font-bold">1</div>
|
||||
<span>Tap the Share button <i class="fas fa-share text-blue-400"></i></span>
|
||||
|
||||
<div class="space-y-4 text-left text-sm text-gray-300 mb-6">
|
||||
<div class="flex items-start space-x-3">
|
||||
<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 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>
|
||||
<span>Select "Add to Home Screen"</span>
|
||||
|
||||
<div class="flex items-start space-x-3">
|
||||
<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 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>
|
||||
<span>Tap "Add" to install</span>
|
||||
|
||||
<div class="flex items-start space-x-3">
|
||||
<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>
|
||||
<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">
|
||||
Got it
|
||||
</button>
|
||||
|
||||
<div class="bg-orange-500/10 border border-orange-500/20 rounded-lg p-3 mb-4">
|
||||
<p class="text-orange-300 text-xs">
|
||||
<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>
|
||||
`;
|
||||
|
||||
document.body.appendChild(modal);
|
||||
|
||||
this.saveInstallPreference('ios_instructions_shown', Date.now());
|
||||
}
|
||||
|
||||
showFallbackInstructions() {
|
||||
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 = `
|
||||
<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">
|
||||
@@ -307,6 +360,11 @@ class PWAInstallPrompt {
|
||||
showInstallSuccess() {
|
||||
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';
|
||||
|
||||
const successText = this.isIOSSafari() ?
|
||||
'iOS App installed! Open from home screen.' :
|
||||
'SecureBit.chat is now on your device';
|
||||
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center space-x-3">
|
||||
<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 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>
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Animate in
|
||||
setTimeout(() => {
|
||||
notification.classList.remove('translate-x-full');
|
||||
}, 100);
|
||||
|
||||
// Auto-remove after 4 seconds
|
||||
setTimeout(() => {
|
||||
notification.classList.add('translate-x-full');
|
||||
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() {
|
||||
@@ -351,12 +437,11 @@ class PWAInstallPrompt {
|
||||
this.saveInstallPreference('dismissed', this.dismissedCount);
|
||||
|
||||
if (this.dismissedCount < this.maxDismissals) {
|
||||
// Show reminder after some time
|
||||
setTimeout(() => {
|
||||
if (!this.isInstalled && this.shouldShowPrompt()) {
|
||||
this.showInstallButton();
|
||||
}
|
||||
}, 300000); // 5 minutes
|
||||
}, 300000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,24 +475,6 @@ class PWAInstallPrompt {
|
||||
}, 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) {
|
||||
const preferences = this.loadInstallPreferences();
|
||||
preferences[action] = value;
|
||||
@@ -439,12 +506,16 @@ class PWAInstallPrompt {
|
||||
|
||||
isIOSSafari() {
|
||||
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
|
||||
showInstallPrompt() {
|
||||
if (this.deferredPrompt && !this.isInstalled) {
|
||||
if (this.isIOSSafari()) {
|
||||
this.showIOSInstallInstructions();
|
||||
} else if (this.deferredPrompt && !this.isInstalled) {
|
||||
this.handleInstallClick();
|
||||
} else {
|
||||
this.showFallbackInstructions();
|
||||
@@ -459,6 +530,7 @@ class PWAInstallPrompt {
|
||||
return {
|
||||
isInstalled: this.isInstalled,
|
||||
canPrompt: !!this.deferredPrompt,
|
||||
isIOSSafari: this.isIOSSafari(),
|
||||
dismissedCount: this.dismissedCount,
|
||||
shouldShowPrompt: this.shouldShowPrompt()
|
||||
};
|
||||
@@ -469,6 +541,12 @@ class PWAInstallPrompt {
|
||||
this.saveInstallPreference('dismissed', 0);
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
|
||||
class PWAOfflineManager {
|
||||
|
||||
@@ -164,11 +164,11 @@ main {
|
||||
border: 1px solid rgba(75, 85, 99, 0.2);
|
||||
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);
|
||||
transform: translateY(-1px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
} */
|
||||
|
||||
.status-dot {
|
||||
width: 8px;
|
||||
|
||||
4
sw.js
@@ -1,5 +1,5 @@
|
||||
// SecureBit.chat Service Worker
|
||||
// Enhanced Security Edition v4.01.212
|
||||
// Enhanced Security Edition v4.01.222
|
||||
|
||||
const CACHE_NAME = 'securebit-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.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');
|
||||