Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
4e31b4e
removed portrait lock for most activities, retained for WebRtcCallAct…
jbsession Sep 1, 2025
20a5fa9
Initial landscape, compact, and flip compatibility
jbsession Sep 1, 2025
c85a724
Landing screen initial landscape compat with flip, tablet and phone
jbsession Sep 1, 2025
17446ab
Merge branch 'dev' into improvements/ses-4433
jbsession Sep 11, 2025
1f494a2
QR code activity landscape
jbsession Sep 11, 2025
ed86d27
Initial layout for Start Conversation sheet
jbsession Sep 11, 2025
29fe922
Added Adaptive layout helper
jbsession Sep 11, 2025
0e007e9
Revert "Initial landscape, compact, and flip compatibility"
jbsession Sep 11, 2025
385721d
Merge branch 'improvements/ses-4433' into landscape/qr-codes
jbsession Sep 11, 2025
ecaf47a
Use adaptive layout
jbsession Sep 11, 2025
21fcff0
made sholdUseTwoPane private
jbsession Sep 11, 2025
955dec0
removed padding for back button
jbsession Sep 12, 2025
368f97b
GiphyActivity initial compose
jbsession Sep 12, 2025
f837831
GiphyFragment compose
jbsession Sep 12, 2025
968d555
GiphyFragment initial kotlin
jbsession Sep 12, 2025
73cd000
cleanup
jbsession Sep 12, 2025
2980bea
GiphyFragment to kotlin
jbsession Sep 12, 2025
93baba2
Cleanup
jbsession Sep 12, 2025
0094130
Converted async task to coroutine
jbsession Sep 12, 2025
28fc0d3
Giphy fragment and sticket to kotlin
jbsession Sep 12, 2025
f3af5cb
Merge remote-tracking branch 'upstream/dev' into improvements/ses-4433
jbsession Sep 22, 2025
d2bb418
Merge branch 'landscape/qr-codes' into improvements/ses-4433
jbsession Sep 22, 2025
019e76f
Merge branch 'landscape/login-screen' into improvements/ses-4433
jbsession Sep 22, 2025
c51f0aa
Merge branch 'landscape/giphy' into improvements/ses-4433
jbsession Sep 22, 2025
ea6c10d
Separate compose fun
jbsession Sep 22, 2025
5e0f1e5
Start conversation cleanup
jbsession Sep 22, 2025
4734623
cleanup
jbsession Sep 22, 2025
cc679cd
Cleanup
jbsession Sep 22, 2025
06262dd
Merge branch 'dev' into improvements/ses-4433
jbsession Oct 1, 2025
821f72a
Merge branch 'dev' into improvements/ses-4433
jbsession Oct 1, 2025
3cc3ec0
notif landscape fix
jbsession Oct 2, 2025
1fc426b
Revert "notif landscape fix"
jbsession Oct 6, 2025
8db8133
Merge branch 'dev' into improvements/ses-4433
jbsession Oct 6, 2025
3305b9d
initial scaling for QR in recovery password
jbsession Oct 6, 2025
373c6ea
Updated usage of twopane into landscape check only.
jbsession Oct 6, 2025
6d43704
Share component for qrPanel
jbsession Oct 6, 2025
ead5bbc
Fixed overlap for 3 button navigation
jbsession Oct 7, 2025
35c479c
camera inset in conversation
jbsession Oct 7, 2025
5327c48
apply safe inset camera inset
jbsession Oct 7, 2025
e34617c
remove portrait mode for webrtccall
jbsession Oct 7, 2025
b3019dd
cleanup
jbsession Oct 7, 2025
e0a54d4
Media preview insets
jbsession Oct 7, 2025
7f0ed93
Use state for giph loading
jbsession Oct 7, 2025
4cfb2c6
Use state for giphyLoading
jbsession Oct 8, 2025
7919364
themed content for tabs
jbsession Oct 8, 2025
7a05fbc
Removed two pane
jbsession Oct 8, 2025
2cdbee9
GiphyActivity converted to kotlin, updated compose usage
jbsession Oct 8, 2025
925d767
Cleanup
jbsession Oct 8, 2025
f0cbcf5
A bit of optimization for session netowork's node image
jbsession Oct 8, 2025
3a7a84f
inset for settings screen
jbsession Oct 11, 2025
e53f8ec
token page and conversation settings
jbsession Oct 11, 2025
7800906
App bar search bar insets
jbsession Oct 11, 2025
75bb40c
WebRtc rotation fix, Landscape xml
jbsession Oct 13, 2025
0e33c04
contactAvatar webRtc adaptive
jbsession Oct 13, 2025
d2f5b7b
refactor adaptiveInfo name
jbsession Oct 13, 2025
a72d85a
Merge branch 'dev' into improvements/ses-4433
jbsession Oct 14, 2025
4d697ce
State list drawable landscape
jbsession Oct 14, 2025
a982661
rtc call landscape update
jbsession Oct 15, 2025
f4db0e4
Added insets and updated overlay stub
jbsession Oct 16, 2025
9e4cc10
Serializable data for bottom sheet. Fixed crashes
jbsession Oct 16, 2025
f933efa
Fixed landscape scroll for conversation bottomsheet
jbsession Oct 16, 2025
320684d
insets for cameraXfragment
jbsession Oct 16, 2025
cc3d015
Initial workaround for giphytabs
jbsession Oct 16, 2025
31a96cd
cleanup
jbsession Oct 16, 2025
715cf77
Let activity handle the orientation change
jbsession Oct 17, 2025
7862735
Fixed how web rtc looks on landscape
jbsession Oct 17, 2025
4edf2d7
allow recreation of layout for fragment. Add saveInstance check to pr…
jbsession Oct 17, 2025
f19fef4
Simplified logic
jbsession Oct 17, 2025
65659b6
Added to LocalDimensions
jbsession Oct 19, 2025
9c6d565
cleanups
jbsession Oct 19, 2025
4aaf4af
Filter thread record instead of db call
jbsession Oct 20, 2025
9dcd9b0
Cleanup
jbsession Oct 20, 2025
52627df
Removed auto scroll flag from setDeviceOrientation function
jbsession Oct 20, 2025
e3adebc
Merge branch 'dev' into pr/1527
ThomasSession Oct 20, 2025
9841c74
Search contact action bottomsheet landscape state expanded
jbsession Oct 20, 2025
8f35539
Merge branch 'improvements/ses-4433' of github.com:jbsession/session-…
jbsession Oct 20, 2025
a79df8f
convert calculation into anchor
jbsession Oct 21, 2025
96f4758
Narrow width use anchor, helper function to get anchor
jbsession Oct 21, 2025
7847eb9
Safe insets for start conversation sheet
jbsession Oct 21, 2025
908a250
Dynamic insets if sheet does not fill the width
jbsession Oct 21, 2025
20df279
Update minimum size, fixed box constraints
jbsession Oct 22, 2025
9bd0da2
cleanup
jbsession Oct 22, 2025
b1cf894
draw on image fix layout
jbsession Oct 22, 2025
fe198a7
spacing fixes for editing images
jbsession Oct 22, 2025
bfdd84b
fixed constraints for color slider
jbsession Oct 22, 2025
8c9891d
initial configuration change handling
jbsession Oct 22, 2025
b303a8c
Revert "initial configuration change handling"
jbsession Oct 23, 2025
828e812
Made some QR areas scrollable but fit area
jbsession Oct 23, 2025
d1700ad
conversationv2 landscape layout
jbsession Oct 23, 2025
b51242d
Merge branch 'dev' into improvements/ses-4433
jbsession Nov 20, 2025
99ebb43
Remove landscape hiding the rail
jbsession Nov 21, 2025
6fdd2ae
Merge branch 'dev' into improvements/ses-4433
jbsession Nov 26, 2025
b3a4802
Refactored dimen name
jbsession Nov 26, 2025
7c8fdb7
added comments
jbsession Nov 27, 2025
5c075a6
Fixed rotation value
jbsession Nov 27, 2025
570a736
Removed landscape layout, added rotation to back arrow
jbsession Nov 27, 2025
4ddaa86
Handle onConfigureChanged for WebrtcActivity
jbsession Nov 27, 2025
f65372d
Cleanups
jbsession Nov 27, 2025
a9d2bd6
Updated inset margine helper to fix home FAB
jbsession Nov 28, 2025
e3a3516
Initial orientation handling for CameraXFragment
jbsession Nov 30, 2025
74d2c56
Added CameraXActivity to replace old fragment
jbsession Dec 3, 2025
a088a9f
Merge branch 'dev' into improvements/ses-4433
ThomasSession Dec 4, 2025
6dd0b9a
Fixed insets for CameraXActivity
jbsession Dec 5, 2025
ed3f770
Added tiny helper for bottom margin insets
jbsession Dec 5, 2025
a541a01
Merge branch 'improvements/ses-4433' of github.com:jbsession/session-…
jbsession Dec 5, 2025
944797b
Merge branch 'dev' into improvements/ses-4433
jbsession Dec 10, 2025
557d1dd
Fixed missing dimen
jbsession Dec 10, 2025
c2bb1a4
SDK 36 bump
jbsession Dec 10, 2025
c480f29
Updated back handling for activity with fragment
jbsession Dec 10, 2025
b74fd2e
Updated back handling
jbsession Dec 10, 2025
b0e035a
Video camera landscape adjustment
jbsession Dec 10, 2025
d4d380f
Merge branch 'dev' into improvements/ses-4433
jbsession Dec 11, 2025
f0c084b
Updated avatar sizes for portrait and landscape
jbsession Dec 12, 2025
988127f
Navigator to survive config changes, collapsible footer inset
jbsession Dec 12, 2025
fb659b5
replaced vm with retain
jbsession Dec 12, 2025
e84d379
Used retain for navigations, updated insets for debug and pro screens
jbsession Dec 12, 2025
01eb7b1
Fixed leftoever condition
jbsession Dec 14, 2025
0f0d655
Merge branch 'dev' into improvements/ses-4433
ThomasSession Dec 16, 2025
3a2ea1b
Updated landscape screen for manage group stuff
jbsession Dec 17, 2025
165f491
ManageMembersScreen cleanup and improvements
jbsession Dec 17, 2025
57df335
More cleanups
jbsession Dec 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 18 additions & 41 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -104,41 +104,33 @@

<activity
android:name="org.thoughtcrime.securesms.onboarding.landing.LandingActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
<activity
android:name="org.thoughtcrime.securesms.onboarding.loadaccount.LoadAccountActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
<activity
android:name="org.thoughtcrime.securesms.onboarding.loading.LoadingActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
<activity
android:name="org.thoughtcrime.securesms.onboarding.pickname.PickDisplayNameActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
<activity
android:name="org.thoughtcrime.securesms.onboarding.messagenotifications.MessageNotificationsActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
<activity
android:name="org.thoughtcrime.securesms.home.HomeActivity"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
<activity
android:name="org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity"
android:exported="false"
android:label="@string/sessionMessageRequests"
android:screenOrientation="portrait" />
android:label="@string/sessionMessageRequests"/>

<activity
android:name="org.thoughtcrime.securesms.preferences.SettingsActivity"
android:screenOrientation="portrait"
android:label="@string/sessionSettings" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
Expand All @@ -147,62 +139,47 @@

<activity
android:name="org.thoughtcrime.securesms.debugmenu.DebugActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
<activity
android:name="org.thoughtcrime.securesms.home.PathActivity"
android:screenOrientation="portrait" />
android:name="org.thoughtcrime.securesms.home.PathActivity"/>
<activity
android:name="org.thoughtcrime.securesms.preferences.QRCodeActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
<activity
android:name="org.thoughtcrime.securesms.preferences.BlockedContactsActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight.FlatActionBar"
android:label="@string/conversationsBlockedContacts"
/>
<activity
android:name="org.thoughtcrime.securesms.conversation.v2.settings.ConversationSettingsActivity"
android:theme="@style/Theme.Session.DayNight.NoActionBar"
android:label="@string/sessionSettings"
android:screenOrientation="portrait" />
android:label="@string/sessionSettings" />
<activity
android:name="org.thoughtcrime.securesms.preferences.prosettings.ProSettingsActivity"
android:theme="@style/Theme.Session.DayNight.NoActionBar"
android:screenOrientation="portrait" />
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
<activity
android:name="org.thoughtcrime.securesms.recoverypassword.RecoveryPasswordActivity"
android:screenOrientation="portrait" />
android:name="org.thoughtcrime.securesms.recoverypassword.RecoveryPasswordActivity" />
<activity
android:name="org.thoughtcrime.securesms.preferences.PrivacySettingsActivity"
android:label="@string/sessionPrivacy"
android:screenOrientation="portrait" />
android:label="@string/sessionPrivacy" />
<activity
android:name="org.thoughtcrime.securesms.preferences.NotificationSettingsActivity"
android:screenOrientation="portrait" />
android:name="org.thoughtcrime.securesms.preferences.NotificationSettingsActivity" />
<activity
android:name="org.thoughtcrime.securesms.preferences.ChatSettingsActivity"
android:screenOrientation="portrait" />
android:name="org.thoughtcrime.securesms.preferences.ChatSettingsActivity" />
<activity
android:name="org.thoughtcrime.securesms.preferences.HelpSettingsActivity"
android:label="@string/sessionHelp"
android:screenOrientation="portrait" />
<activity android:name="org.thoughtcrime.securesms.preferences.appearance.AppearanceSettingsActivity"
android:screenOrientation="portrait"/>
android:label="@string/sessionHelp"/>
<activity android:name="org.thoughtcrime.securesms.preferences.appearance.AppearanceSettingsActivity" />
<activity android:name="org.thoughtcrime.securesms.groups.GroupMembersActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
<activity android:name="org.thoughtcrime.securesms.conversation.v2.settings.notification.NotificationSettingsActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
<activity
android:exported="true"
android:name="org.thoughtcrime.securesms.ShareActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:noHistory="true"
android:taskAffinity=""
android:theme="@style/Theme.TextSecure.DayNight.NoActionBar"
Expand Down Expand Up @@ -254,7 +231,6 @@

<activity
android:name="org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2"
android:screenOrientation="portrait"
android:parentActivityName="org.thoughtcrime.securesms.home.HomeActivity"
android:theme="@style/Theme.Session.DayNight.NoActionBar"
android:windowSoftInputMode="adjustResize" >
Expand All @@ -264,7 +240,6 @@
</activity>
<activity
android:name="org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight">
</activity>
<activity
Expand All @@ -281,14 +256,16 @@
android:name="org.thoughtcrime.securesms.giph.ui.GiphyActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/Theme.Session.DayNight.NoActionBar"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden" />
<activity
android:name="org.thoughtcrime.securesms.mediasend.MediaSendActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight.NoActionBar"
android:windowSoftInputMode="stateHidden" />
android:windowSoftInputMode="stateHidden"/>
<activity
android:name="org.thoughtcrime.securesms.mediasend.CameraXActivity"
android:theme="@style/Theme.Session.DayNight.NoActionBar"
android:windowSoftInputMode="stateHidden"
android:configChanges="orientation|screenSize|keyboardHidden|layoutDirection"/>
<activity
android:name="org.thoughtcrime.securesms.MediaPreviewActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
Expand Down Expand Up @@ -317,10 +294,10 @@
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
<activity android:name="org.thoughtcrime.securesms.webrtc.WebRtcCallActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:showForAllUsers="true"
android:parentActivityName="org.thoughtcrime.securesms.home.HomeActivity"
android:theme="@style/Theme.Session.DayNight.NoActionBar">
android:theme="@style/Theme.Session.DayNight.NoActionBar"
android:configChanges="orientation|screenSize|keyboardHidden|layoutDirection">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.thoughtcrime.securesms.home.HomeActivity" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,11 @@ abstract class BaseActionBarActivity : AppCompatActivity() {
}

override fun onSupportNavigateUp(): Boolean {
if (super.onSupportNavigateUp()) return true

onBackPressed()
if (handleNavigateUp()) return true
onBackPressedDispatcher.onBackPressed()
return true
}
protected open fun handleNavigateUp(): Boolean = false

private fun initializeScreenshotSecurity(isResume: Boolean) {
if (!isResume) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import android.net.Uri
import android.os.AsyncTask
import android.os.Build
import android.os.Bundle
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
Expand Down Expand Up @@ -100,6 +101,7 @@ import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.FilenameUtils.getFilenameFromUri
import org.thoughtcrime.securesms.util.SaveAttachmentTask
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Companion.showOneTimeWarningDialogOrSave
import org.thoughtcrime.securesms.util.applySafeInsetsPaddings
import java.io.IOException
import java.util.WeakHashMap
import javax.inject.Inject
Expand Down Expand Up @@ -172,8 +174,12 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),
ViewCompat.setOnApplyWindowInsetsListener(findViewById<View>(android.R.id.content)) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.ime())
windowInsetBottom = insets.bottom

binding.toolbar.updatePadding(top = insets.top)

binding.toolbar.updatePadding(
left = insets.left,
top = insets.top,
right = insets.right
)
binding.mediaPreviewAlbumRailContainer.updatePadding(bottom = insets.bottom)

updateControlsPosition()
Expand Down Expand Up @@ -258,9 +264,6 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),
}

private fun showAlbumRail() {
// never show the rail in landscape
if(isLandscape()) return

val rail = binding.mediaPreviewAlbumRailContainer
rail.animate().cancel()
rail.visibility = View.VISIBLE
Expand Down Expand Up @@ -389,13 +392,11 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),

override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// always hide the rail in landscape
if (isLandscape()) {
hideAlbumRail()

if (!isFullscreen) {
showAlbumRail()
} else {
if (!isFullscreen) {
showAlbumRail()
}
hideAlbumRail()
}

// Re-apply fullscreen if we were already in it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
Expand Down Expand Up @@ -684,6 +685,8 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
val navInsets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
val imeInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime())

val systemBarsInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())

val keyboardVisible = imeInsets.bottom > 0

if (keyboardVisible != isKeyboardVisible) {
Expand All @@ -701,6 +704,11 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
height = if (keyboardVisible) imeInsets.bottom else navInsets.bottom
}

binding.contentContainer.updatePadding(
left = systemBarsInsets.left,
right = systemBarsInsets.right
)

windowInsets
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class ConversationReactionOverlay : FrameLayout {

// Use your existing utility to handle insets
applySafeInsetsPaddings(
typeMask = WindowInsetsCompat.Type.systemBars(),
typeMask = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout(),
consumeInsets = false, // Don't consume so children can also access them
applyTop = false, // Don't apply as padding, just capture the values
applyBottom = false
Expand Down Expand Up @@ -211,7 +211,17 @@ class ConversationReactionOverlay : FrameLayout {
val contextMenu = ConversationContextMenu(dropdownAnchor, recipient?.let { getMenuActionItems(messageRecord, it) }.orEmpty())
this.contextMenu = contextMenu

var endX = if (isMessageOnLeft) scrubberHorizontalMargin.toFloat() else selectedConversationModel.bubbleX - conversationItem.width + selectedConversationModel.bubbleWidth
// Visual left/right edges that account for system insets and configured margin.
val leftEdge = (systemInsets.left + scrubberHorizontalMargin).toFloat()
val rightEdge = (width - systemInsets.right - scrubberHorizontalMargin).toFloat()

// Start the bubble aligned to the same visual edge as the scrubber.
var endX = if (isMessageOnLeft) {
leftEdge
} else {
rightEdge - conversationItem.width
}

var endY = selectedConversationModel.bubbleY - statusBarHeight
conversationItem.x = endX
conversationItem.y = endY
Expand Down Expand Up @@ -312,13 +322,23 @@ class ConversationReactionOverlay : FrameLayout {

// Adjust for system insets
reactionBarBackgroundY = maxOf(reactionBarBackgroundY, systemInsets.top.toFloat() - statusBarHeight)

// Now that endScale is final, clamp the bubble X so it stays fully within the visual edges.
val minBubbleX = leftEdge
val maxBubbleX = rightEdge
endX = endX.coerceIn(minBubbleX, maxBubbleX)
// Ensure initial position is corrected before making the overlay visible.
conversationItem.x = endX
conversationItem.y = endY

hideAnimatorSet.end()
visibility = VISIBLE

// Place the scrubber on the same visual edges (accounting for its own width on the right).
val scrubberX = if (isMessageOnLeft) {
scrubberHorizontalMargin.toFloat()
leftEdge
} else {
(width - scrubberWidth - scrubberHorizontalMargin).toFloat()
(rightEdge - scrubberWidth)
}

foregroundView.x = scrubberX
Expand All @@ -332,22 +352,37 @@ class ConversationReactionOverlay : FrameLayout {
revealAnimatorSet.start()

if (isWideLayout) {
val scrubberRight = scrubberX + scrubberWidth
val offsetX = when {
isMessageOnLeft -> scrubberRight + menuPadding
else -> scrubberX - contextMenu.getMaxWidth() - menuPadding
val menuXInOverlay = if (isMessageOnLeft) {
// Menu to the RIGHT of the scrubber
scrubberX + scrubberWidth + menuPadding
} else {
// Menu to the LEFT of the scrubber - use MENU width here, not scrubber width
scrubberX - contextMenu.getMaxWidth() - menuPadding
}
// Adjust Y position to account for insets
val adjustedY = minOf(backgroundView.y, (availableHeight - actualMenuHeight).toFloat()).toInt()
contextMenu.show(offsetX.toInt(), adjustedY)

val maxMenuYInOverlay = (height - systemInsets.bottom - actualMenuHeight).toFloat()
val menuYInOverlay = minOf(backgroundView.y, maxMenuYInOverlay)

// Convert overlay-local to anchor relative as expected by ConversationContextMenu.show()
val (xOffset, yOffset) = toAnchorOffsets(menuXInOverlay, menuYInOverlay)
contextMenu.show(xOffset, yOffset)

} else {
val contentX = if (isMessageOnLeft) scrubberHorizontalMargin.toFloat() else selectedConversationModel.bubbleX
val offsetX = when {
isMessageOnLeft -> contentX
else -> -contextMenu.getMaxWidth() + contentX + bubbleWidth
val menuXInOverlay = if (isMessageOnLeft) {
leftEdge
} else {
rightEdge - contextMenu.getMaxWidth()
}

val menuTop = endApparentTop + conversationItemSnapshot.height * endScale
contextMenu.show(offsetX.toInt(), (menuTop + menuPadding).toInt())
val menuYInOverlay = (menuTop + menuPadding)
.coerceIn(
systemInsets.top.toFloat(),
(height - systemInsets.bottom - actualMenuHeight).toFloat()
)

val (xOffset, yOffset) = toAnchorOffsets(menuXInOverlay, menuYInOverlay)
contextMenu.show(xOffset, yOffset)
}

val revealDuration = context.resources.getInteger(R.integer.reaction_scrubber_reveal_duration)
Expand All @@ -361,6 +396,12 @@ class ConversationReactionOverlay : FrameLayout {
.setDuration(revealDuration.toLong())
}

private fun toAnchorOffsets(xInOverlay: Float, yInOverlay: Float): Pair<Int, Int> {
val xOffset = (xInOverlay - dropdownAnchor.x).toInt()
val yOffset = (yInOverlay - dropdownAnchor.y).toInt()
return xOffset to yOffset
}

private fun getReactionBarOffsetForTouch(itemY: Float,
contextMenuTop: Float,
contextMenuPadding: Float,
Expand Down
Loading