haptics.ts
1 import * as Haptics from 'expo-haptics'; 2 import { Platform } from 'react-native'; 3 4 export enum HapticType { 5 Light = 'light', 6 Medium = 'medium', 7 Heavy = 'heavy', 8 Success = 'success', 9 Warning = 'warning', 10 Error = 'error', 11 Selection = 'selection', 12 } 13 14 class HapticFeedbackService { 15 private static instance: HapticFeedbackService; 16 private isEnabled: boolean = true; 17 18 private constructor() {} 19 20 static getInstance(): HapticFeedbackService { 21 if (!HapticFeedbackService.instance) { 22 HapticFeedbackService.instance = new HapticFeedbackService(); 23 } 24 return HapticFeedbackService.instance; 25 } 26 27 setEnabled(enabled: boolean): void { 28 this.isEnabled = enabled; 29 } 30 31 async trigger(type: HapticType): Promise<void> { 32 if (!this.isEnabled || Platform.OS === 'web') { 33 return; 34 } 35 36 try { 37 switch (type) { 38 case HapticType.Light: 39 await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); 40 break; 41 case HapticType.Medium: 42 await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); 43 break; 44 case HapticType.Heavy: 45 await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy); 46 break; 47 case HapticType.Success: 48 await Haptics.notificationAsync( 49 Haptics.NotificationFeedbackType.Success 50 ); 51 break; 52 case HapticType.Warning: 53 await Haptics.notificationAsync( 54 Haptics.NotificationFeedbackType.Warning 55 ); 56 break; 57 case HapticType.Error: 58 await Haptics.notificationAsync( 59 Haptics.NotificationFeedbackType.Error 60 ); 61 break; 62 case HapticType.Selection: 63 await Haptics.selectionAsync(); 64 break; 65 default: 66 await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); 67 } 68 } catch (error) { 69 console.warn('Haptic feedback failed:', error); 70 } 71 } 72 73 // Convenience methods for common interactions 74 async onPress(): Promise<void> { 75 return this.trigger(HapticType.Light); 76 } 77 78 async onLongPress(): Promise<void> { 79 return this.trigger(HapticType.Medium); 80 } 81 82 async onSuccess(): Promise<void> { 83 return this.trigger(HapticType.Success); 84 } 85 86 async onError(): Promise<void> { 87 return this.trigger(HapticType.Error); 88 } 89 90 async onSelection(): Promise<void> { 91 return this.trigger(HapticType.Selection); 92 } 93 94 async onSwipe(): Promise<void> { 95 return this.trigger(HapticType.Light); 96 } 97 98 async onBookmark(): Promise<void> { 99 return this.trigger(HapticType.Medium); 100 } 101 102 async onChapterComplete(): Promise<void> { 103 return this.trigger(HapticType.Success); 104 } 105 } 106 107 export const hapticFeedback = HapticFeedbackService.getInstance(); 108 109 // React hook for haptic feedback 110 export function useHapticFeedback() { 111 return { 112 onPress: () => hapticFeedback.onPress(), 113 onLongPress: () => hapticFeedback.onLongPress(), 114 onSuccess: () => hapticFeedback.onSuccess(), 115 onError: () => hapticFeedback.onError(), 116 onSelection: () => hapticFeedback.onSelection(), 117 onSwipe: () => hapticFeedback.onSwipe(), 118 onBookmark: () => hapticFeedback.onBookmark(), 119 onChapterComplete: () => hapticFeedback.onChapterComplete(), 120 trigger: (type: HapticType) => hapticFeedback.trigger(type), 121 setEnabled: (enabled: boolean) => hapticFeedback.setEnabled(enabled), 122 }; 123 }