fix: prevent install prompt showing in installed PWA

- Improve installation status detection logic
- Add proper DOM cleanup when PWA is installed
- Enhance monitoring for installation state changes
- Fix shouldShowPrompt() logic to always check current status
- Add forceInstallationCheck() method for manual status updates
This commit is contained in:
lockbitchat
2025-08-24 17:07:31 -04:00
parent 26ba6eebb9
commit dde7196bb8

View File

@@ -14,10 +14,8 @@ class PWAInstallPrompt {
init() {
console.log('💿 PWA Install Prompt initializing...');
// Сначала проверяем статус установки
this.checkInstallationStatus();
// Если уже установлено, не инициализируем остальное
if (this.isInstalled) {
console.log('💿 App already installed, skipping initialization');
return;
@@ -27,7 +25,6 @@ class PWAInstallPrompt {
this.createInstallButton();
this.loadInstallPreferences();
// Проверяем статус установки периодически для iOS
if (this.isIOSSafari()) {
this.startInstallationMonitoring();
}
@@ -38,7 +35,6 @@ class PWAInstallPrompt {
checkInstallationStatus() {
console.log('🔍 Checking PWA installation status...');
// Проверяем различные способы определения установки PWA
const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
const isIOSStandalone = window.navigator.standalone === true;
const hasInstallPreference = this.loadInstallPreferences().installed;
@@ -50,17 +46,14 @@ class PWAInstallPrompt {
userAgent: navigator.userAgent.slice(0, 100)
});
// Проверяем, установлено ли приложение
if (isStandalone || isIOSStandalone || hasInstallPreference) {
this.isInstalled = true;
console.log('📱 App is already installed as PWA');
document.body.classList.add('pwa-installed');
document.body.classList.remove('pwa-browser');
// Скрываем все промпты установки
this.hideInstallPrompts();
// Если это iOS, добавляем специальный класс
if (this.isIOSSafari()) {
document.body.classList.add('ios-pwa');
}
@@ -69,7 +62,6 @@ class PWAInstallPrompt {
return true;
}
// Если не установлено, добавляем соответствующие классы
this.isInstalled = false;
document.body.classList.add('pwa-browser');
document.body.classList.remove('pwa-installed');
@@ -83,7 +75,6 @@ class PWAInstallPrompt {
}
startInstallationMonitoring() {
// Для iOS Safari мониторим изменения в standalone режиме
let wasStandalone = window.navigator.standalone;
const checkStandalone = () => {
@@ -97,24 +88,20 @@ class PWAInstallPrompt {
document.body.classList.remove('pwa-browser', 'ios-safari');
document.body.classList.add('pwa-installed', 'ios-pwa');
// Сохраняем предпочтение установки
this.saveInstallPreference('installed', true);
}
wasStandalone = isStandalone;
};
// Проверяем каждые 2 секунды
setInterval(checkStandalone, 2000);
// Также проверяем при изменении видимости страницы
window.addEventListener('visibilitychange', () => {
if (!document.hidden) {
setTimeout(checkStandalone, 1000);
}
});
// Проверяем при фокусе окна
window.addEventListener('focus', () => {
setTimeout(checkStandalone, 500);
});
@@ -126,12 +113,10 @@ class PWAInstallPrompt {
event.preventDefault();
this.deferredPrompt = event;
// Повторно проверяем статус установки
if (this.checkInstallationStatus()) {
return; // Если установлено, не показываем промпт
return;
}
// Показываем промпт только если приложение не установлено
if (!this.isInstalled && this.shouldShowPrompt()) {
setTimeout(() => this.showInstallOptions(), 1000);
}
@@ -148,7 +133,6 @@ class PWAInstallPrompt {
document.body.classList.add('pwa-installed');
});
// Дополнительная проверка для всех устройств при изменении видимости
window.addEventListener('visibilitychange', () => {
if (document.hidden) return;
@@ -156,7 +140,6 @@ class PWAInstallPrompt {
const wasInstalled = this.isInstalled;
this.checkInstallationStatus();
// Если статус изменился с "не установлено" на "установлено"
if (!wasInstalled && this.isInstalled) {
console.log('✅ PWA installation detected on visibility change');
this.hideInstallPrompts();
@@ -165,7 +148,6 @@ class PWAInstallPrompt {
}, 1000);
});
// Проверяем при фокусе окна
window.addEventListener('focus', () => {
setTimeout(() => {
const wasInstalled = this.isInstalled;
@@ -181,7 +163,6 @@ class PWAInstallPrompt {
}
createInstallButton() {
// Если уже установлено, не создаем кнопку
if (this.isInstalled) {
return;
}
@@ -202,14 +183,12 @@ class PWAInstallPrompt {
</button>
`;
// Обработчик для установки
this.installButton.addEventListener('click', (e) => {
if (!e.target.classList.contains('close-btn')) {
this.handleInstallClick();
}
});
// Обработчик для закрытия
const closeBtn = this.installButton.querySelector('.close-btn');
closeBtn.addEventListener('click', (e) => {
e.stopPropagation();
@@ -220,7 +199,6 @@ class PWAInstallPrompt {
}
createInstallBanner() {
// Если уже установлено, не создаем баннер
if (this.isInstalled || this.installBanner) {
return;
}
@@ -268,7 +246,6 @@ class PWAInstallPrompt {
}
showInstallOptions() {
// Всегда проверяем статус установки перед показом
if (this.checkInstallationStatus()) {
console.log('💿 App is installed, not showing install options');
return;
@@ -284,7 +261,6 @@ class PWAInstallPrompt {
}
showInstallButton() {
// Проверяем статус установки
if (this.checkInstallationStatus()) {
console.log('💿 App is installed, not showing install button');
return;
@@ -308,7 +284,6 @@ class PWAInstallPrompt {
}
showInstallBanner() {
// Проверяем статус установки
if (this.checkInstallationStatus()) {
console.log('💿 App is installed, not showing install banner');
return;
@@ -335,7 +310,6 @@ class PWAInstallPrompt {
if (this.installButton) {
this.installButton.classList.add('hidden');
// Полностью удаляем кнопку если приложение установлено
if (this.isInstalled) {
this.installButton.remove();
this.installButton = null;
@@ -346,7 +320,6 @@ class PWAInstallPrompt {
if (this.installBanner) {
this.installBanner.classList.remove('show');
this.installBanner.style.transform = 'translateY(100%)';
// Полностью удаляем баннер если приложение установлено
if (this.isInstalled) {
setTimeout(() => {
if (this.installBanner) {
@@ -379,7 +352,7 @@ class PWAInstallPrompt {
if (result.outcome === 'accepted') {
console.log('✅ User accepted install prompt');
this.isInstalled = true; // Устанавливаем флаг сразу
this.isInstalled = true;
this.hideInstallPrompts();
this.saveInstallPreference('accepted', true);
this.saveInstallPreference('installed', true);
@@ -550,12 +523,10 @@ class PWAInstallPrompt {
setTimeout(() => notification.remove(), 300);
}, 5000);
// Скрываем все промпты установки
this.hideInstallPrompts();
}
shouldShowPrompt() {
// Всегда проверяем актуальный статус установки
if (this.checkInstallationStatus()) {
console.log('💿 App is installed, not showing prompt');
return false;
@@ -563,7 +534,6 @@ class PWAInstallPrompt {
const preferences = this.loadInstallPreferences();
// Проверяем, не было ли приложение уже установлено
if (preferences.installed) {
console.log('💿 Installation preference found, marking as installed');
this.isInstalled = true;
@@ -691,7 +661,6 @@ class PWAInstallPrompt {
// Public API methods
showInstallPrompt() {
// Проверяем статус перед показом
if (this.checkInstallationStatus()) {
console.log('💿 App already installed, not showing prompt');
return;
@@ -711,7 +680,6 @@ class PWAInstallPrompt {
}
getInstallStatus() {
// Проверяем актуальный статус
this.checkInstallationStatus();
return {
@@ -735,7 +703,6 @@ class PWAInstallPrompt {
console.log('📡 Service Worker registration set for PWA Install Prompt');
}
// Метод для принудительной проверки статуса установки
forceInstallationCheck() {
console.log('🔄 Force checking installation status...');
this.installationChecked = false;
@@ -766,10 +733,8 @@ if (typeof window !== 'undefined') {
}
});
// Дополнительная проверка при полной загрузке страницы
window.addEventListener('load', () => {
if (window.pwaInstallPrompt) {
// Проверяем статус установки через небольшую задержку
setTimeout(() => {
window.pwaInstallPrompt.forceInstallationCheck();
}, 1000);