Skip to content

Commit 590cae7

Browse files
SES-4433 : Handle landscape mode (#1527)
* removed portrait lock for most activities, retained for WebRtcCallActivity * Initial landscape, compact, and flip compatibility * Landing screen initial landscape compat with flip, tablet and phone * QR code activity landscape * Initial layout for Start Conversation sheet * Added Adaptive layout helper * Revert "Initial landscape, compact, and flip compatibility" This reverts commit 20a5fa9. * Use adaptive layout * made sholdUseTwoPane private * removed padding for back button * GiphyActivity initial compose * GiphyFragment compose * GiphyFragment initial kotlin * cleanup * GiphyFragment to kotlin * Cleanup * Converted async task to coroutine * Giphy fragment and sticket to kotlin * Separate compose fun * Start conversation cleanup * cleanup * Cleanup * notif landscape fix * Revert "notif landscape fix" This reverts commit 3cc3ec0. * initial scaling for QR in recovery password * Updated usage of twopane into landscape check only. * Share component for qrPanel * Fixed overlap for 3 button navigation * camera inset in conversation * apply safe inset camera inset * remove portrait mode for webrtccall * cleanup * Media preview insets * Use state for giph loading * Use state for giphyLoading * themed content for tabs * Removed two pane * GiphyActivity converted to kotlin, updated compose usage * Cleanup * A bit of optimization for session netowork's node image * inset for settings screen * token page and conversation settings * App bar search bar insets * WebRtc rotation fix, Landscape xml * contactAvatar webRtc adaptive * refactor adaptiveInfo name * State list drawable landscape * rtc call landscape update * Added insets and updated overlay stub * Serializable data for bottom sheet. Fixed crashes * Fixed landscape scroll for conversation bottomsheet * insets for cameraXfragment * Initial workaround for giphytabs * cleanup * Let activity handle the orientation change * Fixed how web rtc looks on landscape * allow recreation of layout for fragment. Add saveInstance check to prevent duplicate framgnet * Simplified logic * Added to LocalDimensions * cleanups * Filter thread record instead of db call * Cleanup * Removed auto scroll flag from setDeviceOrientation function * Search contact action bottomsheet landscape state expanded * convert calculation into anchor * Narrow width use anchor, helper function to get anchor * Safe insets for start conversation sheet * Dynamic insets if sheet does not fill the width * Update minimum size, fixed box constraints * cleanup * draw on image fix layout * spacing fixes for editing images * fixed constraints for color slider * initial configuration change handling * Revert "initial configuration change handling" This reverts commit 8c9891d. * Made some QR areas scrollable but fit area * conversationv2 landscape layout * Remove landscape hiding the rail * Refactored dimen name * added comments * Fixed rotation value * Removed landscape layout, added rotation to back arrow * Handle onConfigureChanged for WebrtcActivity * Cleanups * Updated inset margine helper to fix home FAB * Initial orientation handling for CameraXFragment * Added CameraXActivity to replace old fragment * Fixed insets for CameraXActivity * Added tiny helper for bottom margin insets * Fixed missing dimen * SDK 36 bump * Updated back handling for activity with fragment * Updated back handling * Video camera landscape adjustment * Updated avatar sizes for portrait and landscape * Navigator to survive config changes, collapsible footer inset * replaced vm with retain * Used retain for navigations, updated insets for debug and pro screens * Fixed leftoever condition * Updated landscape screen for manage group stuff * ManageMembersScreen cleanup and improvements * More cleanups * Updated some remembers to retain * Minor cleanup --------- Co-authored-by: ThomasSession <thomas.r@getsession.org>
1 parent 4552e98 commit 590cae7

File tree

90 files changed

+4589
-2069
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+4589
-2069
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -104,41 +104,33 @@
104104

105105
<activity
106106
android:name="org.thoughtcrime.securesms.onboarding.landing.LandingActivity"
107-
android:screenOrientation="portrait"
108107
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
109108
<activity
110109
android:name="org.thoughtcrime.securesms.onboarding.loadaccount.LoadAccountActivity"
111-
android:screenOrientation="portrait"
112110
android:windowSoftInputMode="adjustResize"
113111
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
114112
<activity
115113
android:name="org.thoughtcrime.securesms.onboarding.loading.LoadingActivity"
116-
android:screenOrientation="portrait"
117114
android:windowSoftInputMode="adjustResize"
118115
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
119116
<activity
120117
android:name="org.thoughtcrime.securesms.onboarding.pickname.PickDisplayNameActivity"
121-
android:screenOrientation="portrait"
122118
android:windowSoftInputMode="adjustResize"
123119
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
124120
<activity
125121
android:name="org.thoughtcrime.securesms.onboarding.messagenotifications.MessageNotificationsActivity"
126-
android:screenOrientation="portrait"
127122
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
128123
<activity
129124
android:name="org.thoughtcrime.securesms.home.HomeActivity"
130-
android:screenOrientation="portrait"
131125
android:launchMode="singleTask"
132126
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
133127
<activity
134128
android:name="org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity"
135129
android:exported="false"
136-
android:label="@string/sessionMessageRequests"
137-
android:screenOrientation="portrait" />
130+
android:label="@string/sessionMessageRequests"/>
138131

139132
<activity
140133
android:name="org.thoughtcrime.securesms.preferences.SettingsActivity"
141-
android:screenOrientation="portrait"
142134
android:label="@string/sessionSettings" >
143135
<meta-data
144136
android:name="android.support.PARENT_ACTIVITY"
@@ -147,62 +139,47 @@
147139

148140
<activity
149141
android:name="org.thoughtcrime.securesms.debugmenu.DebugActivity"
150-
android:screenOrientation="portrait"
151142
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
152143
<activity
153-
android:name="org.thoughtcrime.securesms.home.PathActivity"
154-
android:screenOrientation="portrait" />
144+
android:name="org.thoughtcrime.securesms.home.PathActivity"/>
155145
<activity
156146
android:name="org.thoughtcrime.securesms.preferences.QRCodeActivity"
157-
android:screenOrientation="portrait"
158147
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
159148
<activity
160149
android:name="org.thoughtcrime.securesms.preferences.BlockedContactsActivity"
161-
android:screenOrientation="portrait"
162150
android:theme="@style/Theme.Session.DayNight.FlatActionBar"
163151
android:label="@string/conversationsBlockedContacts"
164152
/>
165153
<activity
166154
android:name="org.thoughtcrime.securesms.conversation.v2.settings.ConversationSettingsActivity"
167155
android:theme="@style/Theme.Session.DayNight.NoActionBar"
168-
android:label="@string/sessionSettings"
169-
android:screenOrientation="portrait" />
156+
android:label="@string/sessionSettings" />
170157
<activity
171158
android:name="org.thoughtcrime.securesms.preferences.prosettings.ProSettingsActivity"
172-
android:theme="@style/Theme.Session.DayNight.NoActionBar"
173-
android:screenOrientation="portrait" />
159+
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
174160
<activity
175-
android:name="org.thoughtcrime.securesms.recoverypassword.RecoveryPasswordActivity"
176-
android:screenOrientation="portrait" />
161+
android:name="org.thoughtcrime.securesms.recoverypassword.RecoveryPasswordActivity" />
177162
<activity
178163
android:name="org.thoughtcrime.securesms.preferences.PrivacySettingsActivity"
179-
android:label="@string/sessionPrivacy"
180-
android:screenOrientation="portrait" />
164+
android:label="@string/sessionPrivacy" />
181165
<activity
182-
android:name="org.thoughtcrime.securesms.preferences.NotificationSettingsActivity"
183-
android:screenOrientation="portrait" />
166+
android:name="org.thoughtcrime.securesms.preferences.NotificationSettingsActivity" />
184167
<activity
185-
android:name="org.thoughtcrime.securesms.preferences.ChatSettingsActivity"
186-
android:screenOrientation="portrait" />
168+
android:name="org.thoughtcrime.securesms.preferences.ChatSettingsActivity" />
187169
<activity
188170
android:name="org.thoughtcrime.securesms.preferences.HelpSettingsActivity"
189-
android:label="@string/sessionHelp"
190-
android:screenOrientation="portrait" />
191-
<activity android:name="org.thoughtcrime.securesms.preferences.appearance.AppearanceSettingsActivity"
192-
android:screenOrientation="portrait"/>
171+
android:label="@string/sessionHelp"/>
172+
<activity android:name="org.thoughtcrime.securesms.preferences.appearance.AppearanceSettingsActivity" />
193173
<activity android:name="org.thoughtcrime.securesms.groups.GroupMembersActivity"
194-
android:screenOrientation="portrait"
195174
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
196175
<activity android:name="org.thoughtcrime.securesms.conversation.v2.settings.notification.NotificationSettingsActivity"
197-
android:screenOrientation="portrait"
198176
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
199177
<activity
200178
android:exported="true"
201179
android:name="org.thoughtcrime.securesms.ShareActivity"
202180
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
203181
android:excludeFromRecents="true"
204182
android:launchMode="singleTask"
205-
android:screenOrientation="portrait"
206183
android:noHistory="true"
207184
android:taskAffinity=""
208185
android:theme="@style/Theme.TextSecure.DayNight.NoActionBar"
@@ -254,7 +231,6 @@
254231

255232
<activity
256233
android:name="org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2"
257-
android:screenOrientation="portrait"
258234
android:parentActivityName="org.thoughtcrime.securesms.home.HomeActivity"
259235
android:theme="@style/Theme.Session.DayNight.NoActionBar"
260236
android:windowSoftInputMode="adjustResize" >
@@ -264,7 +240,6 @@
264240
</activity>
265241
<activity
266242
android:name="org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity"
267-
android:screenOrientation="portrait"
268243
android:theme="@style/Theme.Session.DayNight">
269244
</activity>
270245
<activity
@@ -281,14 +256,16 @@
281256
android:name="org.thoughtcrime.securesms.giph.ui.GiphyActivity"
282257
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
283258
android:theme="@style/Theme.Session.DayNight.NoActionBar"
284-
android:screenOrientation="portrait"
285259
android:windowSoftInputMode="stateHidden" />
286260
<activity
287261
android:name="org.thoughtcrime.securesms.mediasend.MediaSendActivity"
288-
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
289-
android:screenOrientation="portrait"
290262
android:theme="@style/Theme.Session.DayNight.NoActionBar"
291-
android:windowSoftInputMode="stateHidden" />
263+
android:windowSoftInputMode="stateHidden"/>
264+
<activity
265+
android:name="org.thoughtcrime.securesms.mediasend.CameraXActivity"
266+
android:theme="@style/Theme.Session.DayNight.NoActionBar"
267+
android:windowSoftInputMode="stateHidden"
268+
android:configChanges="orientation|screenSize|keyboardHidden|layoutDirection"/>
292269
<activity
293270
android:name="org.thoughtcrime.securesms.MediaPreviewActivity"
294271
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
@@ -317,10 +294,10 @@
317294
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
318295
<activity android:name="org.thoughtcrime.securesms.webrtc.WebRtcCallActivity"
319296
android:launchMode="singleTop"
320-
android:screenOrientation="portrait"
321297
android:showForAllUsers="true"
322298
android:parentActivityName="org.thoughtcrime.securesms.home.HomeActivity"
323-
android:theme="@style/Theme.Session.DayNight.NoActionBar">
299+
android:theme="@style/Theme.Session.DayNight.NoActionBar"
300+
android:configChanges="orientation|screenSize|keyboardHidden|layoutDirection">
324301
<meta-data
325302
android:name="android.support.PARENT_ACTIVITY"
326303
android:value="org.thoughtcrime.securesms.home.HomeActivity" />

app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,11 @@ abstract class BaseActionBarActivity : AppCompatActivity() {
147147
}
148148

149149
override fun onSupportNavigateUp(): Boolean {
150-
if (super.onSupportNavigateUp()) return true
151-
152-
onBackPressed()
150+
if (handleNavigateUp()) return true
151+
onBackPressedDispatcher.onBackPressed()
153152
return true
154153
}
154+
protected open fun handleNavigateUp(): Boolean = false
155155

156156
private fun initializeScreenshotSecurity(isResume: Boolean) {
157157
if (!isResume) {

app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.kt

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import android.net.Uri
2727
import android.os.AsyncTask
2828
import android.os.Build
2929
import android.os.Bundle
30+
import android.util.AttributeSet
3031
import android.view.LayoutInflater
3132
import android.view.Menu
3233
import android.view.MenuItem
@@ -100,6 +101,7 @@ import org.thoughtcrime.securesms.util.DateUtils
100101
import org.thoughtcrime.securesms.util.FilenameUtils.getFilenameFromUri
101102
import org.thoughtcrime.securesms.util.SaveAttachmentTask
102103
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Companion.showOneTimeWarningDialogOrSave
104+
import org.thoughtcrime.securesms.util.applySafeInsetsPaddings
103105
import java.io.IOException
104106
import java.util.WeakHashMap
105107
import javax.inject.Inject
@@ -175,8 +177,12 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),
175177
ViewCompat.setOnApplyWindowInsetsListener(findViewById<View>(android.R.id.content)) { view, windowInsets ->
176178
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.ime())
177179
windowInsetBottom = insets.bottom
178-
179-
binding.toolbar.updatePadding(top = insets.top)
180+
181+
binding.toolbar.updatePadding(
182+
left = insets.left,
183+
top = insets.top,
184+
right = insets.right
185+
)
180186
binding.mediaPreviewAlbumRailContainer.updatePadding(bottom = insets.bottom)
181187

182188
updateControlsPosition()
@@ -261,9 +267,6 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),
261267
}
262268

263269
private fun showAlbumRail() {
264-
// never show the rail in landscape
265-
if(isLandscape()) return
266-
267270
val rail = binding.mediaPreviewAlbumRailContainer
268271
rail.animate().cancel()
269272
rail.visibility = View.VISIBLE
@@ -392,13 +395,11 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),
392395

393396
override fun onConfigurationChanged(newConfig: Configuration) {
394397
super.onConfigurationChanged(newConfig)
395-
// always hide the rail in landscape
396-
if (isLandscape()) {
397-
hideAlbumRail()
398+
399+
if (!isFullscreen) {
400+
showAlbumRail()
398401
} else {
399-
if (!isFullscreen) {
400-
showAlbumRail()
401-
}
402+
hideAlbumRail()
402403
}
403404

404405
// Re-apply fullscreen if we were already in it

app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import androidx.core.view.ViewCompat
4242
import androidx.core.view.WindowInsetsCompat
4343
import androidx.core.view.isVisible
4444
import androidx.core.view.updateLayoutParams
45+
import androidx.core.view.updatePadding
4546
import androidx.fragment.app.DialogFragment
4647
import androidx.lifecycle.Lifecycle
4748
import androidx.lifecycle.LiveData
@@ -714,6 +715,8 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
714715
val navInsets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
715716
val imeInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime())
716717

718+
val systemBarsInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
719+
717720
val keyboardVisible = imeInsets.bottom > 0
718721

719722
if (keyboardVisible != isKeyboardVisible) {
@@ -731,6 +734,11 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
731734
height = if (keyboardVisible) imeInsets.bottom else navInsets.bottom
732735
}
733736

737+
binding.contentContainer.updatePadding(
738+
left = systemBarsInsets.left,
739+
right = systemBarsInsets.right
740+
)
741+
734742
windowInsets
735743
}
736744
}

app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class ConversationReactionOverlay : FrameLayout {
140140

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

214-
var endX = if (isMessageOnLeft) scrubberHorizontalMargin.toFloat() else selectedConversationModel.bubbleX - conversationItem.width + selectedConversationModel.bubbleWidth
214+
// Visual left/right edges that account for system insets and configured margin.
215+
val leftEdge = (systemInsets.left + scrubberHorizontalMargin).toFloat()
216+
val rightEdge = (width - systemInsets.right - scrubberHorizontalMargin).toFloat()
217+
218+
// Start the bubble aligned to the same visual edge as the scrubber.
219+
var endX = if (isMessageOnLeft) {
220+
leftEdge
221+
} else {
222+
rightEdge - conversationItem.width
223+
}
224+
215225
var endY = selectedConversationModel.bubbleY - statusBarHeight
216226
conversationItem.x = endX
217227
conversationItem.y = endY
@@ -312,13 +322,23 @@ class ConversationReactionOverlay : FrameLayout {
312322

313323
// Adjust for system insets
314324
reactionBarBackgroundY = maxOf(reactionBarBackgroundY, systemInsets.top.toFloat() - statusBarHeight)
325+
326+
// Now that endScale is final, clamp the bubble X so it stays fully within the visual edges.
327+
val minBubbleX = leftEdge
328+
val maxBubbleX = rightEdge
329+
endX = endX.coerceIn(minBubbleX, maxBubbleX)
330+
// Ensure initial position is corrected before making the overlay visible.
331+
conversationItem.x = endX
332+
conversationItem.y = endY
333+
315334
hideAnimatorSet.end()
316335
visibility = VISIBLE
317336

337+
// Place the scrubber on the same visual edges (accounting for its own width on the right).
318338
val scrubberX = if (isMessageOnLeft) {
319-
scrubberHorizontalMargin.toFloat()
339+
leftEdge
320340
} else {
321-
(width - scrubberWidth - scrubberHorizontalMargin).toFloat()
341+
(rightEdge - scrubberWidth)
322342
}
323343

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

334354
if (isWideLayout) {
335-
val scrubberRight = scrubberX + scrubberWidth
336-
val offsetX = when {
337-
isMessageOnLeft -> scrubberRight + menuPadding
338-
else -> scrubberX - contextMenu.getMaxWidth() - menuPadding
355+
val menuXInOverlay = if (isMessageOnLeft) {
356+
// Menu to the RIGHT of the scrubber
357+
scrubberX + scrubberWidth + menuPadding
358+
} else {
359+
// Menu to the LEFT of the scrubber - use MENU width here, not scrubber width
360+
scrubberX - contextMenu.getMaxWidth() - menuPadding
339361
}
340-
// Adjust Y position to account for insets
341-
val adjustedY = minOf(backgroundView.y, (availableHeight - actualMenuHeight).toFloat()).toInt()
342-
contextMenu.show(offsetX.toInt(), adjustedY)
362+
363+
val maxMenuYInOverlay = (height - systemInsets.bottom - actualMenuHeight).toFloat()
364+
val menuYInOverlay = minOf(backgroundView.y, maxMenuYInOverlay)
365+
366+
// Convert overlay-local to anchor relative as expected by ConversationContextMenu.show()
367+
val (xOffset, yOffset) = toAnchorOffsets(menuXInOverlay, menuYInOverlay)
368+
contextMenu.show(xOffset, yOffset)
369+
343370
} else {
344-
val contentX = if (isMessageOnLeft) scrubberHorizontalMargin.toFloat() else selectedConversationModel.bubbleX
345-
val offsetX = when {
346-
isMessageOnLeft -> contentX
347-
else -> -contextMenu.getMaxWidth() + contentX + bubbleWidth
371+
val menuXInOverlay = if (isMessageOnLeft) {
372+
leftEdge
373+
} else {
374+
rightEdge - contextMenu.getMaxWidth()
348375
}
376+
349377
val menuTop = endApparentTop + conversationItemSnapshot.height * endScale
350-
contextMenu.show(offsetX.toInt(), (menuTop + menuPadding).toInt())
378+
val menuYInOverlay = (menuTop + menuPadding)
379+
.coerceIn(
380+
systemInsets.top.toFloat(),
381+
(height - systemInsets.bottom - actualMenuHeight).toFloat()
382+
)
383+
384+
val (xOffset, yOffset) = toAnchorOffsets(menuXInOverlay, menuYInOverlay)
385+
contextMenu.show(xOffset, yOffset)
351386
}
352387

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

399+
private fun toAnchorOffsets(xInOverlay: Float, yInOverlay: Float): Pair<Int, Int> {
400+
val xOffset = (xInOverlay - dropdownAnchor.x).toInt()
401+
val yOffset = (yInOverlay - dropdownAnchor.y).toInt()
402+
return xOffset to yOffset
403+
}
404+
364405
private fun getReactionBarOffsetForTouch(itemY: Float,
365406
contextMenuTop: Float,
366407
contextMenuPadding: Float,

0 commit comments

Comments
 (0)