fix: bot-review robustness fixes (TTS sync, updater, nightly, a11y) (#4659)
Cherry-picked and re-verified the applicable subset of julianshen/readest@fa1b74a0 (its "address PR #15 bot reviews" commit). The fork-only AI-annotation-tool change was dropped — readest has no 'ai' toolbar tool. Each logic fix is covered by a failing-first test. - TTS position sequence is now an app-wide monotonic counter, so a fresh TTSController (constructed per `tts-speak`) isn't dropped by consumers holding `lastSequenceSeen` from a prior session. - share.ts only swallows AbortError (user cancel); other failures — e.g. NotAllowedError when a quick action fires without a user gesture — fall back to the clipboard so the text still reaches the user. - document.isTxt tolerates MIME params (text/plain;charset=utf-8), uppercase extensions (BOOK.TXT), and a nameless Blob, so a TXT can't slip onto the non-text path and yield a null book. - updater getNightlyPlatformKey matches x86_64/aarch64 explicitly; a 32-bit or otherwise unknown arch yields no nightly instead of mis-routing to aarch64. - UpdaterWindow downloadWithProgress resolves on tauriDownload completion even when Content-Length is absent (no more hang on portable/AppImage/Android). - nightly_update.rs uses async tokio::fs::read in the async command. - nightly.yml: serialize runs via a concurrency group (no cancel) and persist-credentials:false on checkouts. - edge TTS route only emits the word-boundary header when it fits under ~8KB; oversized values get dropped by proxies, and the client falls back to []. - RSVPOverlay drops the contradictory aria-disabled on the functional rate button (it opens the pace picker). - nightly verify harness handles artifact stream errors instead of crashing. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -760,15 +760,14 @@ const RSVPOverlay: React.FC<RSVPOverlayProps> = ({
|
||||
|
||||
{/* WPM selector — while RSVP follows TTS the timer no longer paces, so it
|
||||
becomes an "Audio pace" affordance that opens a TTS rate picker
|
||||
instead (decision 6). aria-disabled (not hard-disabled) keeps it
|
||||
focusable as a hint; the lock glyph + border reads in e-ink without
|
||||
relying on opacity. */}
|
||||
instead (decision 6). It stays a real, enabled button (it opens the
|
||||
picker), so no aria-disabled; the lock glyph + border reads in e-ink
|
||||
without relying on opacity. */}
|
||||
<div className='relative shrink-0'>
|
||||
{ttsDriven ? (
|
||||
<button
|
||||
className='eink-bordered flex items-center gap-1.5 rounded-full border border-gray-500/20 bg-gray-500/10 px-3 py-1.5 text-sm transition-colors hover:bg-gray-500/20'
|
||||
onClick={() => setShowRateDropdown(!showRateDropdown)}
|
||||
aria-disabled='true'
|
||||
aria-label={_('Audio pace')}
|
||||
title={_('Speed follows audio')}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user