Files
swiper/js/swipe-integration.js
Aodhan Collins 5e893a0c9d Bug fixes
2025-07-31 01:38:07 +01:00

471 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Swipe Integration Manager
* Allows seamless switching between original and enhanced swipe systems
*/
import { showToast, updateImageInfo } from './utils.js';
import EnhancedSwipeCard from '../components/enhanced-swipe-card.js';
export class SwipeIntegrationManager {
constructor() {
this.currentMode = this.detectOptimalMode();
this.swipeCard = null;
this.isInitialized = false;
// Configuration options
this.config = {
enablePhysics: true,
enableVisualEffects: true,
enableHapticFeedback: true,
animationQuality: 'auto', // 'low', 'medium', 'high', 'auto'
performanceMode: 'auto', // 'low', 'normal', 'high', 'auto'
debugMode: false
};
// Load user preferences
this.loadUserPreferences();
console.log(`SwipeIntegrationManager initialized in ${this.currentMode} mode`);
}
/**
* Detect optimal swipe mode based on device capabilities
*/
detectOptimalMode() {
const userAgent = navigator.userAgent.toLowerCase();
const isMobile = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/.test(userAgent);
const isLowEnd = /android.*chrome\/[1-6][0-9]/.test(userAgent);
const hasReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
// Check device memory if available
const deviceMemory = navigator.deviceMemory || 4;
const hasLowMemory = deviceMemory < 2;
// Check connection speed if available
let hasSlowConnection = false;
if ('connection' in navigator) {
const connection = navigator.connection;
hasSlowConnection = connection.effectiveType === 'slow-2g' || connection.effectiveType === '2g';
}
// Determine optimal mode
if (hasReducedMotion || isLowEnd || hasLowMemory || hasSlowConnection) {
return 'original';
} else if (isMobile) {
return 'enhanced-lite';
} else {
return 'enhanced';
}
}
/**
* Initialize the swipe system
*/
async initialize(container, onSwipe, options = {}) {
if (this.isInitialized) {
console.warn('SwipeIntegrationManager already initialized');
return;
}
// Merge options with config
this.config = { ...this.config, ...options };
try {
switch (this.currentMode) {
case 'enhanced':
await this.initializeEnhancedMode(container, onSwipe);
break;
case 'enhanced-lite':
await this.initializeEnhancedLiteMode(container, onSwipe);
break;
case 'original':
default:
await this.initializeOriginalMode(container, onSwipe);
break;
}
this.isInitialized = true;
this.logInitialization();
} catch (error) {
console.error('Failed to initialize swipe system:', error);
// Clean up any partially initialized swipe card
if (this.swipeCard && typeof this.swipeCard.destroy === 'function') {
this.swipeCard.destroy();
this.swipeCard = null;
}
// Fallback to original mode
await this.initializeOriginalMode(container, onSwipe);
this.currentMode = 'original';
this.isInitialized = true;
}
}
/**
* Initialize enhanced mode with full physics
*/
async initializeEnhancedMode(container, onSwipe) {
this.swipeCard = new EnhancedSwipeCard({
container,
onSwipe,
threshold: 100,
velocityThreshold: 2.5,
springTension: 320,
springFriction: 25,
mass: 1.0,
momentumDecay: 0.90
});
// Add enhanced CSS classes
document.body.classList.add('enhanced-swipe-mode');
container.classList.add('enhanced-container');
// Load enhanced styles if not already loaded
await this.loadEnhancedStyles();
}
/**
* Initialize enhanced lite mode for mobile devices
*/
async initializeEnhancedLiteMode(container, onSwipe) {
this.swipeCard = new EnhancedSwipeCard({
container,
onSwipe,
threshold: 80,
velocityThreshold: 2.0,
springTension: 280,
springFriction: 30,
mass: 1.2,
momentumDecay: 0.92
});
// Add lite mode classes
document.body.classList.add('enhanced-swipe-lite-mode');
container.classList.add('enhanced-container-lite');
// Disable some heavy effects for performance
this.config.enableVisualEffects = false;
await this.loadEnhancedStyles();
}
/**
* Initialize original mode as fallback
*/
async initializeOriginalMode(container, onSwipe) {
// Import and initialize fallback swipe card
const { default: FallbackSwipeCard } = await import('../components/fallback-swipe-card.js');
this.swipeCard = new FallbackSwipeCard({
container,
onSwipe,
threshold: 100
});
document.body.classList.add('original-swipe-mode');
}
/**
* Load enhanced styles dynamically
*/
async loadEnhancedStyles() {
return new Promise((resolve, reject) => {
// Check if enhanced styles are already loaded
if (document.querySelector('link[href*="enhanced-animations"]')) {
resolve();
return;
}
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'scss/enhanced-animations.css'; // Compiled CSS
link.onload = resolve;
link.onerror = reject;
document.head.appendChild(link);
});
}
/**
* Switch between swipe modes dynamically
*/
async switchMode(newMode) {
if (newMode === this.currentMode) {
console.log(`Already in ${newMode} mode`);
return;
}
console.log(`Switching from ${this.currentMode} to ${newMode} mode`);
// Clean up current mode
if (this.swipeCard && typeof this.swipeCard.destroy === 'function') {
this.swipeCard.destroy();
}
// Remove current mode classes
document.body.classList.remove(
'enhanced-swipe-mode',
'enhanced-swipe-lite-mode',
'original-swipe-mode'
);
// Update mode and reinitialize
this.currentMode = newMode;
this.isInitialized = false;
// Save user preference
this.saveUserPreference('swipeMode', newMode);
// Show feedback to user
showToast(`Switched to ${newMode} swipe mode`, 'info');
}
/**
* Get current swipe card instance
*/
getSwipeCard() {
return this.swipeCard;
}
/**
* Get current mode
*/
getCurrentMode() {
return this.currentMode;
}
/**
* Get available modes
*/
getAvailableModes() {
return ['original', 'enhanced-lite', 'enhanced'];
}
/**
* Update configuration
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
// Apply config changes to current swipe card if applicable
if (this.swipeCard && typeof this.swipeCard.updateConfig === 'function') {
this.swipeCard.updateConfig(this.config);
}
// Save configuration
this.saveUserPreference('swipeConfig', this.config);
}
/**
* Get current configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Load user preferences from localStorage
*/
loadUserPreferences() {
try {
const savedMode = localStorage.getItem('swipeMode');
if (savedMode && this.getAvailableModes().includes(savedMode)) {
this.currentMode = savedMode;
}
const savedConfig = localStorage.getItem('swipeConfig');
if (savedConfig) {
this.config = { ...this.config, ...JSON.parse(savedConfig) };
}
} catch (error) {
console.warn('Failed to load user preferences:', error);
}
}
/**
* Save user preference to localStorage
*/
saveUserPreference(key, value) {
try {
if (typeof value === 'object') {
localStorage.setItem(key, JSON.stringify(value));
} else {
localStorage.setItem(key, value);
}
} catch (error) {
console.warn('Failed to save user preference:', error);
}
}
/**
* Performance monitoring
*/
getPerformanceMetrics() {
if (this.swipeCard && typeof this.swipeCard.getPerformanceMetrics === 'function') {
return this.swipeCard.getPerformanceMetrics();
}
return null;
}
/**
* Debug information
*/
getDebugInfo() {
return {
currentMode: this.currentMode,
config: this.config,
isInitialized: this.isInitialized,
deviceInfo: {
userAgent: navigator.userAgent,
deviceMemory: navigator.deviceMemory,
hardwareConcurrency: navigator.hardwareConcurrency,
connection: navigator.connection ? {
effectiveType: navigator.connection.effectiveType,
downlink: navigator.connection.downlink
} : null
},
performanceMetrics: this.getPerformanceMetrics()
};
}
/**
* Log initialization details
*/
logInitialization() {
if (this.config.debugMode) {
console.group('SwipeIntegrationManager Initialization');
console.log('Mode:', this.currentMode);
console.log('Config:', this.config);
console.log('Debug Info:', this.getDebugInfo());
console.groupEnd();
}
}
/**
* Destroy the swipe system
*/
destroy() {
if (this.swipeCard && typeof this.swipeCard.destroy === 'function') {
this.swipeCard.destroy();
}
// Remove mode classes
document.body.classList.remove(
'enhanced-swipe-mode',
'enhanced-swipe-lite-mode',
'original-swipe-mode'
);
this.swipeCard = null;
this.isInitialized = false;
console.log('SwipeIntegrationManager destroyed');
}
}
/**
* Create settings panel for swipe mode selection
*/
export function createSwipeSettingsPanel(integrationManager) {
const panel = document.createElement('div');
panel.className = 'swipe-settings-panel';
panel.innerHTML = `
<div class="settings-header">
<h3>Swipe Settings</h3>
<button class="close-settings">×</button>
</div>
<div class="settings-content">
<div class="setting-group">
<label>Swipe Mode:</label>
<select id="swipe-mode-select">
<option value="original">Original (Compatible)</option>
<option value="enhanced-lite">Enhanced Lite (Mobile)</option>
<option value="enhanced">Enhanced (Full Physics)</option>
</select>
</div>
<div class="setting-group">
<label>
<input type="checkbox" id="enable-physics"> Enable Physics
</label>
</div>
<div class="setting-group">
<label>
<input type="checkbox" id="enable-visual-effects"> Visual Effects
</label>
</div>
<div class="setting-group">
<label>
<input type="checkbox" id="enable-haptic"> Haptic Feedback
</label>
</div>
<div class="setting-group">
<label>Animation Quality:</label>
<select id="animation-quality">
<option value="auto">Auto</option>
<option value="low">Low</option>
<option value="medium">Medium</option>
<option value="high">High</option>
</select>
</div>
<div class="settings-actions">
<button id="apply-settings" class="apply-btn">Apply</button>
<button id="reset-settings" class="reset-btn">Reset</button>
</div>
</div>
`;
// Set current values
const config = integrationManager.getConfig();
panel.querySelector('#swipe-mode-select').value = integrationManager.getCurrentMode();
panel.querySelector('#enable-physics').checked = config.enablePhysics;
panel.querySelector('#enable-visual-effects').checked = config.enableVisualEffects;
panel.querySelector('#enable-haptic').checked = config.enableHapticFeedback;
panel.querySelector('#animation-quality').value = config.animationQuality;
// Event listeners
panel.querySelector('.close-settings').addEventListener('click', () => {
panel.remove();
});
panel.querySelector('#apply-settings').addEventListener('click', () => {
const newMode = panel.querySelector('#swipe-mode-select').value;
const newConfig = {
enablePhysics: panel.querySelector('#enable-physics').checked,
enableVisualEffects: panel.querySelector('#enable-visual-effects').checked,
enableHapticFeedback: panel.querySelector('#enable-haptic').checked,
animationQuality: panel.querySelector('#animation-quality').value
};
integrationManager.updateConfig(newConfig);
if (newMode !== integrationManager.getCurrentMode()) {
integrationManager.switchMode(newMode);
}
showToast('Settings applied successfully', 'success');
});
panel.querySelector('#reset-settings').addEventListener('click', () => {
integrationManager.updateConfig({
enablePhysics: true,
enableVisualEffects: true,
enableHapticFeedback: true,
animationQuality: 'auto',
performanceMode: 'auto'
});
// Reset form values
panel.querySelector('#enable-physics').checked = true;
panel.querySelector('#enable-visual-effects').checked = true;
panel.querySelector('#enable-haptic').checked = true;
panel.querySelector('#animation-quality').value = 'auto';
showToast('Settings reset to defaults', 'info');
});
return panel;
}
// Export singleton instance
export const swipeIntegration = new SwipeIntegrationManager();