Skip to content

Commit bc1f30f

Browse files
authored
UI : Landscape QA fixes (#1909)
* Edit text does not cover screen, save scroll position state * Run unread reconciliation regardless of savedstate * let it scroll first before db udpate
1 parent ecd6701 commit bc1f30f

File tree

2 files changed

+56
-22
lines changed

2 files changed

+56
-22
lines changed

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

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import android.net.Uri
1515
import android.os.AsyncTask
1616
import android.os.Build
1717
import android.os.Bundle
18+
import android.os.Parcelable
1819
import android.os.Handler
1920
import android.os.Looper
2021
import android.os.SystemClock
@@ -459,6 +460,9 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
459460

460461
private var isKeyboardVisible = false
461462

463+
private var pendingRecyclerViewScrollState: Parcelable? = null
464+
private var hasRestoredRecyclerViewScrollState: Boolean = false
465+
462466
private lateinit var reactionDelegate: ConversationReactionDelegate
463467
private val reactWithAnyEmojiStartPage = -1
464468

@@ -529,6 +533,7 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
529533
// Extras
530534
private const val ADDRESS = "address"
531535
private const val SCROLL_MESSAGE_ID = "scroll_message_id"
536+
private const val CONVERSATION_SCROLL_STATE = "conversation_scroll_state"
532537

533538
const val SHOW_SEARCH = "show_search"
534539

@@ -570,6 +575,9 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
570575
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
571576
super.onCreate(savedInstanceState, isReady)
572577

578+
pendingRecyclerViewScrollState = savedInstanceState?.getParcelable(CONVERSATION_SCROLL_STATE)
579+
hasRestoredRecyclerViewScrollState = false
580+
573581
// Check if address is null before proceeding with initialization
574582
if (
575583
IntentCompat.getParcelableExtra(
@@ -924,33 +932,27 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
924932
unreadCount = data.threadUnreadCount
925933
updateUnreadCountIndicator()
926934

935+
// If we have a saved RecyclerView scroll state (after rotation), restore it and skip first-load autoscroll.
936+
if (!hasRestoredRecyclerViewScrollState && pendingRecyclerViewScrollState != null) {
937+
val lm = binding.conversationRecyclerView.layoutManager
938+
binding.conversationRecyclerView.runWhenLaidOut {
939+
lm?.onRestoreInstanceState(pendingRecyclerViewScrollState)
940+
hasRestoredRecyclerViewScrollState = true
941+
pendingRecyclerViewScrollState = null
942+
}
943+
}
944+
927945
if (messageToScrollTo != null) {
928946
if(gotoMessageById(messageToScrollTo!!.id, smoothScroll = messageToScrollTo!!.smoothScroll, highlight = firstLoad)){
929947
messageToScrollTo = null
930948
}
931949
} else {
932-
if (firstLoad) {
933-
scrollToFirstUnreadMessageOrBottom()
934-
935-
// On the first load, check if there unread messages
936-
if (unreadCount == 0 && adapter.itemCount > 0) {
937-
lifecycleScope.launch(Dispatchers.Default) {
938-
val isUnread = configFactory.withUserConfigs {
939-
it.convoInfoVolatile.getConversationUnread(
940-
viewModel.address,
941-
)
942-
}
950+
val shouldAutoScrollOnFirstLoad = firstLoad &&
951+
pendingRecyclerViewScrollState == null &&
952+
!hasRestoredRecyclerViewScrollState
943953

944-
viewModel.threadId?.let { threadId ->
945-
if (isUnread) {
946-
storage.markConversationAsRead(
947-
threadId,
948-
clock.currentTimeMillis()
949-
)
950-
}
951-
}
952-
}
953-
}
954+
if (shouldAutoScrollOnFirstLoad) {
955+
scrollToFirstUnreadMessageOrBottom()
954956
} else {
955957
// If there are new data updated, we'll try to stay scrolled at the bottom (if we were at the bottom).
956958
// scrolled to bottom has a leniency of 50dp, so if we are within the 50dp but not fully at the bottom, scroll down
@@ -960,6 +962,26 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
960962
}
961963
}
962964

965+
// We should do this check regardless of whether we're restoring a saved scroll position.
966+
if (firstLoad && unreadCount == 0 && adapter.itemCount > 0) {
967+
lifecycleScope.launch(Dispatchers.Default) {
968+
val isUnread = configFactory.withUserConfigs {
969+
it.convoInfoVolatile.getConversationUnread(
970+
viewModel.address,
971+
)
972+
}
973+
974+
viewModel.threadId?.let { threadId ->
975+
if (isUnread) {
976+
storage.markConversationAsRead(
977+
threadId,
978+
clock.currentTimeMillis()
979+
)
980+
}
981+
}
982+
}
983+
}
984+
963985
handleRecyclerViewScrolled()
964986
}
965987
}
@@ -973,6 +995,17 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
973995
}
974996
}
975997

998+
override fun onSaveInstanceState(outState: Bundle) {
999+
super.onSaveInstanceState(outState)
1000+
1001+
// Persist the current scroll position so rotations (e.g., portrait <-> landscape) don't jump to bottom.
1002+
val lm = binding.conversationRecyclerView.layoutManager
1003+
val state = lm?.onSaveInstanceState()
1004+
if (state != null) {
1005+
outState.putParcelable(CONVERSATION_SCROLL_STATE, state)
1006+
}
1007+
}
1008+
9761009
override fun onLoaderReset(cursor: Loader<ConversationLoader.Data>) = adapter.changeCursor(null)
9771010

9781011
// called from onCreate

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ class InputBar @JvmOverloads constructor(
142142

143143
// Edit text
144144
binding.inputBarEditText.setOnEditorActionListener(this)
145-
binding.inputBarEditText.imeOptions = EditorInfo.IME_ACTION_NONE
145+
// Prevent some IMEs from switching to fullscreen/extracted text mode in landscape (shows IME-owned text field).
146+
binding.inputBarEditText.imeOptions = EditorInfo.IME_ACTION_NONE or EditorInfo.IME_FLAG_NO_EXTRACT_UI
146147

147148
val incognitoFlag = if (TextSecurePreferences.isIncognitoKeyboardEnabled(context)) 16777216 else 0
148149
binding.inputBarEditText.imeOptions = binding.inputBarEditText.imeOptions or incognitoFlag // Always use incognito keyboard if setting enabled

0 commit comments

Comments
 (0)