fix(mobile): missing items and fixes in long-press message menu#879
Closed
Just-Insane wants to merge 21 commits into
Closed
fix(mobile): missing items and fixes in long-press message menu#879Just-Insane wants to merge 21 commits into
Just-Insane wants to merge 21 commits into
Conversation
Tracks Issue #9 with root cause analysis and proposed fix using visualViewport API. Implementation will follow after proper testing on iOS devices.
When the thread drawer is open alongside the main room view, two RoomInput components each mount their own useKeyboardHeight instance. On keyboard open the thread instance had savedHeight=0 (freshly mounted), so its immediate-estimate branch fell back to viewport.height — the wrong mid-animation value — and overwrote the correct estimate already written by the main room instance. This produced a third layout change (wrong height → correct height) visible as jank on every keyboard open. Fix: promote savedHeight, cssVarsSet, and the mount reference counter to module-level variables so all instances share them. - sharedSavedHeight: all instances read and write the same value, so the estimate is always correct even for newly-mounted instances. - cssVarsApplied: the 'only set once while keyboard open' guard now works across instances, preventing double setCSSVars calls. - mountCount: reference-counted so only the last instance to unmount clears the CSS variables — prevents the thread drawer unmounting while the main room keyboard is still open from wiping --sable-visible-height.
- Increase swipe thresholds (velocity 0.5→1.2, distance 100-120→150-180) in SwipeableChatWrapper, SwipeableOverlayWrapper, SwipeableMessageWrapper to reduce accidental navigation triggers - Replace double-tap context menu trigger with 500ms long-press (useMobileLongPress) that cancels on scroll or >10px movement - Add 'Copy Text' menu item (MessageCopyTextItem) to message context menus; prefers m.new_content.body for edited messages, returns null if redacted - Fix file picker on iOS Safari: append hidden input to document.body before .click() and remove after selection so the native dialog reliably appears - Add autoCorrect="on" to Slate Editable alongside autoCapitalize="sentences" for correct iOS sentence-case and autocorrect behaviour - Use height:100dvh on <html> so the layout shrinks when the on-screen keyboard opens (iOS/Android), keeping the app anchored at the top; add interactive-widget=resizes-content to viewport meta for Android Chrome - Keep EmojiBoard mounted after first open via createPortal + display:none toggling instead of unmounting through PopOut; add active prop to EmojiBoard to deactivate FocusTrap when hidden, avoiding re-initialisation of the virtualizer on every open
Two root causes for notifications stopping after a while: 1. sw.ts hasVisibleClient used OR logic (appIsVisible || matchAll visible): On iOS the SW is killed between pushes so appIsVisible resets to false on restart. With OR logic, a stale matchAll() result with visibilityState='visible' still set hasVisibleClient=true, silently suppressing every notification after the first. Fix: switch to AND logic so BOTH appIsVisible AND a visible client are required to suppress. A cold-start SW (appIsVisible=false) never suppresses, regardless of stale matchAll() data. 2. useAppVisibility.ts was passing isMobile as keepEnabledWhenVisible, meaning on desktop the pusher was deleted from the homeserver whenever the tab was visible. If the async re-enable in enablePushNotifications didn't complete before the page was torn down, the homeserver was left with no pusher — so no more push notifications until a manual background/foreground cycle. Fix: always pass true for keepEnabledWhenVisible so the pusher stays registered permanently. The SW's hasVisibleClient check handles OS-notification suppression in the foreground; the homeserver never needs to be without a pusher.
- SlidingSyncManager.onConnectionChange now calls slidingSync.resend() when the device comes back online, so the sync retries immediately instead of staying idle. - Add SlidingSyncManager.retryNow() public method that calls resend(). - useAppVisibility: on visibilitychange → visible, call mx.retryImmediately() (classic sync) and getSlidingSyncManager(mx)?.retryNow() (sliding sync) so the PWA reconnects when opened from the home screen. The SDK's SlidingSyncSdk.retryImmediately() is a no-op stub, so the visibility path was previously a dead end for sliding sync users.
…d to survive iOS network resume latency
SyncStatus initialised stateData.current as null, so when the splash was dismissed via the fast-path (cached rooms before first sync), the component would miss the null→Syncing transition if sync had already started by the time it mounted. Initialise current from mx.getSyncState() so the banner correctly shows "Connecting..." whenever the component first renders while a sync is already in progress.
When a sync gap triggers TimelineReset (e.g. mobile PWA returning from background or opening from notification), getInitialTimeline() loads new events directly into timeline state. useLiveEventArrive never fires for events that arrived via reset, so if the user was scrolled up the unread jump bar was never shown. Call setUnreadInfo explicitly in that case.
- View Reactions (when relations are available) - Pin / Unpin Message (when canPinEvent) - Set / Edit Nickname for other users (inline edit within the sheet) - Kick from Room for moderators with sufficient power level Also passes canPinEvent and relations from MessageInternal to MobileMessageMenu so the desktop and mobile menus stay in parity. Fix missing mobileOrTablet import in useAppVisibility.
- Add bookmark add/remove action to mobile long-press menu (respects enableMessageBookmarks setting, same as desktop menu) - Fix: when the nickname input opens, use visualViewport resize events to lift the bottom sheet above the virtual keyboard so the input is not covered on iOS/Android
a6444a7 to
6354bbe
Compare
Contributor
Author
|
This PR has been superseded by #874 ( |
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.
Description
The mobile long-press message menu was missing several actions available on desktop. This adds the missing items (bookmark toggle, report, etc.), fixes the bookmark toggle handler, and resolves two iOS-specific issues: the virtual keyboard covering the menu on open, and the nickname input not receiving focus correctly.
Fixes #
Type of change
Checklist:
AI disclosure:
The missing menu items and iOS fixes were drafted with AI assistance. The bookmark toggle was wired to the correct handler (the previous one was a no-op). The iOS keyboard issue is addressed by calling
blur()on any focused input before opening the bottom sheet, preventing the virtual keyboard from pushing the menu above the viewport. The nickname input focus fix schedules afocus()call in arequestAnimationFramecallback after the sheet animation completes.