Fix list-view thumbnail spacing, scroll-to-post on fullscreen close, and feed→fullscreen position sync#47
Merged
Conversation
…ewer - Remove .gif from _isVideo() in ThreadMediaViewerPage so GIFs are rendered via Image.network() (Flutter built-in animated GIF support) instead of the media_kit decoder which fails to initialize - Fix open/setPlaylistMode ordering in _ThreadMediaVideoPage, ThreadVideoPlayerPage, and SavedMediaVideoPage: call open(play:false) first, then setPlaylistMode(loop), then play() — mirrors the working pattern in FeedVideoPlayer and ensures loop mode is applied after open() clears the player's internal playlist state Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/111e3f35-b94d-4cd7-af6f-b6b54a1e1578 Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
- Bump version to 0.11.2 in pubspec.yaml - Set VisibilityDetectorController.instance.updateInterval = Duration.zero in main() so visibility callbacks fire every frame instead of every 500 ms (the default), eliminating the 1-2 s wait before playback starts - Tighten _scheduleVisibilityRecheck from 110 ms to 50 ms and _scheduleRecoveryCheck from 700 ms to 350 ms for snappier fallback paths Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/4224a8a7-a0a4-44cd-884e-3c74ef750a5d Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
…ion sync
- list_post.dart: center avatar/text column vertically against thumbnail
(CrossAxisAlignment.center) — eliminates the blank gap below the
user name / No. row when thumbnail is taller than the text
- thread_media_viewer_page.dart: fix scroll-to-post on dismiss
· PopScope canPop→false + onPopInvokedWithResult always calls
_closeViewer(), so iOS swipe-back and Android back button both
return the current post id to the thread list
· Add startPosition param to ThreadMediaViewerPage and
_ThreadMediaVideoPage; seek after open for the initial page
- thread_video_player_page.dart: add startPosition param and seek
after open (used by the FeedVideoPlayer fullscreen-expand button)
- feed_video_player.dart: expose positionNotifier (ValueNotifier<Duration>)
so callers can track current playback position; pass _position to
ThreadVideoPlayerPage when fullscreen button is tapped
- thread_page_post.dart: create _feedVideoPosition ValueNotifier,
pass it to FeedVideoPlayer, and supply its value as startPosition
when opening ThreadMediaViewerPage
Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/f577b24b-4054-46fa-9a1c-63ce31b54a77
Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
Copilot created this pull request from a session on behalf of
wrngwrld
April 27, 2026 09:29
View session
- ios/Runner.xcodeproj/project.pbxproj: bump MARKETING_VERSION 0.11.1
→ 0.11.2 and CURRENT_PROJECT_VERSION 63 → 64 to match pubspec.yaml
- lib/main.dart: change VisibilityDetectorController.instance.updateInterval
from Duration.zero → const Duration(milliseconds:100). Duration.zero fires
the visibility callback on every frame; with multiple video widgets in a
thread that caused excessive native-player lifecycle work on iOS, leading
to crashes under scroll pressure.
- lib/widgets/feed_video_player.dart:
· Reduce iOS deferred-disposal timer from 8 s → 3 s and hard cap from
18 → 5 entries. Fewer concurrently alive native players = less memory
pressure and fewer file-descriptor leaks.
· Add throttled setState in _positionSub: once _hasFirstFrame is true,
call setState() at most every 250 ms. Previously _position was updated
without setState so LinearProgressIndicator only refreshed when an
unrelated state change occurred, making it appear frozen or laggy.
· Reset _lastPositionUiUpdate in _resetForNewSource() and dispose() so
stale timestamps don't suppress the first progress-bar update.
Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/cae14e4b-8739-445a-894a-c1e83c3befb8
Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
…ayer pool - New lib/services/feed_player_pool.dart: global fixed-size pool (2 slots iOS, 3 Android) so at most N+1 native Player instances ever exist app-wide - Rewrite FeedVideoPlayer to acquire/release pool slots instead of creating/disposing Players on scroll; no more deferred-dispose timer chain - Fix _applyAudioMode: remove AudioTrack.no() calls (root cause of ~1s stutter per media-kit #964); only apply AudioTrack.auto() on unmute; mute purely via setVolume(0) - Remove the 90ms Future.delayed workaround in _playIfNeeded (it was itself triggering the stutter) - Move PlaylistMode.loop setup to pool initialisation (before open()), persists across open() calls - Add _acquiredPlayerKey guard to correctly release pool slots even when widget.playerKey changes via didUpdateWidget - Dispose pool on app shutdown in AppWithTheme.dispose() Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/af374ccc-d8cc-4433-add8-328dbba28f7a Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/af374ccc-d8cc-4433-add8-328dbba28f7a Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
…pauseAll() before fullscreen open - Increase pool size from 2→3 on iOS and 3→4 on Android so 3-4 simultaneously visible feed videos can all acquire a slot - Replace MaterialPageRoute with CupertinoPageRoute when opening the fullscreen player so the iOS edge-swipe back gesture works - Call FeedPlayerPool.instance.pauseAll() both in the fullscreen button onPressed (synchronous, instant) and in ThreadVideoPlayerPage.initState() so pool players release the AVAudioSession before the new player opens, eliminating the ~1s stutter on first playback Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/51811454-7c70-4d90-a661-3f588d58be86 Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
…xt.mounted Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/51811454-7c70-4d90-a661-3f588d58be86 Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
…tall device_info_plus 12.4.0 calls [[NSProcessInfo processInfo] isiOSAppOnVision] which only exists in the visionOS-capable iOS SDK headers (Xcode 15.3+). On a standard macos-latest CI runner the compile fails with: "No visible @interface for 'NSProcessInfo' declares the selector 'isiOSAppOnVision'" Add a post_install Ruby block that finds FPPDeviceInfoPlusPlugin.m in the Pods sandbox and comments out all lines referencing the missing selector, allowing the build to succeed without requiring visionOS SDK headers. Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/9910df16-07c6-4fa0-a38c-b1cea5f181ce Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
device_info_plus 12.4.0 requires Xcode 26.1.1+ and Flutter 3.38.1+, neither of which are available on the CI runner (Flutter 3.35.6, macos-latest). 12.4.0 introduced the isiOSAppOnVision NSProcessInfo call that fails to compile without the visionOS SDK headers. Pin to >=12.1.0 <12.4.0 so pub resolves to 12.3.0 which works with the current CI stack. Remove the Podfile post_install hack that was patching FPPDeviceInfoPlusPlugin.m, since the root cause is now addressed properly. Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/29a8df7b-571c-425b-a700-ff33dc247b44 Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
…equirements - Revert device_info_plus back to ^12.1.0 (no longer need the version cap) - CI: bump flutter-version from 3.35.6 to 3.38.1 in both jobs - CI: add maxim-lobanov/setup-xcode@v1 step (xcode-version: 26.1) to iOS job - android/settings.gradle: AGP 8.9.1 -> 8.12.1, Kotlin 2.1.0 -> 2.2.0 Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/1bd3ed11-d772-4248-88fe-59dcb00a8823 Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
Previously _open() was always called in initState (even for inactive adjacent pages pre-built by PageView during the scroll animation). didUpdateWidget then called _player.play() immediately on activation, but if _player.open(play:false) was still in flight that play() was a no-op; open() then completed leaving the player paused, causing a visible pause before the trailing `if (isActive) play()` in _open() fired. Fix mirrors _ThreadMediaVideoPage._openAndPlay(): - Only call _open() in initState when the page is initially active - Call _open() (not _player.play()) in didUpdateWidget on activation, so play() is always sequenced after open() in the same async chain - Add generation counter so a superseded async open never starts playback after a newer one has taken over Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/d0de1a29-a048-436a-a06f-889054725dc9 Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
- PopScope(canPop: false) → canPop: true so iOS swipe-back gesture works. Explicit back button still calls _closeViewer() returning the post ID for thread scroll; swipe-back returns null result which is safely handled by the existing onDismiss(null) early-return in thread_page. - Remove tap-to-toggle (_showControls / _controlsHideTimer / _startControlsAutoHide) from _ThreadMediaVideoPage. Controls are now always visible, matching the SavedMediaVideoPage overlay. This also eliminates the bug where clicking play/pause or the slider would simultaneously toggle controls off via the outer GestureDetector. - Remove the outer GestureDetector(onTap) wrapper from the build method; the scrub GestureDetector (Positioned.fill left:24) is unchanged. Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/fbf85620-3359-4abb-9637-a674e1539e59 Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
…o they receive touches Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/809758e6-e39d-4743-9b4f-bc30d0533337 Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
… to prevent ~1s iOS pause (media-kit #964) Agent-Logs-Url: https://github.com/NekoSurf/NekoSurf/sessions/36330f43-4793-4b09-a2c2-f1bf420371b9 Co-authored-by: wrngwrld <48834041+wrngwrld@users.noreply.github.com>
wrngwrld
marked this pull request as ready for review
April 27, 2026 14:08
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.
Uh oh!
There was an error while loading. Please reload this page.