Exemples de Fonctionnalités Mobile Web Python

Exemples de fonctionnalités mobile Web Python incluant les informations sur l'appareil, le statut du réseau et la vibration

Key Facts

Category
Python
Items
3
Format Families
sample

Sample Overview

Exemples de fonctionnalités mobile Web Python incluant les informations sur l'appareil, le statut du réseau et la vibration This sample set belongs to Python and can be used to test related workflows inside Elysia Tools.

💻 Informations sur l'Appareil python

🟢 simple ⭐⭐⭐

Obtenir les informations sur l'appareil y compris le type, le système d'exploitation, le navigateur, l'écran et les capacités matérielles

⏱️ 20 min 🏷️ python, web, mobile features
Prerequisites: Basic Python, Pyodide, JavaScript interop
# Web Python Device Information Examples
# Using JavaScript interop for device detection in browser environment (Pyodide)

import js
from typing import Dict, Any, Optional

# 1. Device Info Manager
class DeviceInfoManager:
    def get_device_info(self) -> Dict[str, Any]:
        """
        Get basic device information from Navigator API

        Returns:
            dict: Device information
        """
        navigator = js.navigator

        return {
            'user_agent': str(navigator.userAgent),
            'platform': str(navigator.platform),
            'vendor': str(navigator.vendor),
            'language': str(navigator.language),
            'cookies_enabled': bool(navigator.cookieEnabled),
            'on_line': bool(navigator.onLine),
            'hardware_concurrency': getattr(navigator, 'hardwareConcurrency', 0),
            'device_memory': getattr(navigator, 'deviceMemory', 0),
            'max_touch_points': getattr(navigator, 'maxTouchPoints', 0)
        }

    def get_device_type(self) -> str:
        """
        Determine device type (desktop, mobile, tablet)

        Returns:
            str: Device type
        """
        user_agent = js.navigator.userAgent.lower()
        max_touch_points = getattr(js.navigator, 'maxTouchPoints', 0)

        # Check for mobile
        is_mobile = any(keyword in user_agent for keyword in
                       ['android', 'iphone', 'ipod', 'blackberry', 'iemobile', 'opera mini'])

        # Check for tablet
        is_tablet = (any(keyword in user_agent for keyword in ['ipad', 'tablet']) or
                     ('android' in user_agent and 'mobile' not in user_agent) or
                     (max_touch_points > 0 and 'macintosh' in user_agent))

        if is_tablet:
            return 'tablet'
        elif is_mobile:
            return 'mobile'
        else:
            return 'desktop'

    def get_os_info(self) -> Dict[str, str]:
        """
        Get operating system information

        Returns:
            dict: OS name and version
        """
        user_agent = str(js.navigator.userAgent)
        name = 'Unknown'
        version = 'Unknown'

        if 'windows' in user_agent.lower():
            name = 'Windows'
            import re
            match = re.search(r'Windows NT (\d+\.\d+)', user_agent)
            if match:
                version = match.group(1)
        elif 'macintosh' in user_agent.lower() or 'mac os x' in user_agent.lower():
            name = 'macOS'
            import re
            match = re.search(r'Mac OS X (\d+[._]\d+)', user_agent)
            if match:
                version = match.group(1).replace('_', '.')
        elif 'android' in user_agent.lower():
            name = 'Android'
            import re
            match = re.search(r'Android (\d+\.\d+)', user_agent)
            if match:
                version = match.group(1)
        elif any(keyword in user_agent for keyword in ['iphone', 'ipad', 'ipod']):
            name = 'iOS'
            import re
            match = re.search(r'OS (\d+_\d+)', user_agent)
            if match:
                version = match.group(1).replace('_', '.')
        elif 'linux' in user_agent.lower():
            name = 'Linux'

        return {'name': name, 'version': version}

    def get_browser_info(self) -> Dict[str, str]:
        """
        Get browser information

        Returns:
            dict: Browser name and version
        """
        user_agent = str(js.navigator.userAgent)
        name = 'Unknown'
        version = 'Unknown'

        if 'chrome' in user_agent.lower() and 'edge' not in user_agent.lower() and 'opr' not in user_agent.lower():
            name = 'Chrome'
            import re
            match = re.search(r'Chrome\/(\d+\.\d+\.\d+\.\d+)', user_agent)
            if match:
                version = match.group(1)
        elif 'safari' in user_agent.lower() and 'chrome' not in user_agent.lower():
            name = 'Safari'
            import re
            match = re.search(r'Version\/(\d+\.\d+)', user_agent)
            if match:
                version = match.group(1)
        elif 'firefox' in user_agent.lower():
            name = 'Firefox'
            import re
            match = re.search(r'Firefox\/(\d+\.\d+)', user_agent)
            if match:
                version = match.group(1)
        elif 'edge' in user_agent.lower():
            name = 'Edge'
            import re
            match = re.search(r'Edge\/(\d+\.\d+)', user_agent)
            if match:
                version = match.group(1)
        elif 'opr' in user_agent.lower():
            name = 'Opera'
            import re
            match = re.search(r'OPR\/(\d+\.\d+)', user_agent)
            if match:
                version = match.group(1)

        return {'name': name, 'version': version}

    def get_screen_info(self) -> Dict[str, Any]:
        """
        Get screen information

        Returns:
            dict: Screen dimensions and properties
        """
        screen = js.screen
        window = js.window

        orientation = getattr(screen.orientation, 'type', 'unknown') if hasattr(screen, 'orientation') else 'unknown'

        return {
            'width': screen.width,
            'height': screen.height,
            'avail_width': screen.availWidth,
            'avail_height': screen.availHeight,
            'color_depth': screen.colorDepth,
            'pixel_depth': screen.pixelDepth,
            'orientation': str(orientation),
            'device_pixel_ratio': window.devicePixelRatio
        }

    def get_viewport_info(self) -> Dict[str, int]:
        """
        Get viewport information

        Returns:
            dict: Viewport dimensions and scroll position
        """
        window = js.window

        return {
            'width': window.innerWidth,
            'height': window.innerHeight,
            'scroll_x': window.scrollX,
            'scroll_y': window.scrollY
        }

    def is_touch_device(self) -> bool:
        """
        Check if device supports touch

        Returns:
            bool: True if touch is supported
        """
        return 'ontouchstart' in dir(js.window) or getattr(js.navigator, 'maxTouchPoints', 0) > 0

    def is_retina_display(self) -> bool:
        """
        Check if device has retina display

        Returns:
            bool: True if retina display
        """
        return js.window.devicePixelRatio > 1

    def check_webgl(self) -> bool:
        """
        Check if WebGL is supported

        Returns:
            bool: True if WebGL is supported
        """
        try:
            canvas = js.document.createElement('canvas')
            return bool(canvas.getContext('webgl') or canvas.getContext('experimental-webgl'))
        except:
            return False

    def get_complete_report(self) -> Dict[str, Any]:
        """
        Get complete device report

        Returns:
            dict: Complete device information
        """
        return {
            'device': {
                'type': self.get_device_type(),
                'info': self.get_device_info()
            },
            'os': self.get_os_info(),
            'browser': self.get_browser_info(),
            'screen': self.get_screen_info(),
            'viewport': self.get_viewport_info(),
            'capabilities': {
                'touch': self.is_touch_device(),
                'retina': self.is_retina_display(),
                'webgl': self.check_webgl(),
                'local_storage': self.check_local_storage(),
                'session_storage': self.check_session_storage()
            }
        }

    def check_local_storage(self) -> bool:
        """Check if localStorage is available"""
        try:
            js.window.localStorage.setItem('test', 'test')
            js.window.localStorage.removeItem('test')
            return True
        except:
            return False

    def check_session_storage(self) -> bool:
        """Check if sessionStorage is available"""
        try:
            js.window.sessionStorage.setItem('test', 'test')
            js.window.sessionStorage.removeItem('test')
            return True
        except:
            return False


# 2. Battery Manager
class BatteryManager:
    def __init__(self):
        self.battery = None

    async def initialize(self):
        """Initialize battery API"""
        if hasattr(js.navigator, 'getBattery'):
            self.battery = await js.navigator.getBattery()

    def is_supported(self) -> bool:
        """Check if battery API is supported"""
        return hasattr(js.navigator, 'getBattery')

    def get_battery_info(self) -> Optional[Dict[str, Any]]:
        """
        Get battery information

        Returns:
            dict or None: Battery information if available
        """
        if not self.battery:
            return None

        return {
            'charging': bool(self.battery.charging),
            'level': float(self.battery.level),
            'charging_time': float(self.battery.chargingTime),
            'discharging_time': float(self.battery.dischargingTime)
        }


# 3. Connection Manager
class ConnectionManager:
    def get_connection_info(self) -> Optional[Dict[str, Any]]:
        """
        Get connection information

        Returns:
            dict or None: Connection information if available
        """
        connection = getattr(js.navigator, 'connection', None) or                      getattr(js.navigator, 'mozConnection', None) or                      getattr(js.navigator, 'webkitConnection', None)

        if not connection:
            return None

        return {
            'effective_type': str(getattr(connection, 'effectiveType', 'unknown')),
            'downlink': float(getattr(connection, 'downlink', 0)),
            'rtt': int(getattr(connection, 'rtt', 0)),
            'save_data': bool(getattr(connection, 'saveData', False))
        }

    def is_slow_connection(self) -> bool:
        """Check if connection is slow"""
        info = self.get_connection_info()
        if not info:
            return False
        return info['effective_type'] in ['slow-2g', '2g']

    def is_fast_connection(self) -> bool:
        """Check if connection is fast"""
        info = self.get_connection_info()
        if not info:
            return False
        return info['effective_type'] == '4g'


# 4. Orientation Manager
class OrientationManager:
    def get_orientation(self) -> str:
        """
        Get current orientation

        Returns:
            str: 'portrait' or 'landscape'
        """
        window = js.window
        return 'portrait' if window.innerHeight > window.innerWidth else 'landscape'


# 5. Device Capability Detector
class DeviceCapabilityDetector:
    async def has_camera(self) -> bool:
        """Check if camera is available"""
        try:
            devices = await js.navigator.mediaDevices.enumerateDevices()
            return any(d.kind == 'videoinput' for d in devices)
        except:
            return False

    async def has_microphone(self) -> bool:
        """Check if microphone is available"""
        try:
            devices = await js.navigator.mediaDevices.enumerateDevices()
            return any(d.kind == 'audioinput' for d in devices)
        except:
            return False

    def has_geolocation(self) -> bool:
        """Check if geolocation is available"""
        return 'geolocation' in dir(js.navigator)

    def has_vibration(self) -> bool:
        """Check if vibration is supported"""
        return 'vibrate' in dir(js.navigator)

    def has_bluetooth(self) -> bool:
        """Check if bluetooth is available"""
        return 'bluetooth' in dir(js.navigator)

    def has_usb(self) -> bool:
        """Check if USB is available"""
        return 'usb' in dir(js.navigator)


# Usage Examples
async def demonstrate_device_info():
    print("=== Web Python Device Information Examples ===\n")

    device_manager = DeviceInfoManager()
    battery_manager = BatteryManager()
    connection_manager = ConnectionManager()
    orientation_manager = OrientationManager()
    capability_detector = DeviceCapabilityDetector()

    # 1. Basic device info
    print("--- 1. Device Info ---")
    device_info = device_manager.get_device_info()
    print(f"User Agent: {device_info['user_agent']}")
    print(f"Platform: {device_info['platform']}")
    print(f"Device Type: {device_manager.get_device_type()}")

    # 2. OS and browser
    print("\n--- 2. OS & Browser ---")
    os_info = device_manager.get_os_info()
    print(f"OS: {os_info['name']} {os_info['version']}")

    browser_info = device_manager.get_browser_info()
    print(f"Browser: {browser_info['name']} {browser_info['version']}")

    # 3. Screen info
    print("\n--- 3. Screen Info ---")
    screen_info = device_manager.get_screen_info()
    print(f"Screen: {screen_info['width']}x{screen_info['height']}")
    print(f"Available: {screen_info['avail_width']}x{screen_info['avail_height']}")
    print(f"Device Pixel Ratio: {screen_info['device_pixel_ratio']}")

    # 4. Capabilities
    print("\n--- 4. Capabilities ---")
    print(f"Touch Device: {device_manager.is_touch_device()}")
    print(f"Retina Display: {device_manager.is_retina_display()}")

    # 5. Battery
    print("\n--- 5. Battery ---")
    await battery_manager.initialize()
    battery_info = battery_manager.get_battery_info()
    if battery_info:
        print(f"Battery Level: {int(battery_info['level'] * 100)}%")
        print(f"Charging: {battery_info['charging']}")
    else:
        print("Battery API not supported")

    # 6. Connection
    print("\n--- 6. Connection ---")
    conn_info = connection_manager.get_connection_info()
    if conn_info:
        print(f"Connection Type: {conn_info['effective_type']}")
        print(f"Downlink: {conn_info['downlink']} Mbps")
        print(f"RTT: {conn_info['rtt']} ms")

    # 7. Capabilities detection
    print("\n--- 7. Device Capabilities ---")
    print(f"Camera: {await capability_detector.has_camera()}")
    print(f"Microphone: {await capability_detector.has_microphone()}")
    print(f"Geolocation: {capability_detector.has_geolocation()}")
    print(f"Vibration: {capability_detector.has_vibration()}")
    print(f"Bluetooth: {capability_detector.has_bluetooth()}")

    # 8. Complete report
    print("\n--- 8. Complete Report ---")
    report = device_manager.get_complete_report()
    print(str(report))

    print("\n=== All Device Information Examples Completed ===")

# Export functions
export = {
    'DeviceInfoManager': DeviceInfoManager,
    'BatteryManager': BatteryManager,
    'ConnectionManager': ConnectionManager,
    'OrientationManager': OrientationManager,
    'DeviceCapabilityDetector': DeviceCapabilityDetector,
    'demonstrate_device_info': demonstrate_device_info
}

💻 Statut du Réseau python

🟢 simple ⭐⭐⭐

Surveiller l'état de la connectivité réseau avec des événements en ligne/hors ligne et la qualité de connexion

⏱️ 20 min 🏷️ python, web, mobile features
Prerequisites: Basic Python, Pyodide, Network API
# Web Python Network Status Examples
# Monitoring network connectivity and connection quality

import js
from typing import Dict, Any, Callable, Optional

# 1. Network Status Monitor
class NetworkStatusMonitor:
    def __init__(self):
        self.is_online = bool(js.navigator.onLine)
        self.listeners = []

    def _handle_online(self):
        """Handle online event"""
        self.is_online = True
        self._notify_listeners(True)
        print("Network status: Online")

    def _handle_offline(self):
        """Handle offline event"""
        self.is_online = False
        self._notify_listeners(False)
        print("Network status: Offline")

    def _notify_listeners(self, online: bool):
        """Notify all listeners"""
        for listener in self.listeners:
            try:
                listener(online)
            except Exception as error:
                print(f"Error in network status listener: {error}")

    def is_currently_online(self) -> bool:
        """
        Get current online status

        Returns:
            bool: True if online
        """
        return self.is_online

    def add_listener(self, listener: Callable[[bool], None]):
        """
        Add status change listener

        Args:
            listener: Callback function
        """
        self.listeners.append(listener)

    def remove_listener(self, listener: Callable[[bool], None]):
        """
        Remove status change listener

        Args:
            listener: Callback function to remove
        """
        if listener in self.listeners:
            self.listeners.remove(listener)

    def initialize(self):
        """Initialize event listeners"""
        # Note: In Pyodide, you'd need to set up JavaScript event handlers
        # This is a simplified version
        pass


# 2. Connection Quality Monitor
class ConnectionQualityMonitor:
    def __init__(self):
        self.connection = getattr(js.navigator, 'connection', None) or                           getattr(js.navigator, 'mozConnection', None) or                           getattr(js.navigator, 'webkitConnection', None)
        self.listeners = []

    def get_connection_info(self) -> Optional[Dict[str, Any]]:
        """
        Get connection information

        Returns:
            dict or None: Connection info
        """
        if not self.connection:
            return None

        return {
            'effective_type': str(getattr(self.connection, 'effectiveType', 'unknown')),
            'downlink': float(getattr(self.connection, 'downlink', 0)),
            'rtt': int(getattr(self.connection, 'rtt', 0)),
            'save_data': bool(getattr(self.connection, 'saveData', False))
        }

    def is_slow_connection(self) -> bool:
        """
        Check if connection is slow

        Returns:
            bool: True if slow connection
        """
        info = self.get_connection_info()
        if not info:
            return False
        return info['effective_type'] in ['slow-2g', '2g', '3g']

    def is_fast_connection(self) -> bool:
        """
        Check if connection is fast

        Returns:
            bool: True if fast connection
        """
        info = self.get_connection_info()
        if not info:
            return False
        return info['effective_type'] == '4g'

    def get_quality_description(self) -> str:
        """
        Get connection quality description

        Returns:
            str: Quality description
        """
        info = self.get_connection_info()
        if not info:
            return 'Unknown'

        descriptions = {
            'slow-2g': 'Very Slow (2G)',
            '2g': 'Slow (2G)',
            '3g': 'Moderate (3G)',
            '4g': 'Fast (4G)'
        }

        return descriptions.get(info['effective_type'], 'Unknown')


# 3. Network Speed Tester
class NetworkSpeedTester:
    def __init__(self, test_url: str = 'https://www.google.com/favicon.ico'):
        self.test_url = test_url

    async def test_download_speed(self) -> Dict[str, float]:
        """
        Test download speed

        Returns:
            dict: Speed and latency in kbps and ms
        """
        import time
        start_time = time.time()

        try:
            response = await js.fetch(f"{self.test_url}?t={int(time.time() * 1000)}")
            blob = await response.blob()
            download_size = blob.size

            end_time = time.time()
            duration = end_time - start_time
            speed_kbps = ((download_size * 8) / duration) / 1000
            latency = (end_time - start_time) * 1000

            return {
                'speed_kbps': speed_kbps,
                'latency': latency
            }
        except Exception as error:
            print(f"Speed test failed: {error}")
            return {'speed_kbps': 0, 'latency': 0}

    async def test_latency(self) -> float:
        """
        Test latency (ping)

        Returns:
            float: Latency in ms
        """
        import time
        start = time.time()

        try:
            await js.fetch(f"{self.test_url}?t={int(time.time() * 1000)}", method='HEAD')
            return (time.time() - start) * 1000
        except:
            return -1

    async def test_average(self, iterations: int = 3) -> Dict[str, float]:
        """
        Test multiple times and get average

        Args:
            iterations: Number of test iterations

        Returns:
            dict: Average speed and latency
        """
        import time
        speeds = []
        latencies = []

        for i in range(iterations):
            result = await self.test_download_speed()
            speeds.append(result['speed_kbps'])
            latencies.append(result['latency'])

            # Wait between tests
            await asyncio(0.5)

        avg_speed_kbps = sum(speeds) / len(speeds)
        avg_latency = sum(latencies) / len(latencies)

        return {
            'avg_speed_kbps': avg_speed_kbps,
            'avg_latency': avg_latency
        }


# 4. Offline Manager
class OfflineManager:
    def __init__(self):
        self.network_monitor = NetworkStatusMonitor()
        self.offline_queue = []
        self.is_offline_mode = False

    def queue_request(self, url: str, options: Dict = None):
        """
        Add request to offline queue

        Args:
            url: Request URL
            options: Request options
        """
        self.offline_queue.append({'url': url, 'options': options or {}})
        print(f"Request queued: {url}")

    async def sync_offline_requests(self):
        """Sync offline requests when back online"""
        if not self.offline_queue:
            return

        print(f"Syncing {len(self.offline_queue)} offline requests...")

        queue = self.offline_queue.copy()
        self.offline_queue = []

        for request in queue:
            try:
                await js.fetch(request['url'], **request['options'])
                print(f"Synced: {request['url']}")
            except Exception as error:
                print(f"Failed to sync {request['url']}: {error}")
                # Re-queue failed requests
                self.queue_request(request['url'], request['options'])

    def is_offline(self) -> bool:
        """Check if currently in offline mode"""
        return self.is_offline_mode

    def get_queue_size(self) -> int:
        """Get offline queue size"""
        return len(self.offline_queue)

    def clear_queue(self):
        """Clear offline queue"""
        self.offline_queue = []


# 5. Network Health Checker
class NetworkHealthChecker:
    def __init__(self):
        self.connection_monitor = ConnectionQualityMonitor()
        self.speed_tester = NetworkSpeedTester()

    async def get_health_report(self) -> Dict[str, Any]:
        """
        Get comprehensive health report

        Returns:
            dict: Health report
        """
        online = bool(js.navigator.onLine)
        connection_info = self.connection_monitor.get_connection_info()
        speed_test = None
        health = 'poor'

        if online:
            speed_test = await self.speed_tester.test_download_speed()

            # Determine health based on speed and latency
            if speed_test['speed_kbps'] > 5000 and speed_test['latency'] < 50:
                health = 'excellent'
            elif speed_test['speed_kbps'] > 1000 and speed_test['latency'] < 100:
                health = 'good'
            elif speed_test['speed_kbps'] > 500 and speed_test['latency'] < 200:
                health = 'fair'
            else:
                health = 'poor'

        return {
            'online': online,
            'connection_info': connection_info,
            'speed_test': speed_test,
            'health': health
        }

    def quick_health_check(self) -> Dict[str, Any]:
        """
        Simple health check (quick)

        Returns:
            dict: Quick health status
        """
        online = bool(js.navigator.onLine)
        conn_info = self.connection_monitor.get_connection_info()

        estimated_quality = 'poor'
        if conn_info:
            if conn_info['effective_type'] == '4g' and conn_info['downlink'] >= 10:
                estimated_quality = 'good'
            elif conn_info['effective_type'] in ['3g', '4g']:
                estimated_quality = 'fair'

        return {
            'online': online,
            'connection_type': conn_info['effective_type'] if conn_info else 'unknown',
            'estimated_quality': estimated_quality
        }


# Helper function for asyncio
async def asyncio(delay: float):
    """Simple delay helper"""
    import asyncio
    await asyncio.sleep(delay)


# Usage Examples
async def demonstrate_network_status():
    print("=== Web Python Network Status Examples ===\n")

    network_monitor = NetworkStatusMonitor()
    connection_monitor = ConnectionQualityMonitor()
    speed_tester = NetworkSpeedTester()
    offline_manager = OfflineManager()
    health_checker = NetworkHealthChecker()

    # 1. Network status
    print("--- 1. Network Status ---")
    print(f"Currently Online: {network_monitor.is_currently_online()}")

    # 2. Connection quality
    print("\n--- 2. Connection Quality ---")
    conn_info = connection_monitor.get_connection_info()
    if conn_info:
        print(f"Effective Type: {conn_info['effective_type']}")
        print(f"Downlink: {conn_info['downlink']} Mbps")
        print(f"RTT: {conn_info['rtt']} ms")
        print(f"Quality Description: {connection_monitor.get_quality_description()}")
        print(f"Slow Connection: {connection_monitor.is_slow_connection()}")
        print(f"Fast Connection: {connection_monitor.is_fast_connection()}")

    # 3. Speed test
    print("\n--- 3. Speed Test ---")
    speed_result = await speed_tester.test_download_speed()
    print(f"Speed: {speed_result['speed_kbps']:.2f} kbps")
    print(f"Latency: {speed_result['latency']:.2f} ms")

    # 4. Average speed test
    print("\n--- 4. Average Speed Test ---")
    avg_result = await speed_tester.test_average(2)
    print(f"Average Speed: {avg_result['avg_speed_kbps']:.2f} kbps")
    print(f"Average Latency: {avg_result['avg_latency']:.2f} ms")

    # 5. Health check
    print("\n--- 5. Health Check ---")
    health_report = await health_checker.get_health_report()
    print(f"Health: {health_report['health']}")
    print(f"Online: {health_report['online']}")

    # 6. Quick health check
    print("\n--- 6. Quick Health Check ---")
    quick_health = health_checker.quick_health_check()
    print(f"Quick Health: {quick_health}")

    # 7. Offline manager
    print("\n--- 7. Offline Manager ---")
    print(f"Is Offline: {offline_manager.is_offline()}")
    print(f"Queue Size: {offline_manager.get_queue_size()}")

    print("\n=== All Network Status Examples Completed ===")

# Export functions
export = {
    'NetworkStatusMonitor': NetworkStatusMonitor,
    'ConnectionQualityMonitor': ConnectionQualityMonitor,
    'NetworkSpeedTester': NetworkSpeedTester,
    'OfflineManager': OfflineManager,
    'NetworkHealthChecker': NetworkHealthChecker,
    'demonstrate_network_status': demonstrate_network_status
}

💻 Vibration python

🟢 simple ⭐⭐

Contrôler la vibration de l'appareil pour le retour haptique avec des modèles et un timing

⏱️ 15 min 🏷️ python, web, mobile features
Prerequisites: Basic Python, Vibration API, JavaScript interop
# Web Python Vibration API Examples
# Using Vibration API for haptic feedback with JavaScript interop

import js
from typing import List, Dict, Any

# 1. Vibration Manager
class VibrationManager:
    def is_supported(self) -> bool:
        """
        Check if vibration is supported

        Returns:
            bool: True if supported
        """
        return hasattr(js.navigator, 'vibrate')

    def vibrate(self, duration: int) -> bool:
        """
        Vibrate for specified duration

        Args:
            duration: Duration in milliseconds

        Returns:
            bool: True if successful
        """
        if not self.is_supported():
            print("Vibration API not supported")
            return False

        return bool(js.navigator.vibrate(duration))

    def vibrate_pattern(self, pattern: List[int]) -> bool:
        """
        Vibrate with pattern

        Args:
            pattern: List of vibration durations (vibrate, pause, vibrate, ...)

        Returns:
            bool: True if successful
        """
        if not self.is_supported():
            print("Vibration API not supported")
            return False

        return bool(js.navigator.vibrate(pattern))

    def stop(self) -> bool:
        """
        Stop vibration

        Returns:
            bool: True if successful
        """
        if not self.is_supported():
            return False

        return bool(js.navigator.vibrate(0))


# 2. Haptic Feedback Patterns
class HapticFeedbackPatterns:
    def __init__(self):
        self.vibrate = VibrationManager()

    def tap(self):
        """Short tap feedback"""
        self.vibrate.vibrate(10)

    def medium_tap(self):
        """Medium tap feedback"""
        self.vibrate.vibrate(25)

    def strong_tap(self):
        """Strong tap feedback"""
        self.vibrate.vibrate(50)

    def success(self):
        """Success feedback"""
        self.vibrate.vibrate_pattern([50, 50, 50])

    def error(self):
        """Error feedback"""
        self.vibrate.vibrate_pattern([100, 50, 100, 50, 100])

    def warning(self):
        """Warning feedback"""
        self.vibrate.vibrate_pattern([50, 100, 50])

    def notification(self):
        """Notification feedback"""
        self.vibrate.vibrate_pattern([100, 50, 100])

    def confirmation(self):
        """Confirmation feedback (ask)"""
        self.vibrate.vibrate_pattern([30, 50, 30])

    def heartbeat(self):
        """Heartbeat pattern"""
        self.vibrate.vibrate_pattern([50, 50, 50, 200, 50, 50, 50, 200])

    def sos(self):
        """SOS pattern"""
        self.vibrate.vibrate_pattern([
            100, 50, 100, 50, 100, 200,
            200, 50, 200, 50, 200, 200,
            100, 50, 100, 50, 100, 200
        ])

    def ring(self, repeat: bool = False):
        """Ring pattern"""
        pattern = [1000, 500]
        self.vibrate.vibrate_pattern(pattern)

    def typing(self):
        """Typing feedback"""
        self.vibrate.vibrate(15)

    def delete(self):
        """Delete feedback"""
        self.vibrate.vibrate_pattern([50, 30, 50])

    def scroll_boundary(self):
        """Scroll boundary feedback"""
        self.vibrate.vibrate(25)

    def snap(self):
        """Snap feedback"""
        self.vibrate.vibrate_pattern([20, 30, 40])

    def brush(self):
        """Brush feedback"""
        self.vibrate.vibrate_pattern([10, 20, 10, 20, 10])


# 3. Vibration Sequencer
class VibrationSequencer:
    def __init__(self):
        self.vibrate = VibrationManager()
        self.sequences = {
            'dot': [30],
            'dash': [100],
            'dot-dot-dot': [30, 50, 30, 50, 30],
            'dash-dash-dash': [100, 50, 100, 50, 100],
            'dot-dash': [30, 50, 100],
            'dash-dot': [100, 50, 30]
        }

    def play(self, name: str) -> bool:
        """
        Play sequence by name

        Args:
            name: Sequence name

        Returns:
            bool: True if successful
        """
        pattern = self.sequences.get(name)
        if pattern:
            return self.vibrate.vibrate_pattern(pattern)
        return False

    def register_sequence(self, name: str, pattern: List[int]):
        """
        Register custom sequence

        Args:
            name: Sequence name
            pattern: Vibration pattern
        """
        self.sequences[name] = pattern

    def create_rhythm(self, beats: str) -> List[int]:
        """
        Create rhythm pattern from beat string

        Args:
            beats: Beat string (.=short, -=long, space=pause)

        Returns:
            list: Vibration pattern
        """
        pattern = []

        for char in beats:
            if char == '.':
                pattern.extend([30, 50])
            elif char == '-':
                pattern.extend([100, 50])
            elif char == ' ':
                pattern.extend([0, 200])

        # Remove trailing pause
        if len(pattern) > 1 and pattern[-1] == 0:
            pattern.pop()
            pattern.pop()

        return pattern

    def play_rhythm(self, beats: str) -> bool:
        """
        Play rhythm

        Args:
            beats: Beat string

        Returns:
            bool: True if successful
        """
        pattern = self.create_rhythm(beats)
        return self.vibrate.vibrate_pattern(pattern)


# 4. Notification Vibrations
class NotificationVibrations:
    def __init__(self):
        self.haptic = HapticFeedbackPatterns()

    def new_message(self):
        """New message vibration"""
        self.haptic.notification()

    def new_email(self):
        """New email vibration"""
        self.haptic.vibrate.vibrate_pattern([50, 100, 50, 100, 100, 100, 50, 200])

    def calendar_reminder(self):
        """Calendar reminder"""
        self.haptic.vibrate.vibrate_pattern([100, 50, 100, 50, 100, 200, 200])

    def alarm(self):
        """Alarm vibration"""
        self.haptic.vibrate.vibrate_pattern([500, 200, 500, 200])

    def phone_call(self):
        """Phone call"""
        self.haptic.ring()

    def missed_call(self):
        """Missed call"""
        self.haptic.vibrate.vibrate_pattern([100, 100, 100, 100, 100])


# 5. Game Feedback Vibrations
class GameFeedbackVibrations:
    def __init__(self):
        self.haptic = HapticFeedbackPatterns()

    def button_press(self):
        """Button press"""
        self.haptic.tap()

    def button_hold(self):
        """Button hold"""
        self.haptic.vibrate.vibrate_pattern([20, 10, 20])

    def hit(self, light: bool = False):
        """Hit feedback"""
        if light:
            self.haptic.tap()
        else:
            self.haptic.medium_tap()

    def critical_hit(self):
        """Critical hit"""
        self.haptic.vibrate.vibrate_pattern([50, 30, 100])

    def miss(self):
        """Miss feedback"""
        self.haptic.vibrate.vibrate(15)

    def explosion(self):
        """Explosion"""
        self.haptic.vibrate.vibrate_pattern([200, 50, 100, 50, 50])

    def power_up(self):
        """Power up"""
        self.haptic.vibrate.vibrate_pattern([30, 30, 50, 30, 70, 30, 100, 30, 150])

    def level_complete(self):
        """Level complete"""
        self.haptic.success()

    def game_over(self):
        """Game over"""
        self.haptic.error()

    def achievement(self):
        """Achievement unlocked"""
        self.haptic.vibrate.vibrate_pattern([
            50, 50, 50, 50, 50, 50,
            100, 50, 100, 50, 100, 50,
            200
        ])


# 6. Accessibility Vibrations
class AccessibilityVibrations:
    def __init__(self):
        self.haptic = HapticFeedbackPatterns()

    def tick(self):
        """Tick sound (for clock, timer)"""
        self.haptic.vibrate.vibrate(10)

    def tock(self):
        """Tock sound"""
        self.haptic.vibrate.vibrate(15)

    def hour_chime(self):
        """Hour chime"""
        self.haptic.vibrate.vibrate_pattern([100, 200, 100])

    def timer_complete(self):
        """Timer complete"""
        self.haptic.notification()

    def boundary_warning(self):
        """Boundary warning"""
        self.haptic.warning()

    def focus_reminder(self):
        """Focus reminder"""
        self.haptic.vibrate.vibrate_pattern([30, 100, 30])

    def step(self):
        """Step counter (each step)"""
        self.haptic.vibrate.vibrate(20)

    def goal_reached(self):
        """Goal reached"""
        self.haptic.success()

    def proximity_alert(self, level: int):
        """
        Proximity alert (getting closer)

        Args:
            level: Alert level (1-3)
        """
        patterns = {
            1: [20],
            2: [30, 100, 30],
            3: [50, 50, 50, 50]
        }
        self.haptic.vibrate.vibrate_pattern(patterns.get(level, [20]))


# 7. Vibration Composer
class VibrationComposer:
    def __init__(self):
        self.vibrate = VibrationManager()

    def compose(self, notes: List[Dict[str, Any]]):
        """
        Compose custom vibration from notes

        Args:
            notes: List of dicts with 'duration' and optional 'pause' keys
        """
        pattern = []

        for i, note in enumerate(notes):
            pattern.append(note['duration'])
            if i < len(notes) - 1:
                pattern.append(note.get('pause', 50))

        self.vibrate.vibrate_pattern(pattern)

    def compose_melody(self, notes: List[int], tempo: int = 200):
        """
        Compose melody

        Args:
            notes: List of note durations
            tempo: Time between notes in ms
        """
        pattern = []

        for i, note in enumerate(notes):
            pattern.append(note)
            if i < len(notes) - 1:
                pattern.append(tempo)

        self.vibrate.vibrate_pattern(pattern)

    def fade_in(self, max_duration: int, steps: int = 5):
        """
        Fade in effect

        Args:
            max_duration: Maximum vibration duration
            steps: Number of fade steps
        """
        pattern = []
        step_duration = max_duration / steps

        for i in range(1, steps + 1):
            pattern.extend([int(step_duration * i), 50])

        self.vibrate.vibrate_pattern(pattern)

    def fade_out(self, max_duration: int, steps: int = 5):
        """
        Fade out effect

        Args:
            max_duration: Maximum vibration duration
            steps: Number of fade steps
        """
        pattern = []
        step_duration = max_duration / steps

        for i in range(steps, 0, -1):
            pattern.extend([int(step_duration * i), 50])

        self.vibrate.vibrate_pattern(pattern)


# Usage Examples
async def demonstrate_vibration():
    print("=== Web Python Vibration API Examples ===\n")

    vibration_manager = VibrationManager()
    haptic_patterns = HapticFeedbackPatterns()
    sequencer = VibrationSequencer()
    game_feedback = GameFeedbackVibrations()
    composer = VibrationComposer()

    # 1. Check support
    print("--- 1. Vibration Support ---")
    print(f"Vibration Supported: {vibration_manager.is_supported()}")

    if not vibration_manager.is_supported():
        print("Vibration API is not supported on this device")
        return

    # 2. Basic vibration
    print("\n--- 2. Basic Vibration ---")
    print("Short vibration...")
    vibration_manager.vibrate(100)

    # 3. Haptic patterns
    print("\n--- 3. Haptic Patterns ---")
    print("Success pattern...")
    haptic_patterns.success()

    print("Error pattern...")
    haptic_patterns.error()

    print("Warning pattern...")
    haptic_patterns.warning()

    # 4. Sequencer
    print("\n--- 4. Sequencer ---")
    print("SOS pattern...")
    haptic_patterns.sos()

    # 5. Game feedback
    print("\n--- 5. Game Feedback ---")
    print("Hit...")
    game_feedback.hit()

    print("Critical hit...")
    game_feedback.critical_hit()

    print("Power up...")
    game_feedback.power_up()

    # 6. Composer
    print("\n--- 6. Vibration Composer ---")
    print("Composed melody...")
    composer.compose_melody([100, 150, 200, 150, 100], 150)

    print("\n=== All Vibration API Examples Completed ===")

# Export functions
export = {
    'VibrationManager': VibrationManager,
    'HapticFeedbackPatterns': HapticFeedbackPatterns,
    'VibrationSequencer': VibrationSequencer,
    'NotificationVibrations': NotificationVibrations,
    'GameFeedbackVibrations': GameFeedbackVibrations,
    'AccessibilityVibrations': AccessibilityVibrations,
    'VibrationComposer': VibrationComposer,
    'demonstrate_vibration': demonstrate_vibration
}