Conversation
Contributor
|
@dependabot rebase |
Updates the requirements on [hashicorp/aws](https://github.com/hashicorp/terraform-provider-aws) to permit the latest version. - [Release notes](https://github.com/hashicorp/terraform-provider-aws/releases) - [Changelog](https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md) - [Commits](hashicorp/terraform-provider-aws@v5.0.0...v6.32.1) --- updated-dependencies: - dependency-name: hashicorp/aws dependency-version: 6.32.1 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com>
2ccef46 to
bec263a
Compare
Ur-imazing
added a commit
that referenced
this pull request
Apr 20, 2026
- ContentRail: pass `item` directly through the renderItem hooks callback instead of looking it up via `data[index]` at callback time. FlatList fires focus callbacks asynchronously and an Apollo cache update can shrink `data` between render and callback, making `data[index]` undefined and crashing consumers that read `item.documentId` (review finding P1 #2). - ContentRail: remove the redundant wrapper `<View onFocus>`. Both the wrapper and `hooks.onFocus` resolved to the same `handleItemFocus(index)` call and fired per focus event on platforms where View focus bubbles, double-dispatching the debounce timer and any analytics (P2 #5). - ContentRail: drop the dead `focusMemory` module-level Map. It was written on every focus event but never read anywhere in the codebase (P3 #11). - HomeHero: move `HeroEntry` type to module scope — it was defined inside the component body for no reason (P3 #16). - HomeScreen: replace the local `COLORS` constant that duplicated `src/lib/colors.ts`. Every other component imports the canonical tokens; `index.tsx` was silently drifting (P3 #13). - HomeScreen: derive `effectiveCommittedId = committedId ?? homepageExperience?.documentId ?? null` so the hero renders on first paint rather than waiting for the `useEffect`-seeded `committedId`. Previously a blank hero surface flashed for ~50-100ms on cold mount while the effect fired (P2 #9). - HomeScreen: depend the accessibility-announce effect on `hero?.id`/title/subtitle rather than the `hero` object reference, so Apollo cache re-normalisations that produce a new object identity for the same experience don't trigger spurious re-runs (P3 #14). - queries.ts: remove orphaned comment referencing GET_WATCH_EXPERIENCE that trailed LIST_EXPERIENCES after the surrounding context was moved (P3 #12).
Ur-imazing
added a commit
that referenced
this pull request
Apr 20, 2026
…803) * feat(tv): include VideoHero block in LIST_EXPERIENCES for focus-driven hero Extend the home-screen listing query to carry each experience's first ComponentSectionsVideoHero block alongside its lightweight fields so the rail-driven hero can swap without a second round-trip per focus change. Non-VideoHero blocks are returned with __typename only. Plan: docs/plans/2026-04-17-001-feat-tv-focus-driven-hero-plan.md (Unit 1) * feat(tv): add onItemFocus prop to ContentRail Surface per-item focus events to rail consumers so the home screen can drive a focus-driven hero. Preserves existing focusMemory write behavior; the new prop is optional and additive. Plan: docs/plans/2026-04-17-001-feat-tv-focus-driven-hero-plan.md (Unit 2) * feat(tv): focus-driven hero swaps with rail card focus Rewrite HomeHero to accept a single hero prop and cross-dissolve between previous and current media via two stacked layers. The Explore CTA lives in a stable text overlay (not a crossfading layer) so its first-mount focus claim and identity survive hero swaps. Honors AccessibilityInfo reduce-motion by snapping between states. In HomeScreen, replace the dual LIST_EXPERIENCES + GET_WATCH_EXPERIENCE queries with the extended LIST_EXPERIENCES (now includes each experience's first VideoHero block). A 300ms trailing-only debounce timer holds a committed-experience id; rail focus resets the timer, commit fires on timeout. Initial render seeds the committed id to isHomepage. Explore CTA targets whichever experience the hero currently reflects, never a transiently-focused card. Accessibility: after commit, dispatch AccessibilityInfo.announceForAccessibility with the new hero's title + subtitle, guarded against duplicate announcements when focus returns to the already-committed card. Plan: docs/plans/2026-04-17-001-feat-tv-focus-driven-hero-plan.md (Units 3-6) * fix(tv): wire rail focus through FocusableCard, not wrapper View The wrapper View's onFocus does not reliably fire on react-native-tvos when a nested Pressable inside FocusableCard gains focus, so the focus-driven hero swap never triggered on real hardware. Pass an explicit focus hook into renderItem and plumb it straight into FocusableCard's onFocus prop, where it fires deterministically. Keep the wrapper View's onFocus as a fallback so existing callers that don't consume the hook still get focusMemory updates. * fix(tv): show poster during HLS init to prevent black hero flash When the focus-driven hero swaps to a new experience's streaming URL, the native VideoView surface renders black while HLS loads the manifest, estimates bandwidth, and decodes the first frame — often 200–800ms on TV hardware, and unmaskable on Android TV where the VideoView punches through the RN view hierarchy. Render the poster image as a base layer that always paints first, and only mount the VideoView once the player reports readyToPlay. When the video is ready, fade it in over the poster in 200ms. The user never sees a black hero during a swap. * fix(tv): freeze outgoing video and hold new poster for a seamless swap Replace the prev/current slot pattern with a keyed layer stack so each MediaLayer stays mounted across a hero commit. The outgoing layer now stays where it was — its VideoView keeps painting the video's last frame during the fade instead of re-mounting against the outgoing experience's poster image (which was the jarring mid-transition still the user was seeing). Pause the outgoing player on deactivate so the painted frame freezes instead of continuing to animate during the fade. On the incoming layer, after the player reports readyToPlay hold the poster visible for 1s, then crossfade to the video over 500ms. This gives the eye a single stable still between the outgoing and incoming videos rather than a rapid-fire video→still→still→video sequence. Reduce Motion skips the hold and snaps. * chore(tv): shorten hero poster hold to 500ms * fix(tv): keep focus out of home hero video, add silent focus target on detail Home: propagate pointerEvents="none" to every wrapper around the VideoView inside MediaLayer so the TV focus engine doesn't stop on the native video surface when the user D-pads up out of the rail. Focus now consistently lands on the Explore CTA whether the hero's video is playing or still loading as a poster. Experience detail: the hero was non-focusable, which prevented the user from scrolling back to the top of the screen once they moved down into the blocks. Add a full-bleed Pressable behind the text overlay as a silent focus target — invisible focus state, but acceptable as a D-pad UP landing spot so ScrollView can scroll the hero back into view. * fix(tv): let hero-wide TVFocusGuide redirect rail UP-focus to Explore The previous guide only wrapped the text container at the bottom of the hero. When D-padding UP from the rail, focus tried to land somewhere in the video region above the guide — the native VideoView caught it and the Explore button was never reached while the video was mounted. Wrap the entire hero container in TVFocusGuideView so any upward focus attempt into the hero area is redirected to the Explore Pressable, regardless of whether the video is mounted or not. * fix(tv): let rail receive focus directly on first DOWN from Explore trapFocusDown=false on the hero TVFocusGuideView so DOWN from Explore exits the hero region in a single press instead of bouncing off the guide's bounds once. * fix(tv): make Explore a sibling of the hero focus guide, not a descendant Explore Pressable was inside the TVFocusGuideView, so DOWN from Explore bounced off the guide's bounds once and required a second press to reach the rail. Move the guide to wrap only the media layers and gradient so Explore sits as a sibling in the view hierarchy. The guide still catches upward focus attempts into the media region and redirects them to Explore, but no longer traps Explore's own outbound DOWN movement. * fix(tv): single-press DOWN from Explore to rail via nextFocusDown trapFocusDown on the hero's TVFocusGuideView didn't prevent Explore's outbound DOWN from bouncing off the guide's bounds, so the rail required two presses. Plumb the rail's TVFocusGuideView handle up to HomeScreen, pass it into HomeHero as `nextFocusDownHandle`, and bind it to Explore's `nextFocusDown` prop. Focus now crosses directly from Explore into the rail on a single D-pad press without any guide bounce. Verified end-to-end via keystroke-driven screenshots on the tvOS simulator: DOWN → rail focus, UP → Explore focus, DOWN again → rail focus on first press. Also switch Explore's ref to a callback ref + state-backed node handle so the hero's focus-guide destinations always resolve on first render (React commits refs after render, so a render-time read of `exploreRef.current` was null initially and left the guide without a destination). Route Explore's node handle through a callback-ref so the hero focus guide has a valid destination from first render. * docs(tv): add focus-driven hero brainstorm and plan Brainstorm requirements and implementation plan that drove the focus-driven hero feature shipped in the preceding tv commits. * fix(tv): explore wins initial focus and never drops into limbo Pre-fix: ContentRail's TVFocusGuideView autoFocus claimed initial focus for the first rail card, overriding the Explore Pressable's hasTVPreferredFocus. Pressing UP or DOWN from Explore could leave focus stranded in the hero's non-focusable video region. Changes: - Drop autoFocus from ContentRail's TVFocusGuideView so Explore's hasTVPreferredFocus wins on first mount. - Wrap the hero's text overlay in a TVFocusGuideView with trapFocusUp + autoFocus so UP from Explore keeps Explore focused instead of leaking focus into the video area. - Plumb the Explore Pressable's native handle up through onExploreHandleChange so each rail card gets nextFocusUp routed directly to Explore. - Keep nextFocusDown on Explore so DOWN moves into the rail. - Make Explore's focused state visible: add a white border + glow on top of the 1.08x scale, since tvOS Pressable shadows in the button's own primary color were nearly invisible against the hero gradient. - Disable ScrollView scroll on the home screen (content fits and scroll attempts were blurring Explore on UP). * fix(tv): single-press DOWN from Explore while keeping UP trapped Move the `trapFocusUp` TVFocusGuideView from the text container up to the hero container. Wrapping only the text container made the guide's frame tight enough that the first DOWN press got absorbed by the guide instead of routing through Explore's `nextFocusDown` to the rail. Wrapping the entire hero keeps UP trapped inside the hero (no focusable above Explore in the hero — so UP becomes a no-op), while DOWN from Explore exits the hero boundary in a single press and lands on the rail via the `nextFocusDown` handle. Verified on tvOS simulator via keystroke-driven screenshots: - Initial: Explore visibly focused - UP from Explore: stays on Explore - DOWN from Explore: first press focuses a rail card - UP from rail: returns to Explore * fix(tv): harden hero against VideoView hijacking focus while playing When the hero's native VideoView is actively painting, the tvOS focus engine treats it as a focus candidate even with focusable={false} on VideoView itself. This caused UP/DOWN from Explore to blur into limbo while the video played. Layer the guards so tvOS reliably skips over the video surface: - isTVSelectable={false} on every View/Animated.View wrapping the media layers inside the hero (outer and inner). - Self-referencing nextFocusUp on the Explore Pressable so UP from Explore resolves back to Explore instead of the video above. - Retain the outer hero TVFocusGuideView trapFocusUp as a second line of defense. DOWN from Explore now reaches a rail card in a single press even with the video playing. UP from rail into Explore and initial focus on Explore are preserved. * refactor(tv): make the home hero non-interactive, rail owns all focus Remove the Explore CTA and all the focus-routing plumbing that tried to coordinate focus between it and the rail. The native VideoView kept hijacking focus away from any interactive element placed above the rail, which forced an ever-growing list of guards (nextFocusUp self-references, TVFocusGuideView trapFocusUp wrappers, isTVSelectable={false} on every wrapper, state-backed node handles, etc.) and still wasn't robust once the video was painting. New model: - HomeHero is now purely presentational — title, subtitle, and the crossfading video/poster. No Pressable, no focus concerns. - ContentRail's TVFocusGuideView autoFocus claims initial focus on the first card. The user navigates experiences by D-padding the rail and pressing Select to open the focused experience. - Drop the Explore-related props from HomeHero/ContentRail/FocusableCard (nextFocusUp, nextFocusDown, onExploreHandleChange, onFocusHandleChange, itemNextFocusUp). - Re-enable ScrollView scroll on the home screen. Net effect: something is always visibly focused (the rail auto-focuses on mount), the video hero no longer competes for focus, and the whole focus system is dramatically simpler. * fix(tv): apply code review safe_auto findings - ContentRail: pass `item` directly through the renderItem hooks callback instead of looking it up via `data[index]` at callback time. FlatList fires focus callbacks asynchronously and an Apollo cache update can shrink `data` between render and callback, making `data[index]` undefined and crashing consumers that read `item.documentId` (review finding P1 #2). - ContentRail: remove the redundant wrapper `<View onFocus>`. Both the wrapper and `hooks.onFocus` resolved to the same `handleItemFocus(index)` call and fired per focus event on platforms where View focus bubbles, double-dispatching the debounce timer and any analytics (P2 #5). - ContentRail: drop the dead `focusMemory` module-level Map. It was written on every focus event but never read anywhere in the codebase (P3 #11). - HomeHero: move `HeroEntry` type to module scope — it was defined inside the component body for no reason (P3 #16). - HomeScreen: replace the local `COLORS` constant that duplicated `src/lib/colors.ts`. Every other component imports the canonical tokens; `index.tsx` was silently drifting (P3 #13). - HomeScreen: derive `effectiveCommittedId = committedId ?? homepageExperience?.documentId ?? null` so the hero renders on first paint rather than waiting for the `useEffect`-seeded `committedId`. Previously a blank hero surface flashed for ~50-100ms on cold mount while the effect fired (P2 #9). - HomeScreen: depend the accessibility-announce effect on `hero?.id`/title/subtitle rather than the `hero` object reference, so Apollo cache re-normalisations that produce a new object identity for the same experience don't trigger spurious re-runs (P3 #14). - queries.ts: remove orphaned comment referencing GET_WATCH_EXPERIENCE that trailed LIST_EXPERIENCES after the surrounding context was moved (P3 #12). * feat(tv): focus-driven hero swaps to selected experience's video Home hero now renders the VideoHero block of whichever Experience card is focused in the rail, so the background poster/video tracks D-pad selection instead of being hard-coded. Adds compile-time asserts that gql.tada's discriminated union for the blocks dynamic zone did not collapse to `never`, since that failure mode is silent under tsc. Documents the intentional divergence from the mobile LIST_EXPERIENCES shape so future sync passes don't clobber the per-experience hero data. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(solutions): capture TV focus-driven hero patterns and refresh the cluster Adds a new best-practices learning documenting the patterns that came out of PR #803 (non-interactive hero, rail-owns-focus, poster-hold during HLS source swap, compile-time `never`-collapse assert for gql.tada dynamic zones), and refreshes four adjacent docs whose guidance was either superseded or incomplete in light of it: - ui-bugs/tv-videoview-steals-dpad-focus — Prevention superseded the "wrap the hero in TVFocusGuideView" recommendation for hero-above-rail layouts; now points at the new learning. - ui-bugs/tv-video-hero-blank-autoplay — adds a "Source swap on focus change" section covering the poster-hold technique. - best-practices/react-native-tvos-porting-pitfalls — adds Pitfall 6 (background VideoView + focusable siblings). - best-practices/expo-tv-platform-setup-sdui-monorepo — Section 3 notes the LIST_EXPERIENCES divergence; Section 6 adds the rail-owns-focus pattern. Also drops a duplicate last_updated key. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9 tasks
Ur-imazing
added a commit
that referenced
this pull request
Apr 23, 2026
…+ crimson palette (#830) * docs(tv): brainstorm + plan for video-player auto-hide controls Captures the requirements (5s auto-hide via D-pad, play/pause initial focus, crimson palette alignment) and the 7-unit implementation plan for apps/tv/src/components/VideoPlayer.tsx. Brainstorm: docs/brainstorms/2026-04-21-tv-video-player-controls-auto-hide-requirements.md Plan: docs/plans/2026-04-22-001-feat-tv-video-player-auto-hide-controls-plan.md * feat(tv): scaffold video-player auto-hide state + retire warm-salmon palette Unit 1 of docs/plans/2026-04-22-001-feat-tv-video-player-auto-hide-controls-plan.md. Introduces the auto-hide state machine scaffolding in VideoPlayer.tsx and retires the file-local warm-salmon design tokens. This is foundation-only — subscriptions + refs are in place but the behavioral surface (fade, catcher, buffering/error handling) lands in Units 2-7. - Add controlsVisible, controlsFocusable, status, hasError, isScreenReaderEnabled, isReduceMotionEnabled state. - Add revealFocusPending + errorFocusPending one-shot focus flags (I6), mirroring Fix #5's clear-after-render pattern. - Add stable handler refs (scheduleHideRef, revealControlsRef) so subscriptions in Units 2-3 don't churn the native event emitter. - Mirror controlsVisible and isScreenReaderEnabled into refs so the useTVEventHandler callback in Unit 3 can read without re-binding. - Subscribe to AccessibilityInfo screenReaderChanged and reduceMotionChanged (HomeHero subscription shape). - Subscribe to AppState: on 'active', snap visible + rearm timer. - Claim hardware Menu on tvOS via TVEventControl.enableTVMenuKey() with menuKeyEnabledRef bookkeeping so cleanup is idempotent. - Clear inactivityTimerRef on unmount. - Move hasTVPreferredFocus from back pill to play/pause ({shouldRequestFocus || revealFocusPending}); back pill now receives {errorFocusPending} for Unit 5's error-state focus. - Retire the file-local warm-salmon tokens (ACCENT, ACCENT_ON, TEXT_PRIMARY, TEXT_SECONDARY) and swap every call-site to the shared Crimson Gallery COLORS.* tokens. Play button + progress fill are now COLORS.primary; icons + title use COLORS.text; subtitle + time readouts use COLORS.muted. All eight existing numbered fixes (#4, #5, #6, #8, #9, #15, #24, #25) are preserved. Typecheck + lint clean. * feat(tv): wire video-player auto-hide fade + 5s inactivity timer Unit 2 of docs/plans/2026-04-22-001-feat-tv-video-player-auto-hide-controls-plan.md. Implements the core hide/reveal cycle that Unit 1 scaffolded. - Wrap topBar and controlsContainer in Animated.View, both bound to the shared opacityAnim; collapsable={false} preserves z-order above the Android TV VideoView surface. - Add hideControls: setControlsFocusable(false) before the animation so UIFocusEngine releases the controls before they're invisible (I7 ordering), then 150 ms ease-out fade (or opacityAnim.setValue(0) when reduce-motion is active), then flip controlsVisible to false. - Add scheduleHide: idempotent timer arm — clears any in-flight timer, then only re-arms a new 5 s if the state supports auto-hide (not paused, not loading/error, no hasError, no screen reader). - Add revealControls: early-return when already visible to neutralize the catcher-onPress vs useTVEventHandler-select double-dispatch race that Unit 3 introduces. Does NOT reset opacityAnim before animating to 1 — in-flight hide animations reverse from their current mid-fade value, avoiding a black flash. - Assign scheduleHide / revealControls into their stable refs so the AppState handler (Unit 1) and event handlers (Unit 3) see the latest closure — mirrors Fix #15's onDismissRef. - Modify playingChange listener: clear timer on pause, call scheduleHideRef on resume. First isPlaying=true arms the D1 initial 5 s countdown. - Add a 2 s mount fallback that calls scheduleHideRef unconditionally — covers the race where autoplay retry succeeds but playingChange hasn't fired yet. scheduleHide is idempotent so the normal path wins. - Every control Pressable (back, rewind, play/pause, forward) now reads focusable={controlsFocusable} and calls scheduleHide on onFocus; the three active controls also call scheduleHide on onPress after their original handler (satisfies D14). Typecheck + lint clean. * feat(tv): add D-pad catcher + event routing for hidden video-player chrome Unit 3 of docs/plans/2026-04-22-001-feat-tv-video-player-auto-hide-controls-plan.md. Closes the loop from Unit 2: hidden controls now have an owner for D-pad input, so any key reveals the chrome without firing the focused button's action. - Add useTVEventHandler with a ref-stable useCallback (reads controlsVisibleRef / isScreenReaderEnabledRef / revealControlsRef / scheduleHideRef) so the native TV emitter doesn't re-register on every render. Hidden state: any recognized event triggers reveal. Visible state: Siri-remote swipes reset the timer for D14 (arrow / Select events already reset via Pressable onFocus / onPress). Defensive whitelist-or-fallback on the event-type string — names vary across react-native-tvos versions and Siri-remote generations. - Add BackHandler.addEventListener('hardwareBackPress'). Returns true to consume. Hidden → revealControls. Visible → onDismissRef. react-native-tvos bridges tvOS hardware Menu into this event, so a single subscription covers both platforms. Paired with TVEventControl.enableTVMenuKey from Unit 1 to keep Expo Router's Stack from popping before our handler runs. - Render an invisible Pressable catcher as the first child of TVFocusGuideView when !controlsVisible && !isScreenReaderEnabled. StyleSheet.absoluteFillObject lifts it above the sibling flex layout; hasTVPreferredFocus claims focus on mount (fresh mount per hide cycle); onPress={revealControls} is the primary Select path. collapsable={false} preserves Android TV z-order above the VideoView surface. accessibilityLabel + accessibilityRole for App Store review. - revealControls' existing early-return on controlsVisibleRef.current already neutralizes the catcher-onPress vs useTVEventHandler-select double-dispatch race (see Unit 2). Typecheck + lint clean. * docs(tv): document U4 focus-restore mitigation choice on play/pause Pressable Unit 4 of docs/plans/2026-04-22-001-feat-tv-video-player-auto-hide-controls-plan.md. The focus-restore wiring itself was landed across Units 1 and 2: - U1 added revealFocusPending state + clearing useEffect + wired hasTVPreferredFocus={shouldRequestFocus || revealFocusPending} on play/pause. - U2 added setRevealFocusPending(true) inside revealControls(). The plan offered three mitigations for tvOS's continuously-mounted Pressable focus behaviour. We rely on mitigation (b) — per-cycle focusable toggle — because Unit 2 already flips controlsFocusable on every hide/reveal, producing a "new focus target" event for UIFocusEngine. This comment records the choice so device QA knows which path is in play and what the fallback is (mitigation (a): a per-cycle `key` on the Pressable). * feat(tv): handle video-player buffering + terminal playback error Unit 5 of docs/plans/2026-04-22-001-feat-tv-video-player-auto-hide-controls-plan.md. - Subscribe to player.addListener('statusChange', ...). Branches on the expo-video VideoPlayerStatus literal union — confirmed from node_modules as 'idle' | 'loading' | 'readyToPlay' | 'error' (there is no 'buffering' or 'playing' value). Uses controlsVisibleRef and seekTargetRef to avoid stale-closure reads inside the long-lived callback. - 'loading' + seekTargetRef.current !== null → no-op. Fix #4's seek guard already handles the UI; without this branch the timer would suspend (and force-reveal) on every 10 s skip press. - 'loading' + no seek → clear timer, force reveal if hidden. A hidden stall is indistinguishable from 'video ended' for a low-confidence user; showing chrome during buffering gives them an affordance. revealControls' early-return makes this a no-op if already visible. - 'readyToPlay' → scheduleHideRef to restart the 5 s countdown. - 'idle' → no-op (mount-time default, not a runtime transition). - 'error' → setHasError(true), clear the timer permanently, snap chrome visible, set errorFocusPending=true. hasError gates every subsequent scheduleHide call (added to U2's guard list). Back pill claims focus via hasTVPreferredFocus={errorFocusPending} (Unit 1). - Replace titleRow contents with 'Playback failed — press Back to exit.' when hasError. Inline, not a separate layer — preserves the single-file / single-overlay constraint. Subtitle stays for context. - Ghost rewind / play/pause / forward Pressables when hasError: focusable={controlsFocusable && !hasError} plus a new styles.controlDisabled (opacity 0.3) applied to each. The controls remain mounted so the spatial layout doesn't collapse — only the back pill is meaningful in the error state. Typecheck + lint clean. * feat(tv): flash chrome for one paint before video-player playToEnd dismiss Unit 6 of docs/plans/2026-04-22-001-feat-tv-video-player-auto-hide-controls-plan.md. - Modify the playToEnd listener so that when chrome is hidden at end-of-video, we synchronously snap it visible (setControlsVisible / setControlsFocusable / opacityAnim.setValue(1)) and dispatch onDismissRef via setTimeout(0). Intent is imperceptible technical continuity — the chrome appears for one paint so the dismiss transition doesn't start from a black-screen-with-no-UI. setTimeout(0) queues the dismiss after the current render commit; rAF's mapping to the native paint thread is less specified under react-native-tvos, so we avoid it here. Fallback to rAF if device QA shows a black frame on a hidden-to-dismissed transition. - Refactor to a doDismiss closure so both visible- and hidden-state paths share the Fix #24 try/catch wrapping. - Preserves I4a: playToEnd still always calls onDismissRef.current() — the new logic only delays the call by one tick when chrome was hidden, it never suppresses it. - Expand the comment on Unit 1's AppState handler to document the paused-state branch: scheduleHide's internal isPaused guard (U2) makes an explicit AppState-level guard unnecessary, which avoids re-subscribing AppState on every pause toggle. Also clarifies that playback resume behaviour is out of scope per the plan's deferred items. Typecheck + lint clean. * feat(tv): polish video-player accessibility for screen readers Unit 7 of docs/plans/2026-04-22-001-feat-tv-video-player-auto-hide-controls-plan.md. - Add a useEffect keyed on isScreenReaderEnabled that handles mid-session SR toggles. SR→on: reveal chrome if hidden (the user just gained access to controls they couldn't navigate) plus AccessibilityInfo.announceForAccessibility('Player controls visible') for audible confirmation. SR→off: rearm via scheduleHideRef so a passive viewer who briefly toggled VO on-then- off doesn't get stuck with permanent chrome. A srSeededRef guard skips the first invocation so the mount-time seed from AccessibilityInfo doesn't fire spurious side-effects. - Add accessibilityLabel + accessibilityRole='button' to every control Pressable: back: "Back to {subtitle}" when a subtitle is present, else "Back" rewind: "Rewind 10 seconds" play/pause: dynamic — "Play" when paused, "Pause" when playing forward: "Forward 10 seconds" The invisible catcher (Unit 3) already carries "Show player controls" + role=button. - Unit 3's catcher conditional render ({!controlsVisible && !isScreenReaderEnabled && ...}) means the catcher is NEVER rendered when a screen reader is active, so VoiceOver/TalkBack never encounters a blank interactive element. Plus U2's scheduleHide already bails on isScreenReaderEnabled, so auto-hide never fires while SR is on. Typecheck + lint clean. * fix(tv): stop video-player auto-hide loop + shorten inactivity to 3s Two fixes surfaced by manual QA on the Apple TV simulator: 1. Reveal-on-any-event was too aggressive. The hidden-state branch of useTVEventHandler triggered revealControls on ANY TV event, including the synthetic focus/blur/pan events that react-native-tvos fires when the engine reassigns focus. When the catcher mounted post-hide with hasTVPreferredFocus, the focus acquisition fired a synthetic event, the handler saw controlsVisibleRef.current === false, and called revealControls — producing an instant hide→reveal loop. Fix: strict-whitelist the eventType on the hidden-state branch. Only real directional (up/down/left/right), select, longSelect, and swipe* events count as user intent. Focus-change events are explicitly ignored. 2. Shorten the auto-hide inactivity period from 5000 ms → 3000 ms per user feedback (feels snappier during manual QA). Updated the three inline comments that cited the old value. * fix(tv): resolve 4 code-review P1 bugs in video-player auto-hide Discovered via /ce-code-review on the branch. All four break user- visible behaviour on playback transitions that manual QA on the first play cycle happened to miss. P1.1 — Stale-closure in scheduleHide broke resume-from-pause (adversarial 80, correctness+julik cross-corroborated). scheduleHide read isPaused/status/hasError from the render closure. After paused→ play, the onPress wrapper called scheduleHide synchronously before setIsPaused(false) committed, and the playingChange handler then called scheduleHideRef.current() also before the commit — both saw stale isPaused=true and bailed. Auto-hide never rearmed after any resume. Fix: mirror isPaused / status / hasError into refs (mirroring the existing controlsVisibleRef / isScreenReaderEnabledRef pattern). scheduleHide reads from refs. playingChange and statusChange handlers sync the relevant ref BEFORE calling scheduleHideRef so the guard reads the post-transition value. P1.2 — Animated.timing hide completion callback ran after state transitions (reliability rel-1 75, adversarial #4 60, julik-9 75). The callback unconditionally called setControlsVisible(false), which clobbered force-reveals triggered by error / AppState / unmount. Fix: capture the Animated.CompositeAnimation handle in hideAnimRef. Guard the completion callback with `if (finished)` — stopped animations carry finished=false. Call .stop() from revealControls, the error branch, the AppState handler, and the unmount cleanup so no stale completion can clobber a just-revealed chrome. P1.3 — 150 ms fade dead-zone dropped D-pad input (correctness 75, julik-1 75). During the fade, controls were non-focusable (set synchronously) but the catcher wasn't mounted yet (gated on !controlsVisible, which only flipped in the anim-completion). No focusable target → UIFocusEngine dropped input. Fix: gate the catcher on !controlsFocusable instead of !controlsVisible. The catcher mounts synchronously with the focusable flip, giving tvOS a valid focus target throughout the fade. P1.4 — AppState 'active' bypassed revealControls → orphaned focus (julik-5 75). The handler directly flipped state + opacity but never set revealFocusPending, so on foreground resume the catcher unmounted but play/pause had no hasTVPreferredFocus claim. Matches react- native-tvos #852. Fix: AppState handler now reads hasErrorRef and routes focus to the correct Pressable — errorFocusPending for error state (back pill), revealFocusPending for normal playback (play/pause). Also stops any in-flight hide animation so its completion doesn't clobber the force-reveal. Removed hasError from the effect's deps (reads via ref now — avoids AppState re-subscription on every hasError flip). Also includes P2.1 opportunistically: error branch of statusChange now explicitly setRevealFocusPending(false) so a same-tick reveal doesn't double-claim hasTVPreferredFocus against the back pill's errorFocusPending (adversarial #3 65 + julik-4 50). Typecheck + lint clean. * fix(tv): harden video-player listeners for late-emission + media keys Two more fixes from /ce-code-review P2 tier. P2.2 — useTVEventHandler whitelist excluded hardware media keys (julik-3 50, correctness 25). The strict whitelist that fixed the hide→reveal loop in 2fd092c (excluding focus/blur/pan synthetic events) also excluded playPause / fastForward / rewind events that some Android TV remotes and Siri remote gen-1 emit. Users pressing the physical play/pause button while chrome was hidden saw nothing happen. Fix: denylist the four synthetic focus events (focus, blur, pan, panBegin, panEnd) instead of whitelisting a closed set of known user inputs. Anything not synthetic is treated as intent. Also route media-key events in the visible branch to scheduleHideRef so they reset the timer (same D14 behaviour as Siri swipes). P2.3 — Late-emission listeners could setState on an unmounted component (reliability rel-2 75, rel-3 75). Fix #24's try/catch only catches a throwing onDismiss — it doesn't cover the "callback fires after React unmount" case. Risks surface during rapid mount/unmount (e.g. quickly backing out of a video and opening a new one) when expo-video's native emitter delivers a queued statusChange / playing Change / playToEnd AFTER subscription.remove() has run. Fix: new isMountedRef, flipped to false in the existing unmount useEffect cleanup. Early-returns added to the statusChange + playingChange listener bodies and to the playToEnd hidden-chrome setTimeout(0) callback, so late native emissions are silently ignored instead of calling setState / onDismiss on a dead tree. Typecheck + lint clean. * docs(solutions): capture TV video-overlay async-event patterns + refresh 3 related docs New learning (docs/solutions/design-patterns/): - rntvos-video-overlay-async-native-event-patterns-2026-04-23.md Four primary + two extension patterns extracted from the PR #830 code- review fix batch in apps/tv/src/components/VideoPlayer.tsx: ref-mirror + eager-sync for state-gated guards called from native callbacks; Animated.CompositeAnimation handle capture + if(finished) + .stop() on every transition; gate focus-trap catchers on synchronous focusability, not async visibility; set a one-shot hasTVPreferredFocus flag yourself on AppState foreground (react-native-tvos #852 workaround); denylist synthetic focus events in useTVEventHandler; isMountedRef for late- emission native callbacks. Cross-references added (ce-compound-refresh on 3 related best-practices docs — additions only, no rewrites): - react-native-tvos-porting-pitfalls-20260414.md: Related entry noting the new doc extends the pitfall catalog with async-event-vs-React-state issues that aren't covered by the six existing type/layout pitfalls. - playlist-video-player-sdui-mobile-20260409.md: inline "On TV, additionally" note in Section 5 (wasPlayingRef AppState guard) pointing to Pattern 4's one-shot hasTVPreferredFocus flag; Related entry for the TV companion. - tv-focus-driven-hero-patterns-20260420.md: Related entry linking Pattern 5's useTVEventHandler denylist as a complement to Section 6's onFocus-on-leaf rule. * style(docs): prettier --write for brainstorm + plan docs to satisfy CI CI's `format` job runs `prettier --check .` on the whole repo. The brainstorm + plan were written by the ce-brainstorm / ce-plan skills, which don't run prettier on *.md at write time. lint-staged only covers *.{ts,tsx} + package.json on commit, so the drift slipped past locally. Pure formatting; no content changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Updates the requirements on hashicorp/aws to permit the latest version.
Release notes
Sourced from hashicorp/aws's releases.
Changelog
Sourced from hashicorp/aws's changelog.
... (truncated)
Commits
e9b4629Merge pull request #46447 from hashicorp/td-go1.25.7070ce62Update CHANGELOG.md for #4646483f4911Merge pull request #46464 from hashicorp/prepare6.32.122ee20bMerge pull request #46442 from cluebbehusen/fix-dynamodb-gsi-key-schema-range...4c4e5e7Update CHANGELOG.md for #46455984f86eMerge pull request #46455 from hashicorp/b-cloudwatch-log-delivery-create-time35c2dbbMerge pull request #46454 from hashicorp/b-elasticache-rep-grp-token0111348Prepare for v6.32.1 release.9a12effExtract normalize to helperf4c15adAdd docs about potential issueDependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)