Squash-merge commit. Covers four areas: native video player, chat reliability, multi-tab, and hardening.
## Native video player
- Direct HLS playback via `better_native_video_player` (forked from `plug-and-pay/flutter-native-video-player`, patched on `frosty-patches` branch)
- Twitch GQL playback token fetching with platform cookie extraction (iOS Swift + Android Kotlin plugins) for authenticated streams
- Quality selection (source, 720p, 480p, 360p, 160p, audio-only) persisted per channel
- Picture-in-picture: iOS automatic inline PiP, Android auto-PiP on API 31+ guarded against older devices
- Latency polling, chat latency sync, stall detection/recovery, startup auto-pause recovery, watchdog timers
- **Twitch stitched-ad break detection** (HLS `EXT-X-DATERANGE`) on both platforms, emitting `adBreakChanged` so the host suspends latency/stall recovery and chat sync during ads (program-date-time is unreliable then). Matches `CLASS="twitch-stitched-ad"` / `ID="stitched-ad-"` **and** the `X-TV-TWITCH-AD-*` attribute prefix (the durable signal streamlink/yt-dlp use)
- Shared `VideoPlayerInterface` so WebView and native paths are interchangeable via settings toggle
- `PlaybackAccessToken` model, `TwitchGqlApi` client
## Chat delay & send reliability
- **Optimistic send-finalize**: Twitch acks a sent message with a per-PRIVMSG USERSTATE (not an echo), which it can intermittently drop — more so under a long chat delay. A missing ack no longer shows a false "message may not have been sent" error; the send is finalized optimistically (local echo rendered), and only genuine rejection NOTICEs surface an error. Ack timeout scaled by the chat delay.
- **Per-line chat-delay bypass**: control/state lines (USERSTATE/ROOMSTATE/GLOBALUSERSTATE), rejection NOTICEs, the reconnect notice, and untagged server lines bypass the delay so send-acks and PONGs aren't stalled; only displayable chat content is delayed, staying in sync with delayed video.
- **Measured chat bottom-bar height**: the message list reflows to the composer's real measured height, fixing the input overlapping messages when a long message expands it (replaces a fixed-constant estimate).
- IRC tag parsing handles valueless and escaped tags per the IRCv3 message-tags spec (fixes a recent-messages RangeError on certain tags).
## Chat / multi-tab
- Redesigned tab chips: unread dot indicator, chips dim until WebSocket connects
- Animated tab options popover replacing `MenuAnchor` (no animation hook in Flutter 3.44)
- Simplified `ChatTabs` from `StatefulWidget` to `StatelessWidget`
- Focus-current-channel fade bump to 0.55; section-header alpha lifted to match the muted-label tier
- `addTab` now calls `setActiveTab` to snapshot outgoing tab's `lastSeenMessageId` — fixes spurious unread dots after adding a tab
- `onActivateSourceTab` threaded into `ChatUserModal` so Reply in merged mode switches to the correct source tab's composer
## Bug fixes and hardening
- **Reverted the experimental iOS low-latency mode** (5s live-edge join + 1.05x catch-up): AVPlayer can't sustain <~18s on Twitch (declared `TARGETDURATION:6` paces playlist refreshes), and the offset starved the buffer into pause-on-launch. Default join distance restored.
- Fork (Android): **cap `BEHIND_LIVE_WINDOW` recovery** so a stream repeatedly falling off the live window can't silently re-prepare forever; emits `error` on exhaustion so the host recovery ladder takes over
- Guard all Android `setAutoPipMode` calls with `_autoPipAvailable` — prevents `PlatformException` on Android 8–11; check `_disposed` after `isAutoPipAvailable` await to prevent post-dispose auto-PiP re-enable
- Remove `_isInPipMode` guard from `_onPaused` so `_paused` tracks actual state, fixing PiP play/pause toggle getting stuck
- Tighten iOS cookie domain check to exact `twitch.tv` / `.twitch.tv` suffix
- Invalidate the stored web session token when Twitch rejects it with a 401 (profile card flips back to unlinked; future loads skip the doomed authenticated request), and re-extract the cookie on launch when logged in without a linked session
- Send `play_session_id` and `player_backend=mediaplayer` to Usher, matching the web client / streamlink
- Fork (iOS): restore program-date-time latency measurement (a prior rev measured distance to the manifest edge, reading ~0s and silently disabling high-latency recovery / chat-delay auto-sync); release platform views on dispose (per-stream view + AVPlayerViewController leak), track the observed AVPlayerItem for KVO removal (sibling-view crash), main-thread seek results, resolve superseded load futures
- Fork (Android): clean up method handlers orphaned by PiP-time view disposal (leaked audio-focus listeners), drop the live-offset re-anchoring seekTo on metadata updates (latency creep), restore pre-duck volume, respect user pause in the stall watchdog, resolve superseded load futures
- Deep review pass: expire the quality-switch flag so stall recovery isn't disabled for the session, cap latency-driven recovery (clock-skew loop), generation-guard the error overlay, two-strike offline confirmation, controller null-safety on quality switch
- Tighten `/me` local-echo match (no longer renders `/meow ...` as an action); clear pending send text on disconnect
## Web / docs
- Remove stale Cloudflare Images binding from `wrangler.jsonc` (covered by `images.unoptimized: true`)
- Correct `web/AGENTS.md` Cache Components claim (feature not enabled)
- Repo and agent config cleanup
## Test plan
- [x] `flutter analyze` — clean (frosty + plugin lib)
- [x] `flutter test` — 319/319 pass (adds `ChatLatencySync`, `StreamInfoPoller`, video timing invariants, `PlaybackAccessToken`, IRC tag parsing)
- [x] Android plugin Kotlin compiles against the bumped fork rev
- [ ] Native player plays live streams on iOS and Android
- [ ] Quality switching works and persists across channel reopens
- [ ] PiP enters/exits correctly; pause/resume toggle in PiP window works
- [ ] Audio-only mode does not crash on Android < API 31
- [ ] Sending under a long synced chat delay no longer shows a false "may not have been sent" error
- [ ] Long composer text reflows the message list (no input/message overlap)
- [ ] Multi-tab: adding a tab does not mark previous tab as unread
- [ ] Merged chat: Reply from user modal targets the correct tab's composer
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Fix cold-start privacy bug: apply persisted collection preference on launch
- Disable Firebase collection in debug builds to avoid polluting prod data
- Add Crashlytics custom keys (is_logged_in, channel), user identifier, and
WebSocket reconnection breadcrumbs for actionable crash reports
- Record non-fatal errors for server failures, WebSocket errors, and global
asset fetch failures (skip timeouts/network errors to avoid noise)
- Update is_logged_in key and user identifier on login/logout transitions
- Log auth reconnection exhaustion before forced logout
- Add FirebaseAnalyticsObserver with named routes for automatic screen tracking
- Add static routeName constants to avoid duplicated string literals
- Add Firebase Performance Dio interceptor for automatic HTTP request tracing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
adds a user-controlled toggle (default on) under video settings that
controls whether wakelock is enabled during channel sessions. previously
wakelock was unconditional with no way to turn it off.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* migrate to dio
* ignore folders
* simplify twitch api headers handling
* clean up main
* simplify logs
* optimize profile picture fetching
fixes refetches on tab switch
* update claude md
* refactor irc.dart
* update copilot instructions with essential commands and project structure details
* implement message sending state management and UI updates
* refactor notification handling and add copy-paste functionality in chat
* refactor AlertMessage to support vertical layout and optional padding
* refactor error messages for consistency and clarity across various components
* refactor chat layout to use draggable divider and improve chat width settings
* refactor Uptime widget to use SharedTimerService for synchronized updates
* refactor search results components to handle null future states gracefully
* refactor loading indicators to use skeleton loaders for improved user experience
* refactor UI components for improved layout and responsiveness, enhance skeleton loaders, and streamline padding adjustments
* refactor: replace manual blur effects with BlurredContainer for consistency and reusability
* refactor: enhance JavaScript execution and error handling in WebView components
* refactor: replace app bar with blurred container for improved UI consistency across screens
* refactor: streamline video chat layout and enhance PiP drag gesture functionality
* revert some app bar changes
* refactor: implement Picture-in-Picture drag functionality in VideoChat
* refactor: pass currentChannelId to IRCMessage and ChatMessage for improved context
* fix large thubmnail width
* chore: update Gradle and Kotlin plugin versions for improved compatibility
* changes from v4.10.0 branch
* feat: integrate AnimatedScrollBorder for improved UI responsiveness across various screens
* refactor: update SectionHeader styling and improve theme management
* feat: add pinned section to StreamsList and enhance skeleton loader padding
* feat: add repository guidelines for project structure, coding style, testing, and security
* feat: enhance StreamCard UI with BlurredContainer and adjust border width in theme
* feat: implement unfocusInput and safeRequestFocus methods to manage text field focus behavior
* feat: enhance Picture-in-Picture drag interactions with haptic feedback and smooth animations
* refactor: improve code formatting and readability across multiple files
* feat: implement picture-in-picture mode toggle and state management for video playback
* feat: reset PiP mode state when pausing video playback
* feat: add custom app bar with profile picture and stream info for video chat
* feat: convert multiple settings screens to use StatefulWidget and add animated scroll borders
* feat: update blur configuration for adaptive alpha based on theme
* fix: adjust default font size in SectionHeader widget
* feat: enhance PiP mode with drag overlay instruction and UI improvements
* fix: improve badge rendering with consistent margin and border for current channel
* refactor: replace BackdropFilter with BlurredContainer for improved clarity and maintainability
* fix: reduce background transparency in Uptime widget for better visibility
* feat: enhance photo view dialog with full resolution toggle and blurred background
* fix: reset chat delay to 0 when auto sync is enabled and update settings title for clarity
* fix: adjust border width in theme to improve consistency
* feat: add forceDarkMode option to BlurredContainer for improved theme adaptability
* feat: implement offline followed channels feature with UI integration and settings option
* fix: increase font size and weight for offline status text for better readability
* feat: remove offline pinned channels feature and update related UI components
* feat: optimize offline channels loading behavior based on expansion state
* fix: improve clarity and consistency in repository guidelines formatting
* feat: update full resolution URL handling and button visibility logic
* feat: replace app bar with blurred version in chat-only mode and add animated scroll border
* feat: refactor video chat layout for improved chat and video display in landscape mode
* feat: remove bottom bar visibility setting and adjust chat layout accordingly
* fix: simplify condition for displaying offline channels section in following tab
* feat: enhance reply thread display with indentation and reply icon
* feat: implement showModalBottomSheetWithProperFocus for improved focus handling
* feat: add gradient direction support to BlurredContainer for enhanced visual effects
* feat: enhance NavigationBar and Theme settings for improved visual consistency
* feat: add gradient direction support to BlurredContainer in VideoChat for enhanced visual effects
* chore: update .gitignore to include .cursor file for better environment management
* fix: update PiP drag gesture conditions to include video paused state for better user experience
* refactor: replace ScrollController with SettingsPageLayout in settings screens for improved layout management
* refactor: centralize orientation handling by introducing OrientationUtils for improved readability and maintainability
* refactor: replace OrientationUtils with ContextExtensions for streamlined context-based access to theme, layout, and API dependencies
* refactor: improve video chat UI by adjusting title layout and adding stream info tooltips for better user experience
* refactor: adjust titleSpacing in theme and navigation components for improved layout consistency
* refactor: update stream info timer handling and overlay management for improved UI responsiveness
* refactor: enhance stream info timer logic and overlay visibility management for chat-only mode
* refactor: enhance input decoration theme in FrostyThemes for improved visual consistency and responsiveness
* refactor: adjust inputDecorationTheme padding in FrostyThemes for improved visual consistency
* refactor: enhance video overlay management by including video preview overlay in hideElements for improved UI consistency
* refactor: improve chat bottom bar padding and video chat layout for enhanced UI consistency
* refactor: adjust chat padding to account for device bottom insets for improved layout consistency
* refactor: update text styles in FrostyThemes for improved visual consistency across UI components
* refactor: update iOS minimum deployment target to 13.0 for improved compatibility
* refactor: adjust chat bottom padding based on emote menu visibility for improved layout consistency
* refactor: adjust padding values in StreamsList for improved layout consistency
* refactor: replace Padding with AnimatedPadding in Chat for smoother layout transitions
refactor: replace Container with AnimatedContainer in BlurredContainer for smoother animations
* refactor: remove unnecessary radius property from ProfilePicture in OfflineChannelCard for cleaner code
* refactor: enhance chat bottom bar suffix icon to display message delay with tooltip for improved user experience
* refactor: update hint text and tooltips in chat bottom bar and search for improved clarity
* refactor: simplify notification display logic and enhance chat input behavior for improved user experience
* refactor: enhance layout consistency by adjusting spacing in various components across the channel and home screens
* refactor: introduce LiveIndicator widget and adjust spacing in channel and video components for improved layout consistency
* refactor: remove monospace font family from chat bottom bar for improved text rendering
* refactor: reduce notification animation duration and change dismiss direction for improved user experience
* refactor: replace VideoBar with StreamInfoBar in video components for improved layout and consistency
* refactor: adjust font sizes and spacing in StreamInfoBar for improved layout consistency
* refactor: standardize font sizes and update gradient stops in video components for improved visual consistency
* refactor: update tooltip padding and background color in theme for improved visual consistency
* refactor: enhance tooltip behavior and standardize font sizes in StreamInfoBar and related components for improved visual consistency
* refactor: add showThumbnail option to LargeStreamCardSkeletonLoader for improved layout flexibility
* refactor: add StreamInfoBarSkeletonLoader for improved layout consistency in stream components
* refactor: add shadow effects to icons and text in StreamInfoBar and VideoOverlay for improved visual depth
* refactor: update defaultOverlayOpacity to 0.0 for improved overlay behavior
* fix: correct stream info text color on overlay
* refactor: implement a new color picker dialog with random color generation for enhanced user experience
* refactor: adjust gradient colors and stops in VideoOverlay for improved visual consistency
* refactor: refine gradient colors and stops in VideoOverlay for enhanced visual clarity
* refactor: add isCompact parameter to StreamInfoBar for responsive text sizing
* fix: update tooltip background color to use surface color for better contrast
* feat: add shared chat mode support in chat store and update StreamInfoBar for visual indication
* refactor: disable debug print for IRC messages to reduce log clutter
* feat: implement chat color selection feature with user color management in chat settings
* refactor: replace color adjustment logic with new contrast-aware utility for chat names
* refactor: simplify chat details UI by replacing list tiles with action cards and removing unused clear dialog
* refactor: enhance chat details UI by improving time formatting and adding label styling to action cards
* refactor: update chat color terminology to 'Username color' for clarity in UI
* refactor: enhance chat details UI by introducing active chat modes display and improving layout structure
* refactor: improve chat details layout by replacing ListTile with Padding and adding a Divider for better visual separation
* refactor: remove chat notifications positioning setting and adjust notification alignment in video chat
* refactor: streamline StreamInfoBar component by consolidating offline handling and improving layout for better readability
* refactor: enhance StreamInfoBar by adding tooltip for streamer name and improving text overflow handling
* refactor: adjust tooltip display duration in StreamInfoBar and update theme configuration
* refactor: adjust margin and padding in StreamCard for improved layout consistency
* chore: update dependencies in pubspec.yaml and pubspec.lock for Firebase and other packages
* template
* chore: update iOS platform version to 15.0 and Firebase dependencies to 12.2.0
* refactor: simplify StreamInfoBar layout by reducing nested widgets and improving text color handling
* format
* feat: enhance Channel model and StreamInfoBar to support offline channel details
* feat: add offline indicator and improve StreamInfoBar layout for better offline channel display
* fix: adjust icon color opacity in StreamInfoBar for improved visibility
* feat: enhance dismissal animation in FrostyPhotoViewDialog to track swipe direction
* docs: update copilot instructions for clarity and additional error handling details
* refactor: optimize latency tooltip layout and improve offline indicator styling in VideoOverlay
* feat: implement shared chat asset fetching and participant management in ChatAssetsStore
* refactor: replace Observer with Builder for improved widget rebuilding in VideoOverlay
* refactor: update StreamInfoBar border styling and adjust layout in VideoOverlay for improved visual consistency
* feat: add showTextShadows property to StreamInfoBar for customizable text shadow display
* refactor: adjust layout in VideoOverlay by adding padding to improve spacing and visual consistency
* refactor: enhance VideoOverlay gradients and layout for improved visual hierarchy and user experience
* refactor: reduce vertical padding in VideoOverlay for improved layout consistency
* refactor: remove overlay opacity settings from VideoSettings and SettingsStore for simplification
* refactor: improve text overlay transition in VideoChat for better user experience
* Revert "refactor: improve text overlay transition in VideoChat for better user experience"
This reverts commit fd16ff5ec3.
* refactor: wrap videoOverlay in ColoredBox for improved layout handling
* refactor: optimize animation duration and transition curves in VideoChat for smoother interactions
* refactor: dispose searchScrollController in HomeStoreBase to prevent memory leaks
* refactor: simplify gradient definitions in VideoOverlay for improved readability and maintainability
* refactor: remove 'Offline' text overlay from VideoOverlay for cleaner UI
* refactor: add refresh functionality for assets in ChatDetails with loading indicators
* refactor: update visibility conditions for uptime, viewer count, and category display in StreamInfoBar
* refactor: replace AlertDialog with FrostyDialog for consistent dialog styling across the application
* refactor: enhance layout handling in FrostyPageView to prevent overflow during height transitions
* refactor: replace ColorPickerDialog with AccentColorPickerDialog for improved color selection experience
* refactor: replace theme and accent color settings with dedicated components for improved modularity and readability
* refactor: replace ElevatedButton with TextButton for consistent button styling across dialogs
* refactor: integrate MobX Observer for reactive state management in settings widgets
* refactor: update theme and dialog components for improved styling and consistency
* refactor: enhance dialog styling with rounded corners and border in theme configuration
* refactor: improve dialog messages for unauthorized access handling
* refactor: update bodyLarge text style in theme configuration to include font weight
* refactor: standardize Divider usage and adjust theme styles for improved consistency
* refactor: adjust Divider properties and theme styles for enhanced visual consistency
* chore: remove GEMINI.md file as it is no longer needed for project documentation
* refactor: enhance token validation and reconnect logic in AuthBase for improved error handling
* format
* refactor: integrate landscape cutout settings into VideoChat layout for improved responsiveness
* refactor: implement app lifecycle handling in VideoChat and enhance stream info update logic in VideoStore
* refactor: update landscape cutout conditionals in VideoChat layout for improved responsiveness
* update AGENTS.md
* add scrollbar to search
* fix scrolling exception
* update CLAUDE.md
* 5 auth reconnect attemps then log out
* increase reply max lines to 2
* simplify and improve reply formatting
* add prime icon
* better draggable divider
* support draggable divider in fullscreen overlay chat
* add text shadow in fullscreen chat overlay mode
* format
* add landscape checks
* video store optimization attempts
* Dispose WebViewController and remove JavaScript channels properly
* Track and cleanup all MutationObservers to prevent accumulation
* Throttle latency updates to once per 5 seconds (reduces CPU load)
* Add timeout protection and null checks for robustness
* Prevent duplicate event listeners on page reloads
* double tap divider to reset
* Revert "video store optimization attempts"
This reverts commit b1df7b0de4.
* optimize video store attempt 2
* Revert "double tap divider to reset"
This reverts commit aeb26a4335.
* optimize latency listener to open the menu and check every 20 secconds
* more optimizations
* hard refresh
* abbreviate latency
* fix lint
* improve hide default overlay
* fix chat no longer reconnecting with chat delay
* refine chat alerts
* fix historical message missing badges and emotes on initial connection
* parallelize
* revert
* add reconnect button inline action
* refactor: replace Scrollbar with FrostyScrollbar across chat and settings screens for consistent styling
* tweak chat details menu
* add scrollbar to release notes, renames for consistency
* fix duplicate message case
* fix chat delay alerts in auto sync mode
* add regex for numeric strings and enhance display name formatting logic
* exterminate borders
* refactor: simplify active chat modes display in chat details screen
* feat: enhance chat input button with delay notification and disable state
* fix: wrap chat in SafeArea to prevent UI overflow issues
* refactor: remove divider line from video chat and update draggable divider visibility logic
* persist overlay in pip mode
* fix: update chat delay handling and notifications in chat bottom bar
* fix: update chat overlay visibility logic to respect fullscreen settings
* tap to show deleted message
* fix: prevent accidental chat scrolling when accessing system UI in landscape mode
* show latency in portrait
* fix: enhance chat delay notifications with dynamic delay time
* docs: update CLAUDE.md for improved environment variable instructions and architecture overview
* fix: improve chat delay countdown management and message handling
* add preliminary release notes
* remove agents.md
* update lockfile
* add initial multi chat feature
* add option to persist multi chat tabs
* add remove confirmation dialog
* improve add chat design
* lazy-load tabs
* create global assets store to dedupe global asset fetching
* improve tab design/styles
* update notes
* use frosty dialog
* update claude md
* tweak
* add ability to reorder tabs
* resolve conflict
* merge cleanup
* format
* update release notes
* add chat delay sync completion tracking to prevent countdown re-appearance
* add tests
* fix
* update release notes
* bump
* Added ability to mute keywords from chat
* Muted words logic in widget, added Json Converter
Created a json converter to to serialize the observable list of muted keywords, this required a static method for the default value. Also moved the logic for the muted keyword widget to the widget itself
* Removed JSON Converter and ObservableList
* remove unused imports
---------
Co-authored-by: Tommy Chow <tommyxchow@gmail.com>
* add pinned channels list global config setting
* add ability to pin streams
* ensure that all pinned streams are fetched
* rename
* tweak padding
* fix typo
* Use adaptive refresh indicators
* Add new message count indicator in chat
* Sync pubspec.lock
* Initial migration to material 3
* Restore default bottom sheet style
* Remove FrostyListTile and reset styles
* Use "Clear" button for all search history
* Add `require_trailing_commas` lint rule
* Exclude generated files from linter
* Use ListView for safe area support in bottom sheet
* Add initial dark theme
* Make sizing and units consistent
* Update onbaording spacings & copy
* Migrate to default material 3 buttons
* Add headers to chat details bottom sheet
* Simplify token log in method
* Use bottom sheet for account options
* Remove `AnimateScale` widget
* Tweak search paddings
* Update message spacing divisions
* Upgrade packages
* Update message spacing divisions
* Regenerate splash screens
* Update Inter & add google fonts
* Add initial material 3 themes
* Use adaptive alert dialogs
* Revert to oultined inputs
* Fix tooltip message
* Revert add google_fonts
* Improve themes and various styling
* Convert categories grid to list
* Tweak stream card thumbnail radii
* Tweak settings headers
* Left align floating snackbars
* Tweak search header padding
* Fix profile pics occasionally not rounded
* Use profile pic for settings button if logged in
* Redesign sleep timer
* Use divider theme and reduce thickness
* Use 0 letter spacing for tab bar titles
* Redesign category streams list
* Add border to tooltips
* Increase category card font weight
* Use outlined icon btton for chat user modal
* Reduce profile pic radius in search results
* Fix scrolll to top button safe area
* Add support for reply threads
* Reduce tooltip and snackbar border thickness
* Rebuild reply threads on new messages
* Upgrade packages (iOS)
* Reduce font weight for all chat alerts
* Use tabbars for pageview
* Add dividers everywhere
* Revert "Add dividers everywhere"
This reverts commit 5f0d349fdb.
* Remove fill from inputs
* Add dividers to settings
* Use segmented button for settings list
* Add scrollbar to lists with scrollcontroller
* Redesign badge/emote tooltip
* Remove outline from chat user modal buttons
* Remove divider from reply thread
* Use tap for chatters list and increase font weight
* Constrain emote tooltip width
* Improve PiP behavior (Android)
Added the ability to enter PiP mode when leaving the app on Android.
* Add automatic PiP option
* Redesign video overlay
* Update stream card uptime counter
* Use gradient for overlay opacity
* Restore play button when paused on iOS
* Restore refresh button on overlay
* Prefer above for category tooltip
* Increase default overlay opacity to 80%
* Improve pip behavior
* Fix uptime setState after dispose
* Remove automatic pip option
Redundant since you can disable it in system settings
* Check if `setAutoEnterEnabled` is available
* Fix missing pip auto enter
* Disable auto pip when leaving channel
* Fix pip exception on iOS