🎨 Palette: Add tactile feedback to FlightScreen#42
🎨 Palette: Add tactile feedback to FlightScreen#42TargetMisser wants to merge 2 commits intomainfrom
Conversation
- Added `expo-haptics` to `FlightScreen` for micro-UX delight. - Light haptic impact on Arrival/Departure and Today/Tomorrow tab switches. - Success notification feedback on flight pinning. - Selection feedback on flight unpinning. - Physical 'tick' (haptic selection) when swiping flight cards past the threshold. - Implemented `hasTriggeredHaptic` ref to prevent repeated buzzing during swipe. - Created UX journal in `.Jules/palette.md`. Co-authored-by: TargetMisser <52361977+TargetMisser@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Fixed CI failure caused by out-of-sync `package-lock.json`. - Updated lockfile to satisfy dependencies: `@react-native-picker/picker@2.11.4`, `pdfjs-dist@5.6.205`, `react-native-webview@13.16.1`. - Added missing `expo-secure-store@15.0.8` to lockfile. Co-authored-by: TargetMisser <52361977+TargetMisser@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds micro-UX haptic feedback to FlightScreen interactions (tab/day segmented controls, pin/unpin actions, and swipe-to-toggle gestures) using expo-haptics, and records the related UX guidance in the Jules palette notes.
Changes:
- Added
expo-hapticstriggers for tab/day switches, pin/unpin, and swipe threshold crossing. - Introduced swipe gesture gating state to avoid repeated haptic triggering during continuous pan updates.
- Added
.Jules/palette.mdnotes documenting the “trigger once” haptics pattern for gestures.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| src/screens/FlightScreen.tsx | Adds haptics to key FlightScreen actions (segmented controls, pin/unpin, swipe threshold). |
| .Jules/palette.md | Documents learned patterns for adding haptics without “buzzing” during continuous gestures. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } else if (g.dx >= -SWIPE_THRESHOLD && hasTriggeredHaptic.current) { | ||
| hasTriggeredHaptic.current = false; |
There was a problem hiding this comment.
hasTriggeredHaptic is reset when the swipe moves back above the threshold (dx >= -SWIPE_THRESHOLD), so a single swipe gesture can trigger Haptics.selectionAsync() multiple times if the user jitters across the threshold. If the intent is “exactly once per gesture”, keep the ref true until onPanResponderRelease/Terminate and remove the mid-gesture reset (or update the gating logic accordingly).
| } else if (g.dx >= -SWIPE_THRESHOLD && hasTriggeredHaptic.current) { | |
| hasTriggeredHaptic.current = false; |
| const tab = activeTab; | ||
| await AsyncStorage.setItem(PINNED_FLIGHT_KEY, JSON.stringify({ ...item, _pinTab: tab, _pinnedAt: Date.now() })); | ||
| setPinnedFlightId(id); | ||
| Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); |
There was a problem hiding this comment.
Haptics.notificationAsync(...) returns a Promise, but it’s not awaited or handled. If it rejects (e.g., unsupported platform), it can create unhandled promise rejections. Consider calling it with void ...catch(() => {}) or awaiting it inside the surrounding try (and/or gating with Haptics.isAvailableAsync() / Platform.OS !== 'web').
| Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); | |
| void Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success).catch(() => {}); |
| await AsyncStorage.removeItem(PINNED_FLIGHT_KEY); | ||
| try { await cancelPinnedNotifications(); } catch (e) { if (__DEV__) console.warn('[cancelPinNotif]', e); } | ||
| setPinnedFlightId(null); | ||
| Haptics.selectionAsync(); |
There was a problem hiding this comment.
Haptics.selectionAsync() is fire-and-forget here; if it rejects on unsupported platforms it can surface as an unhandled promise rejection. Consider using void Haptics.selectionAsync().catch(() => {}) (and/or gating with Haptics.isAvailableAsync() / Platform.OS !== 'web').
| Haptics.selectionAsync(); | |
| void Haptics.selectionAsync().catch(() => {}); |
| onPress={() => { | ||
| setActiveTab(tab); | ||
| Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); | ||
| }} |
There was a problem hiding this comment.
Haptics.impactAsync(...) returns a Promise but isn’t awaited/handled; on unsupported platforms this can generate unhandled promise rejections. Consider wrapping haptics in a small helper that gates by platform/availability and uses void ...catch(() => {}).
| onPress={() => { | ||
| setActiveDay(d); | ||
| Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); | ||
| }} |
There was a problem hiding this comment.
Same as above: Haptics.impactAsync(...) is not awaited/handled, which can lead to unhandled promise rejections on platforms where haptics are unavailable (notably web). Consider gating/handling via a shared helper.
🎨 Palette: Micro-UX Haptic Feedback
💡 What: Added physical tactile feedback to the
FlightScreenusingexpo-haptics.🎯 Why: To make the interface feel more responsive and physical. Users get immediate, delightful feedback when performing important actions like switching tabs, pinning/unpinning flights, or swiping list items.
♿ Accessibility: Provides non-visual confirmation of state changes, benefiting users who rely on multi-sensory feedback.
Changes:
PR created automatically by Jules for task 562722060276858861 started by @TargetMisser