diff --git a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt index 17213e596..45b944d21 100644 --- a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt +++ b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt @@ -146,7 +146,7 @@ class NotificationsManager @MainThread constructor(private val context: Context) if (corePreferences.disableChat) return val id = LinphoneUtils.getChatRoomId(chatRoom) - if (id == currentlyDisplayedChatRoomId) { + if (currentlyDisplayedChatRoomId.isNotEmpty() && id == currentlyDisplayedChatRoomId) { Log.i( "$TAG Do not notify received messages for currently displayed conversation [$id]" ) @@ -188,12 +188,12 @@ class NotificationsManager @MainThread constructor(private val context: Context) if (corePreferences.disableChat) return val id = LinphoneUtils.getChatRoomId(chatRoom) - if (id == currentlyDisplayedChatRoomId) { + /*if (id == currentlyDisplayedChatRoomId) { Log.i( "$TAG Do not notify received reaction for currently displayed conversation [$id]" ) return - } + }*/ if (chatRoom.muted) { Log.i("$TAG Conversation $id has been muted") @@ -337,12 +337,16 @@ class NotificationsManager @MainThread constructor(private val context: Context) @AnyThread fun setCurrentlyDisplayedChatRoomId(id: String) { + Log.i( + "$TAG Currently displayed conversation is [$id], messages received in it won't be notified" + ) currentlyDisplayedChatRoomId = id } @AnyThread fun resetCurrentlyDisplayedChatRoomId() { currentlyDisplayedChatRoomId = "" + Log.i("$TAG Reset currently displayed conversation") } @MainThread diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt index b1c91c299..1880298b3 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt @@ -204,11 +204,13 @@ class ConversationFragment : SlidingPaneChildFragment() { } override fun goBack(): Boolean { - coreContext.notificationsManager.resetCurrentlyDisplayedChatRoomId() sharedViewModel.closeSlidingPaneEvent.value = Event(true) coreContext.notificationsManager.resetCurrentlyDisplayedChatRoomId() - // If not done, when going back to ConversationsListFragment this fragment will be created again - return findNavController().popBackStack() + + // If not done this fragment won't be paused, which will cause us issues + val action = ConversationFragmentDirections.actionConversationFragmentToEmptyFragment() + findNavController().navigate(action) + return true } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -294,6 +296,12 @@ class ConversationFragment : SlidingPaneChildFragment() { } } + viewModel.scrollToBottomEvent.observe(viewLifecycleOwner) { + it.consume { + binding.eventsList.scrollToPosition(adapter.itemCount - 1) + } + } + binding.messageBottomSheet.bottomSheetList.setHasFixedSize(true) val bottomSheetLayoutManager = LinearLayoutManager(requireContext()) binding.messageBottomSheet.bottomSheetList.layoutManager = bottomSheetLayoutManager @@ -540,6 +548,8 @@ class ConversationFragment : SlidingPaneChildFragment() { } override fun onPause() { + super.onPause() + coreContext.postOnCoreThread { bottomSheetReactionsModel?.destroy() bottomSheetDeliveryModel?.destroy() @@ -562,8 +572,6 @@ class ConversationFragment : SlidingPaneChildFragment() { val bottomSheetBehavior = BottomSheetBehavior.from(binding.messageBottomSheet.root) bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallback) currentChatMessageModelForBottomSheet = null - - super.onPause() } private fun scrollToFirstUnreadMessageOrBottom(smooth: Boolean): Boolean { diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt index e5b605762..22c203ec6 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt @@ -26,6 +26,8 @@ import androidx.lifecycle.ViewModel import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.R import org.linphone.core.Address +import org.linphone.core.ChatMessage +import org.linphone.core.ChatMessageReaction import org.linphone.core.ChatRoom import org.linphone.core.ChatRoomListenerStub import org.linphone.core.EventLog @@ -83,6 +85,10 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { MutableLiveData>() } + val scrollToBottomEvent: MutableLiveData> by lazy { + MutableLiveData>() + } + val chatRoomFoundEvent = MutableLiveData>() lateinit var chatRoom: ChatRoom @@ -132,18 +138,7 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { override fun onChatMessageSent(chatRoom: ChatRoom, eventLog: EventLog) { val message = eventLog.chatMessage Log.i("$TAG Message [$message] has been sent") - } - - @WorkerThread - override fun onIsComposingReceived( - chatRoom: ChatRoom, - remoteAddress: Address, - isComposing: Boolean - ) { - Log.i( - "$TAG Remote [${remoteAddress.asStringUriOnly()}] is ${if (isComposing) "composing" else "no longer composing"}" - ) - computeComposingLabel() + scrollToBottomEvent.postValue(Event(true)) } @WorkerThread @@ -178,6 +173,33 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { chatRoom.markAsRead() } + @WorkerThread + override fun onNewMessageReaction( + chatRoom: ChatRoom, + message: ChatMessage, + reaction: ChatMessageReaction + ) { + Log.i( + "$TAG A reaction [${reaction.body}] was received from [${reaction.fromAddress.asStringUriOnly()}]" + ) + if (message == (events.value.orEmpty().lastOrNull()?.model as? MessageModel)?.chatMessage) { + // Scrolling to bottom to ensure reaction is visible + scrollToBottomEvent.postValue(Event(true)) + } + } + + @WorkerThread + override fun onIsComposingReceived( + chatRoom: ChatRoom, + remoteAddress: Address, + isComposing: Boolean + ) { + Log.i( + "$TAG Remote [${remoteAddress.asStringUriOnly()}] is ${if (isComposing) "composing" else "no longer composing"}" + ) + computeComposingLabel() + } + @WorkerThread override fun onEphemeralEvent(chatRoom: ChatRoom, eventLog: EventLog) { Log.i("$TAG Adding new ephemeral event [${eventLog.type}]") diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactFragment.kt index 959af9de3..8125a0d3f 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactFragment.kt @@ -77,8 +77,11 @@ class ContactFragment : SlidingPaneChildFragment() { override fun goBack(): Boolean { sharedViewModel.closeSlidingPaneEvent.value = Event(true) - // If not done, when going back to ContactsFragment this fragment will be created again - return findNavController().popBackStack() + + // If not done this fragment won't be paused, which will cause us issues + val action = ContactFragmentDirections.actionContactFragmentToEmptyFragment() + findNavController().navigate(action) + return true } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/java/org/linphone/ui/main/fragment/GenericFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/GenericFragment.kt index 205d36285..73b6e5029 100644 --- a/app/src/main/java/org/linphone/ui/main/fragment/GenericFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/fragment/GenericFragment.kt @@ -44,15 +44,16 @@ abstract class GenericFragment : Fragment() { } protected fun getFragmentRealClassName(): String { - return this.javaClass.name + return "[${this.javaClass.name}]" } protected open fun goBack(): Boolean { + Log.d("$TAG ${getFragmentRealClassName()} Going back") try { Log.d("$TAG ${getFragmentRealClassName()} Calling onBackPressed on activity dispatcher") requireActivity().onBackPressedDispatcher.onBackPressed() } catch (ise: IllegalStateException) { - Log.w("$TAG ${getFragmentRealClassName()}.goBack() can't go back: $ise") + Log.w("$TAG ${getFragmentRealClassName()} Can't go back: $ise") return false } return true diff --git a/app/src/main/java/org/linphone/ui/main/fragment/SlidingPaneChildFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/SlidingPaneChildFragment.kt index 699561f66..7703f2999 100644 --- a/app/src/main/java/org/linphone/ui/main/fragment/SlidingPaneChildFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/fragment/SlidingPaneChildFragment.kt @@ -38,30 +38,20 @@ abstract class SlidingPaneChildFragment : GenericFragment() { try { if (!goBack()) { Log.d( - "$TAG ${getFragmentRealClassName()}'s goBack() method returned false, trying other things" + "$TAG ${getFragmentRealClassName()}'s goBack() method returned false, disabling back pressed callback and trying again" ) - val navController = findNavController() - if (!navController.popBackStack()) { - Log.d("$TAG ${getFragmentRealClassName()} couldn't pop") - if (!navController.navigateUp()) { - Log.d( - "$TAG ${getFragmentRealClassName()} couldn't navigate up" - ) - // Disable this callback & start a new back press event - isEnabled = false - try { - requireActivity().onBackPressedDispatcher.onBackPressed() - } catch (ise: IllegalStateException) { - Log.w( - "$TAG ${getFragmentRealClassName()}.goBack() can't go back: $ise" - ) - } - } + isEnabled = false + try { + requireActivity().onBackPressedDispatcher.onBackPressed() + } catch (ise: IllegalStateException) { + Log.w( + "$TAG ${getFragmentRealClassName()} Can't go back: $ise" + ) } } } catch (ise: IllegalStateException) { Log.e( - "$TAG ${getFragmentRealClassName()}.handleOnBackPressed() Can't go back: $ise" + "$TAG ${getFragmentRealClassName()} Can't go back: $ise" ) } } @@ -91,14 +81,16 @@ abstract class SlidingPaneChildFragment : GenericFragment() { } override fun goBack(): Boolean { - if (!super.goBack()) { - if (onBackPressedCallback.isEnabled) { - onBackPressedCallback.handleOnBackPressed() - return true + if (!findNavController().popBackStack()) { + Log.d("$TAG ${getFragmentRealClassName()} Couldn't pop back stack") + if (!findNavController().navigateUp()) { + Log.d("$TAG ${getFragmentRealClassName()} Couldn't navigate up") + onBackPressedCallback.isEnabled = false + return super.goBack() } return false } - return true + return false } private fun backPressedCallBackEnabled(slideable: Boolean): Boolean { diff --git a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt index 5af25bcfc..bd6fe7e65 100644 --- a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt @@ -63,8 +63,11 @@ class HistoryContactFragment : SlidingPaneChildFragment() { override fun goBack(): Boolean { sharedViewModel.closeSlidingPaneEvent.value = Event(true) - // If not done, when going back to CallsFragment this fragment will be created again - return findNavController().popBackStack() + + // If not done this fragment won't be paused, which will cause us issues + val action = HistoryContactFragmentDirections.actionHistoryContactFragmentToEmptyFragment() + findNavController().navigate(action) + return true } override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt index 06244d9d7..e20224e30 100644 --- a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt @@ -69,8 +69,11 @@ class MeetingFragment : SlidingPaneChildFragment() { override fun goBack(): Boolean { sharedViewModel.closeSlidingPaneEvent.value = Event(true) - // If not done, when going back to MeetingsListFragment this fragment will be created again - return findNavController().popBackStack() + + // If not done this fragment won't be paused, which will cause us issues + val action = MeetingFragmentDirections.actionMeetingFragmentToEmptyFragment() + findNavController().navigate(action) + return true } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/res/layout/meeting_fragment.xml b/app/src/main/res/layout/meeting_fragment.xml index cbe56dfc3..fdd168f53 100644 --- a/app/src/main/res/layout/meeting_fragment.xml +++ b/app/src/main/res/layout/meeting_fragment.xml @@ -34,6 +34,7 @@ android:adjustViewBounds="true" android:padding="15dp" android:src="@drawable/caret_left" + android:visibility="@{viewModel.showBackButton ? View.VISIBLE : View.GONE}" app:tint="?attr/color_main1_500" app:layout_constraintBottom_toBottomOf="@id/title" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/navigation/chat_nav_graph.xml b/app/src/main/res/navigation/chat_nav_graph.xml index 810cdb45f..d579686d1 100644 --- a/app/src/main/res/navigation/chat_nav_graph.xml +++ b/app/src/main/res/navigation/chat_nav_graph.xml @@ -30,12 +30,17 @@ app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" /> + + app:launchSingleTop="true"/> + + +