471 lines
15 KiB
JavaScript
471 lines
15 KiB
JavaScript
/**
|
||
* 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(); |