diff --git a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt
index 89c8d0002..cccf70105 100644
--- a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt
+++ b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt
@@ -1085,7 +1085,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
return NavDeepLinkBuilder(context)
.setComponentName(MainActivity::class.java)
.setGraph(R.navigation.main_nav_graph)
- .setDestination(R.id.conversationsFragment)
+ .setDestination(R.id.conversationsListFragment)
.setArguments(args)
.createPendingIntent()
}
diff --git a/app/src/main/java/org/linphone/ui/main/MainActivity.kt b/app/src/main/java/org/linphone/ui/main/MainActivity.kt
index 41ad4bbc6..6b9f647cc 100644
--- a/app/src/main/java/org/linphone/ui/main/MainActivity.kt
+++ b/app/src/main/java/org/linphone/ui/main/MainActivity.kt
@@ -194,27 +194,27 @@ class MainActivity : AppCompatActivity() {
val startDestination = when (corePreferences.defaultFragment) {
CONTACTS_FRAGMENT_ID -> {
Log.i("$TAG Latest visited page is contacts, setting it as start destination")
- R.id.contactsFragment
+ R.id.contactsListFragment
}
HISTORY_FRAGMENT_ID -> {
Log.i(
"$TAG Latest visited page is call history, setting it as start destination"
)
- R.id.historyFragment
+ R.id.historyListFragment
}
CHAT_FRAGMENT_ID -> {
Log.i(
"$TAG Latest visited page is conversations, setting it as start destination"
)
- R.id.conversationsFragment
+ R.id.conversationsListFragment
}
MEETINGS_FRAGMENT_ID -> {
Log.i("$TAG Latest visited page is meetings, setting it as start destination")
- R.id.meetingsFragment
+ R.id.meetingsListFragment
}
else -> { // Default
Log.i("$TAG No latest visited page stored, using default one (call history)")
- R.id.historyFragment
+ R.id.historyListFragment
}
}
coreContext.postOnMainThread {
@@ -230,16 +230,16 @@ class MainActivity : AppCompatActivity() {
override fun onPause() {
val defaultFragmentId = when (sharedViewModel.currentlyDisplayedFragment.value) {
- R.id.contactsFragment -> {
+ R.id.contactsListFragment -> {
CONTACTS_FRAGMENT_ID
}
- R.id.historyFragment -> {
+ R.id.historyListFragment -> {
HISTORY_FRAGMENT_ID
}
- R.id.conversationsFragment -> {
+ R.id.conversationsListFragment -> {
CHAT_FRAGMENT_ID
}
- R.id.meetingsFragment -> {
+ R.id.meetingsListFragment -> {
MEETINGS_FRAGMENT_ID
}
else -> { // Default
@@ -352,12 +352,12 @@ class MainActivity : AppCompatActivity() {
if (isNewIntent) {
Log.i("$TAG Going to Conversations fragment")
findNavController().navigate(
- R.id.action_global_conversationsFragment,
+ R.id.action_global_conversationsListFragment,
intent.extras
)
} else {
Log.i("$TAG Going to Conversations fragment instead of default destination")
- navGraph.setStartDestination(R.id.conversationsFragment)
+ navGraph.setStartDestination(R.id.conversationsListFragment)
findNavController().setGraph(navGraph, intent.extras)
}
} else {
@@ -415,7 +415,7 @@ class MainActivity : AppCompatActivity() {
}
val navGraph = findNavController().navInflater.inflate(R.navigation.main_nav_graph)
- navGraph.setStartDestination(R.id.conversationsFragment)
+ navGraph.setStartDestination(R.id.conversationsListFragment)
val paths = deferred.awaitAll()
for (path in paths) {
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 a1f5236cb..49cf7a5dd 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
@@ -172,7 +172,8 @@ class ConversationFragment : GenericFragment() {
override fun goBack(): Boolean {
coreContext.notificationsManager.resetCurrentlyDisplayedChatRoomId()
sharedViewModel.closeSlidingPaneEvent.value = Event(true)
- // If not done, when going back to ConversationsFragment this fragment will be created again
+ coreContext.notificationsManager.resetCurrentlyDisplayedChatRoomId()
+ // If not done, when going back to ConversationsListFragment this fragment will be created again
return findNavController().popBackStack()
}
@@ -181,7 +182,6 @@ class ConversationFragment : GenericFragment() {
isSlidingPaneChild = true
super.onViewCreated(view, savedInstanceState)
- // postponeEnterTransition()
binding.lifecycleOwner = viewLifecycleOwner
@@ -234,7 +234,6 @@ class ConversationFragment : GenericFragment() {
}
(view.parent as? ViewGroup)?.doOnPreDraw {
- // startPostponedEnterTransition()
sharedViewModel.openSlidingPaneEvent.value = Event(true)
}
}
diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsFragment.kt
deleted file mode 100644
index ac39dad3e..000000000
--- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsFragment.kt
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (c) 2010-2023 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.ui.main.chat.fragment
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.view.animation.Animation
-import android.view.animation.AnimationUtils
-import androidx.annotation.UiThread
-import androidx.core.view.doOnPreDraw
-import androidx.navigation.findNavController
-import androidx.navigation.fragment.findNavController
-import androidx.slidingpanelayout.widget.SlidingPaneLayout
-import org.linphone.R
-import org.linphone.core.tools.Log
-import org.linphone.databinding.ChatFragmentBinding
-import org.linphone.ui.main.fragment.GenericFragment
-import org.linphone.utils.Event
-import org.linphone.utils.SlidingPaneBackPressedCallback
-
-@UiThread
-class ConversationsFragment : GenericFragment() {
- companion object {
- private const val TAG = "[Conversations Fragment]"
- }
-
- private lateinit var binding: ChatFragmentBinding
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- binding = ChatFragmentBinding.inflate(layoutInflater)
- return binding.root
- }
-
- override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
- if (
- findNavController().currentDestination?.id == R.id.startConversationFragment ||
- findNavController().currentDestination?.id == R.id.meetingWaitingRoomFragment
- ) {
- // Holds fragment in place while new contact fragment slides over it
- return AnimationUtils.loadAnimation(activity, R.anim.hold)
- }
- return super.onCreateAnimation(transit, enter, nextAnim)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- postponeEnterTransition()
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- binding.root.doOnPreDraw {
- val slidingPane = binding.slidingPaneLayout
- slidingPane.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
-
- sharedViewModel.isSlidingPaneSlideable.value = slidingPane.isSlideable
-
- requireActivity().onBackPressedDispatcher.addCallback(
- viewLifecycleOwner,
- SlidingPaneBackPressedCallback(slidingPane)
- )
- }
-
- sharedViewModel.conversationsReadyEvent.observe(viewLifecycleOwner) {
- it.consume {
- (view.parent as? ViewGroup)?.doOnPreDraw {
- startPostponedEnterTransition()
- sharedViewModel.isFirstFragmentReady = true
- }
- }
- }
-
- val args = arguments
- if (args != null) {
- val localSipUri = args.getString("LocalSipUri")
- val remoteSipUri = args.getString("RemoteSipUri")
- if (localSipUri != null && remoteSipUri != null) {
- Log.i("$TAG Found local [$localSipUri] & remote [$remoteSipUri] URIs in arguments")
- val pair = Pair(localSipUri, remoteSipUri)
- sharedViewModel.showConversationEvent.value = Event(pair)
- args.clear()
- }
- }
-
- sharedViewModel.closeSlidingPaneEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- if (binding.slidingPaneLayout.isOpen) {
- Log.i("$TAG Closing sliding pane")
- binding.slidingPaneLayout.closePane()
- }
- }
- }
-
- sharedViewModel.openSlidingPaneEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- if (!binding.slidingPaneLayout.isOpen) {
- Log.i("$TAG Opening sliding pane")
- binding.slidingPaneLayout.openPane()
- }
- }
- }
-
- sharedViewModel.showStartConversationEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.conversationsFragment) {
- Log.i("$TAG Navigating to start conversation fragment")
- val action =
- ConversationsFragmentDirections.actionConversationsFragmentToStartConversationFragment()
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.showConversationEvent.observe(viewLifecycleOwner) {
- it.consume { pair ->
- val localSipUri = pair.first
- val remoteSipUri = pair.second
- Log.i(
- "$TAG Navigating to conversation fragment with local SIP URI [$localSipUri] and remote SIP URI [$remoteSipUri]"
- )
- val action = ConversationFragmentDirections.actionGlobalConversationFragment(
- localSipUri,
- remoteSipUri
- )
- binding.chatNavContainer.findNavController().navigate(action)
- }
- }
-
- sharedViewModel.goToMeetingWaitingRoomEvent.observe(viewLifecycleOwner) {
- it.consume { uri ->
- if (findNavController().currentDestination?.id == R.id.conversationsFragment) {
- Log.i("$TAG Navigating to meeting waiting room fragment with URI [$uri]")
- val action =
- ConversationsFragmentDirections.actionConversationsFragmentToMeetingWaitingRoomFragment(
- uri
- )
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.navigateToContactsEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.conversationsFragment) {
- // To prevent any previously seen conversation to show up when navigating back to here later
- binding.chatNavContainer.findNavController().popBackStack()
-
- val action = ConversationsFragmentDirections.actionConversationsFragmentToContactsFragment()
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.navigateToHistoryEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.conversationsFragment) {
- // To prevent any previously seen conversation to show up when navigating back to here later
- binding.chatNavContainer.findNavController().popBackStack()
-
- val action = ConversationsFragmentDirections.actionConversationsFragmentToHistoryFragment()
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.navigateToMeetingsEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.conversationsFragment) {
- // To prevent any previously seen conversation to show up when navigating back to here later
- binding.chatNavContainer.findNavController().popBackStack()
-
- val action = ConversationsFragmentDirections.actionConversationsFragmentToMeetingsFragment()
- findNavController().navigate(action)
- }
- }
- }
- }
-
- override fun onResume() {
- super.onResume()
-
- sharedViewModel.currentlyDisplayedFragment.value = R.id.conversationsFragment
- }
-}
diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsListFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsListFragment.kt
index e9c283110..b2d0b72db 100644
--- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsListFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationsListFragment.kt
@@ -19,14 +19,17 @@
*/
package org.linphone.ui.main.chat.fragment
-import android.content.res.Configuration
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.view.animation.Animation
+import android.view.animation.AnimationUtils
import androidx.annotation.UiThread
import androidx.core.view.doOnPreDraw
import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.findNavController
+import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import org.linphone.R
import org.linphone.core.tools.Log
@@ -36,7 +39,6 @@ import org.linphone.ui.main.chat.viewmodel.ConversationsListViewModel
import org.linphone.ui.main.fragment.AbstractTopBarFragment
import org.linphone.ui.main.history.fragment.HistoryMenuDialogFragment
import org.linphone.utils.Event
-import org.linphone.utils.setKeyboardInsetListener
@UiThread
class ConversationsListFragment : AbstractTopBarFragment() {
@@ -50,6 +52,24 @@ class ConversationsListFragment : AbstractTopBarFragment() {
private lateinit var adapter: ConversationsListAdapter
+ override fun onDefaultAccountChanged() {
+ Log.i(
+ "$TAG Default account changed, updating avatar in top bar & re-computing conversations"
+ )
+ listViewModel.applyFilter()
+ }
+
+ override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
+ if (
+ findNavController().currentDestination?.id == R.id.startConversationFragment ||
+ findNavController().currentDestination?.id == R.id.meetingWaitingRoomFragment
+ ) {
+ // Holds fragment in place while new contact fragment slides over it
+ return AnimationUtils.loadAnimation(activity, R.anim.hold)
+ }
+ return super.onCreateAnimation(transit, enter, nextAnim)
+ }
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -118,7 +138,12 @@ class ConversationsListFragment : AbstractTopBarFragment() {
}
binding.setOnNewConversationClicked {
- sharedViewModel.showStartConversationEvent.value = Event(true)
+ if (findNavController().currentDestination?.id == R.id.conversationsListFragment) {
+ Log.i("$TAG Navigating to start conversation fragment")
+ val action =
+ ConversationsListFragmentDirections.actionConversationsListFragmentToStartConversationFragment()
+ findNavController().navigate(action)
+ }
}
listViewModel.conversations.observe(viewLifecycleOwner) {
@@ -132,7 +157,7 @@ class ConversationsListFragment : AbstractTopBarFragment() {
(view.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
- sharedViewModel.conversationsReadyEvent.value = Event(true)
+ sharedViewModel.isFirstFragmentReady = true
}
}
@@ -143,6 +168,36 @@ class ConversationsListFragment : AbstractTopBarFragment() {
}
}
+ sharedViewModel.showConversationEvent.observe(viewLifecycleOwner) {
+ it.consume { pair ->
+ val localSipUri = pair.first
+ val remoteSipUri = pair.second
+ Log.i(
+ "${ConversationsListFragment.TAG} Navigating to conversation fragment with local SIP URI [$localSipUri] and remote SIP URI [$remoteSipUri]"
+ )
+ if (findNavController().currentDestination?.id == R.id.conversationsListFragment) {
+ val action = ConversationFragmentDirections.actionGlobalConversationFragment(
+ localSipUri,
+ remoteSipUri
+ )
+ binding.chatNavContainer.findNavController().navigate(action)
+ }
+ }
+ }
+
+ sharedViewModel.goToMeetingWaitingRoomEvent.observe(viewLifecycleOwner) {
+ it.consume { uri ->
+ if (findNavController().currentDestination?.id == R.id.conversationsListFragment) {
+ Log.i("$TAG Navigating to meeting waiting room fragment with URI [$uri]")
+ val action =
+ ConversationsListFragmentDirections.actionConversationsListFragmentToMeetingWaitingRoomFragment(
+ uri
+ )
+ findNavController().navigate(action)
+ }
+ }
+ }
+
// TopBarFragment related
setViewModelAndTitle(
@@ -151,17 +206,23 @@ class ConversationsListFragment : AbstractTopBarFragment() {
getString(R.string.bottom_navigation_conversations_label)
)
- binding.root.setKeyboardInsetListener { keyboardVisible ->
- val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE
- binding.bottomNavBar.root.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE
- }
+ initBottomNavBar(binding.bottomNavBar.root)
- sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) {
- it.consume {
- Log.i(
- "$TAG Default account changed, updating avatar in top bar & re-computing conversations"
- )
- listViewModel.applyFilter()
+ initSlidingPane(binding.slidingPaneLayout)
+
+ initNavigation(R.id.conversationsListFragment)
+
+ // Handle intent params if any
+
+ val args = arguments
+ if (args != null) {
+ val localSipUri = args.getString("LocalSipUri")
+ val remoteSipUri = args.getString("RemoteSipUri")
+ if (localSipUri != null && remoteSipUri != null) {
+ Log.i("$TAG Found local [$localSipUri] & remote [$remoteSipUri] URIs in arguments")
+ val pair = Pair(localSipUri, remoteSipUri)
+ sharedViewModel.showConversationEvent.value = Event(pair)
+ args.clear()
}
}
}
diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/SendMessageInConversationViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/SendMessageInConversationViewModel.kt
index d06065277..4fb642d72 100644
--- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/SendMessageInConversationViewModel.kt
+++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/SendMessageInConversationViewModel.kt
@@ -265,7 +265,9 @@ class SendMessageInConversationViewModel @UiThread constructor() : ViewModel() {
isParticipantsListOpen.postValue(false)
isEmojiPickerOpen.postValue(false)
- stopVoiceRecorder()
+ if (::voiceMessageRecorder.isInitialized) {
+ stopVoiceRecorder()
+ }
voiceRecording.postValue(false)
// Warning: do not delete files
diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsFragment.kt
deleted file mode 100644
index 19e1afe0e..000000000
--- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsFragment.kt
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2010-2023 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.ui.main.contacts.fragment
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.view.animation.Animation
-import android.view.animation.AnimationUtils
-import androidx.annotation.UiThread
-import androidx.core.view.doOnPreDraw
-import androidx.navigation.findNavController
-import androidx.navigation.fragment.findNavController
-import androidx.slidingpanelayout.widget.SlidingPaneLayout
-import org.linphone.R
-import org.linphone.core.tools.Log
-import org.linphone.databinding.ContactsFragmentBinding
-import org.linphone.ui.main.fragment.GenericFragment
-import org.linphone.utils.SlidingPaneBackPressedCallback
-
-@UiThread
-class ContactsFragment : GenericFragment() {
- companion object {
- private const val TAG = "[Contacts Fragment]"
- }
-
- private lateinit var binding: ContactsFragmentBinding
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- binding = ContactsFragmentBinding.inflate(layoutInflater)
- return binding.root
- }
-
- override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
- if (findNavController().currentDestination?.id == R.id.newContactFragment) {
- // Holds fragment in place while new contact fragment slides over it
- return AnimationUtils.loadAnimation(activity, R.anim.hold)
- }
- return super.onCreateAnimation(transit, enter, nextAnim)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- postponeEnterTransition()
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- binding.root.doOnPreDraw {
- val slidingPane = binding.slidingPaneLayout
- slidingPane.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
-
- sharedViewModel.isSlidingPaneSlideable.value = slidingPane.isSlideable
-
- requireActivity().onBackPressedDispatcher.addCallback(
- viewLifecycleOwner,
- SlidingPaneBackPressedCallback(slidingPane)
- )
- }
-
- sharedViewModel.contactsReadyEvent.observe(viewLifecycleOwner) {
- it.consume {
- (view.parent as? ViewGroup)?.doOnPreDraw {
- startPostponedEnterTransition()
- sharedViewModel.isFirstFragmentReady = true
- }
- }
- }
-
- sharedViewModel.closeSlidingPaneEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- if (binding.slidingPaneLayout.isOpen) {
- Log.i("$TAG Closing sliding pane")
- binding.slidingPaneLayout.closePane()
- }
- }
- }
-
- sharedViewModel.openSlidingPaneEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- if (!binding.slidingPaneLayout.isOpen) {
- Log.i("$TAG Opening sliding pane")
- binding.slidingPaneLayout.openPane()
- }
- }
- }
-
- sharedViewModel.showContactEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { refKey ->
- Log.i("$TAG Displaying contact with ref key [$refKey]")
- val navController = binding.contactsNavContainer.findNavController()
- val action = ContactFragmentDirections.actionGlobalContactFragment(
- refKey
- )
- navController.navigate(action)
- }
- }
-
- sharedViewModel.showNewContactEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- Log.i("$TAG Opening contact editor for creating new contact")
- val action = ContactsFragmentDirections.actionContactsFragmentToNewContactFragment()
- findNavController().navigate(action)
- }
- }
-
- sharedViewModel.navigateToHistoryEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.contactsFragment) {
- // To prevent any previously seen contact to show up when navigating back to here later
- binding.contactsNavContainer.findNavController().popBackStack()
-
- val action = ContactsFragmentDirections.actionContactsFragmentToHistoryFragment()
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.navigateToConversationsEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.contactsFragment) {
- // To prevent any previously seen contact to show up when navigating back to here later
- binding.contactsNavContainer.findNavController().popBackStack()
-
- val action = ContactsFragmentDirections.actionContactsFragmentToConversationsFragment()
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.navigateToMeetingsEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.contactsFragment) {
- // To prevent any previously seen contact to show up when navigating back to here later
- binding.contactsNavContainer.findNavController().popBackStack()
-
- val action = ContactsFragmentDirections.actionContactsFragmentToMeetingsFragment()
- findNavController().navigate(action)
- }
- }
- }
- }
-
- override fun onResume() {
- super.onResume()
- sharedViewModel.currentlyDisplayedFragment.value = R.id.contactsFragment
- }
-}
diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt
index 8bff1a1fa..71c9c5363 100644
--- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt
@@ -20,7 +20,6 @@
package org.linphone.ui.main.contacts.fragment
import android.content.Intent
-import android.content.res.Configuration
import android.os.Bundle
import android.provider.ContactsContract
import android.view.Gravity
@@ -33,6 +32,8 @@ import androidx.core.content.FileProvider
import androidx.core.view.doOnPreDraw
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.findNavController
+import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import java.io.File
import org.linphone.LinphoneApplication.Companion.coreContext
@@ -44,7 +45,6 @@ import org.linphone.ui.main.contacts.adapter.ContactsListAdapter
import org.linphone.ui.main.contacts.viewmodel.ContactsListViewModel
import org.linphone.ui.main.fragment.AbstractTopBarFragment
import org.linphone.utils.Event
-import org.linphone.utils.setKeyboardInsetListener
@UiThread
class ContactsListFragment : AbstractTopBarFragment() {
@@ -59,6 +59,14 @@ class ContactsListFragment : AbstractTopBarFragment() {
private lateinit var adapter: ContactsListAdapter
private lateinit var favouritesAdapter: ContactsListAdapter
+ override fun onDefaultAccountChanged() {
+ Log.i(
+ "$TAG Default account changed, updating avatar in top bar & refreshing contacts list"
+ )
+ listViewModel.update()
+ listViewModel.applyCurrentDefaultAccountFilter()
+ }
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -106,7 +114,7 @@ class ContactsListFragment : AbstractTopBarFragment() {
(view.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
- sharedViewModel.contactsReadyEvent.value = Event(true)
+ sharedViewModel.isFirstFragmentReady = true
}
}
@@ -136,6 +144,32 @@ class ContactsListFragment : AbstractTopBarFragment() {
showFilterPopupMenu(binding.filter)
}
+ sharedViewModel.showContactEvent.observe(
+ viewLifecycleOwner
+ ) {
+ it.consume { refKey ->
+ Log.i("$TAG Displaying contact with ref key [$refKey]")
+ val navController = binding.contactsNavContainer.findNavController()
+ val action = ContactFragmentDirections.actionGlobalContactFragment(
+ refKey
+ )
+ navController.navigate(action)
+ }
+ }
+
+ sharedViewModel.showNewContactEvent.observe(
+ viewLifecycleOwner
+ ) {
+ it.consume {
+ if (findNavController().currentDestination?.id == R.id.contactsListFragment) {
+ Log.i("$TAG Opening contact editor for creating new contact")
+ val action =
+ ContactsListFragmentDirections.actionContactsListFragmentToNewContactFragment()
+ findNavController().navigate(action)
+ }
+ }
+ }
+
// TopBarFragment related
setViewModelAndTitle(
@@ -144,20 +178,11 @@ class ContactsListFragment : AbstractTopBarFragment() {
getString(R.string.bottom_navigation_contacts_label)
)
- binding.root.setKeyboardInsetListener { keyboardVisible ->
- val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE
- binding.bottomNavBar.root.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE
- }
+ initBottomNavBar(binding.bottomNavBar.root)
- sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) {
- it.consume {
- Log.i(
- "$TAG Default account changed, updating avatar in top bar & refreshing contacts list"
- )
- listViewModel.update()
- listViewModel.applyCurrentDefaultAccountFilter()
- }
- }
+ initSlidingPane(binding.slidingPaneLayout)
+
+ initNavigation(R.id.contactsListFragment)
}
private fun configureAdapter(adapter: ContactsListAdapter) {
diff --git a/app/src/main/java/org/linphone/ui/main/fragment/AbstractTopBarFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/AbstractTopBarFragment.kt
index 90706385c..105dde48d 100644
--- a/app/src/main/java/org/linphone/ui/main/fragment/AbstractTopBarFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/fragment/AbstractTopBarFragment.kt
@@ -19,17 +19,73 @@
*/
package org.linphone.ui.main.fragment
+import android.content.res.Configuration
+import android.view.View
+import androidx.annotation.IdRes
import androidx.annotation.UiThread
+import androidx.core.view.doOnPreDraw
+import androidx.navigation.NavDirections
+import androidx.navigation.fragment.findNavController
+import androidx.slidingpanelayout.widget.SlidingPaneLayout
import com.google.android.material.textfield.TextInputLayout
import org.linphone.R
+import org.linphone.core.tools.Log
import org.linphone.ui.main.MainActivity
+import org.linphone.ui.main.chat.fragment.ConversationsListFragmentDirections
+import org.linphone.ui.main.contacts.fragment.ContactsListFragmentDirections
+import org.linphone.ui.main.history.fragment.HistoryListFragmentDirections
+import org.linphone.ui.main.meetings.fragment.MeetingsListFragmentDirections
import org.linphone.ui.main.viewmodel.AbstractTopBarViewModel
-import org.linphone.utils.Event
+import org.linphone.utils.SlidingPaneBackPressedCallback
import org.linphone.utils.hideKeyboard
+import org.linphone.utils.setKeyboardInsetListener
import org.linphone.utils.showKeyboard
@UiThread
abstract class AbstractTopBarFragment : GenericFragment() {
+ companion object {
+ private const val TAG = "[Abstract TobBar Fragment]"
+ }
+
+ private var currentFragmentId: Int = 0
+
+ abstract fun onDefaultAccountChanged()
+
+ fun initSlidingPane(slidingPane: SlidingPaneLayout) {
+ view?.doOnPreDraw {
+ slidingPane.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
+
+ sharedViewModel.isSlidingPaneSlideable.value = slidingPane.isSlideable
+
+ requireActivity().onBackPressedDispatcher.addCallback(
+ viewLifecycleOwner,
+ SlidingPaneBackPressedCallback(slidingPane)
+ )
+ }
+
+ sharedViewModel.closeSlidingPaneEvent.observe(
+ viewLifecycleOwner
+ ) {
+ it.consume {
+ if (slidingPane.isOpen) {
+ Log.i("$TAG Closing sliding pane")
+ slidingPane.closePane()
+ }
+ }
+ }
+
+ sharedViewModel.openSlidingPaneEvent.observe(
+ viewLifecycleOwner
+ ) {
+ it.consume {
+ if (!slidingPane.isOpen) {
+ Log.i("$TAG Opening sliding pane")
+ slidingPane.openPane()
+ }
+ }
+ }
+ }
+
fun setViewModelAndTitle(
searchBar: TextInputLayout,
viewModel: AbstractTopBarViewModel,
@@ -59,34 +115,42 @@ abstract class AbstractTopBarFragment : GenericFragment() {
}
viewModel.navigateToContactsEvent.observe(viewLifecycleOwner) {
- if (sharedViewModel.currentlyDisplayedFragment.value != R.id.contactsFragment) {
- sharedViewModel.navigateToContactsEvent.value = Event(true)
+ it.consume {
+ if (currentFragmentId != R.id.contactsListFragment) {
+ goToContactsList()
+ }
}
}
viewModel.navigateToHistoryEvent.observe(viewLifecycleOwner) {
- if (sharedViewModel.currentlyDisplayedFragment.value != R.id.historyFragment) {
- sharedViewModel.navigateToHistoryEvent.value = Event(true)
+ it.consume {
+ if (currentFragmentId != R.id.historyListFragment) {
+ goToHistoryList()
+ }
}
}
viewModel.navigateToConversationsEvent.observe(viewLifecycleOwner) {
- if (sharedViewModel.currentlyDisplayedFragment.value != R.id.conversationsFragment) {
- sharedViewModel.navigateToConversationsEvent.value = Event(true)
+ it.consume {
+ if (currentFragmentId != R.id.conversationsListFragment) {
+ goToConversationsList()
+ }
}
}
viewModel.navigateToMeetingsEvent.observe(viewLifecycleOwner) {
- if (sharedViewModel.currentlyDisplayedFragment.value != R.id.meetingsFragment) {
- sharedViewModel.navigateToMeetingsEvent.value = Event(true)
+ it.consume {
+ if (currentFragmentId != R.id.meetingsListFragment) {
+ goToMeetingsList()
+ }
}
}
sharedViewModel.currentlyDisplayedFragment.observe(viewLifecycleOwner) {
- viewModel.contactsSelected.value = it == R.id.contactsFragment
- viewModel.callsSelected.value = it == R.id.historyFragment
- viewModel.conversationsSelected.value = it == R.id.conversationsFragment
- viewModel.meetingsSelected.value = it == R.id.meetingsFragment
+ viewModel.contactsSelected.value = it == R.id.contactsListFragment
+ viewModel.callsSelected.value = it == R.id.historyListFragment
+ viewModel.conversationsSelected.value = it == R.id.conversationsListFragment
+ viewModel.meetingsSelected.value = it == R.id.meetingsListFragment
}
sharedViewModel.resetMissedCallsCountEvent.observe(viewLifecycleOwner) {
@@ -96,8 +160,146 @@ abstract class AbstractTopBarFragment : GenericFragment() {
}
sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) {
- // Do not consume it!
- viewModel.updateAvailableMenus()
+ it.consume {
+ Log.i("$TAG Default account changed")
+ viewModel.updateAvailableMenus()
+ onDefaultAccountChanged()
+ }
+ }
+ }
+
+ fun initBottomNavBar(navBar: View) {
+ view?.setKeyboardInsetListener { keyboardVisible ->
+ val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE
+ navBar.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE
+ }
+ }
+
+ fun initNavigation(@IdRes fragmentId: Int) {
+ currentFragmentId = fragmentId
+
+ sharedViewModel.navigateToContactsEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ goToContactsList()
+ }
+ }
+
+ sharedViewModel.navigateToHistoryEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ goToHistoryList()
+ }
+ }
+
+ sharedViewModel.navigateToConversationsEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ goToConversationsList()
+ }
+ }
+
+ sharedViewModel.navigateToMeetingsEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ goToMeetingsList()
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ if (currentFragmentId > 0) {
+ sharedViewModel.currentlyDisplayedFragment.value = currentFragmentId
+ }
+ }
+
+ private fun goToContactsList() {
+ Log.i("$TAG Navigating to contacts list")
+ when (currentFragmentId) {
+ R.id.conversationsListFragment -> {
+ Log.i("$TAG Leaving conversations list")
+ val action = ConversationsListFragmentDirections.actionConversationsListFragmentToContactsListFragment()
+ navigateTo(action)
+ }
+ R.id.meetingsListFragment -> {
+ Log.i("$TAG Leaving meetings list")
+ val action = MeetingsListFragmentDirections.actionMeetingsListFragmentToContactsListFragment()
+ navigateTo(action)
+ }
+ R.id.historyListFragment -> {
+ Log.i("$TAG Leaving history list")
+ val action = HistoryListFragmentDirections.actionHistoryListFragmentToContactsListFragment()
+ navigateTo(action)
+ }
+ }
+ }
+
+ private fun goToHistoryList() {
+ Log.i("$TAG Navigating to history list")
+ when (currentFragmentId) {
+ R.id.conversationsListFragment -> {
+ Log.i("$TAG Leaving conversations list")
+ val action = ConversationsListFragmentDirections.actionConversationsListFragmentToHistoryListFragment()
+ navigateTo(action)
+ }
+ R.id.contactsListFragment -> {
+ Log.i("$TAG Leaving contacts list")
+ val action = ContactsListFragmentDirections.actionContactsListFragmentToHistoryListFragment()
+ navigateTo(action)
+ }
+ R.id.meetingsListFragment -> {
+ Log.i("$TAG Leaving meetings list")
+ val action = MeetingsListFragmentDirections.actionMeetingsListFragmentToHistoryListFragment()
+ navigateTo(action)
+ }
+ }
+ }
+
+ private fun goToConversationsList() {
+ Log.i("$TAG Navigating to conversations list")
+ when (currentFragmentId) {
+ R.id.contactsListFragment -> {
+ Log.i("$TAG Leaving contacts list")
+ val action = ContactsListFragmentDirections.actionContactsListFragmentToConversationsListFragment()
+ navigateTo(action)
+ }
+ R.id.meetingsListFragment -> {
+ Log.i("$TAG Leaving meetings list")
+ val action = MeetingsListFragmentDirections.actionMeetingsListFragmentToConversationsListFragment()
+ navigateTo(action)
+ }
+ R.id.historyListFragment -> {
+ Log.i("$TAG Leaving history list")
+ val action = HistoryListFragmentDirections.actionHistoryListFragmentToConversationsListFragment()
+ navigateTo(action)
+ }
+ }
+ }
+
+ private fun goToMeetingsList() {
+ Log.i("$TAG Navigating to meetings list")
+ when (currentFragmentId) {
+ R.id.conversationsListFragment -> {
+ Log.i("$TAG Leaving conversations list")
+ val action = ConversationsListFragmentDirections.actionConversationsListFragmentToMeetingsListFragment()
+ navigateTo(action)
+ }
+ R.id.contactsListFragment -> {
+ Log.i("$TAG Leaving contacts list")
+ val action = ContactsListFragmentDirections.actionContactsListFragmentToMeetingsListFragment()
+ navigateTo(action)
+ }
+ R.id.historyListFragment -> {
+ Log.i("$TAG Leaving history list")
+ val action = HistoryListFragmentDirections.actionHistoryListFragmentToMeetingsListFragment()
+ navigateTo(action)
+ }
+ }
+ }
+
+ private fun navigateTo(action: NavDirections) {
+ try {
+ findNavController().navigate(action)
+ } catch (e: Exception) {
+ Log.e("$TAG Failed to navigate: $e")
}
}
}
diff --git a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryFragment.kt b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryFragment.kt
deleted file mode 100644
index 26374a30e..000000000
--- a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryFragment.kt
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (c) 2010-2023 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.ui.main.history.fragment
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.view.animation.Animation
-import android.view.animation.AnimationUtils
-import androidx.annotation.UiThread
-import androidx.core.view.doOnPreDraw
-import androidx.navigation.findNavController
-import androidx.navigation.fragment.findNavController
-import androidx.slidingpanelayout.widget.SlidingPaneLayout
-import org.linphone.R
-import org.linphone.core.tools.Log
-import org.linphone.databinding.HistoryFragmentBinding
-import org.linphone.ui.main.fragment.GenericFragment
-import org.linphone.utils.SlidingPaneBackPressedCallback
-
-@UiThread
-class HistoryFragment : GenericFragment() {
- companion object {
- private const val TAG = "[Calls Fragment]"
- }
-
- private lateinit var binding: HistoryFragmentBinding
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- binding = HistoryFragmentBinding.inflate(layoutInflater)
- return binding.root
- }
-
- override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
- if (findNavController().currentDestination?.id == R.id.startCallFragment) {
- // Holds fragment in place while new contact fragment slides over it
- return AnimationUtils.loadAnimation(activity, R.anim.hold)
- }
- return super.onCreateAnimation(transit, enter, nextAnim)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- postponeEnterTransition()
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- binding.root.doOnPreDraw {
- val slidingPane = binding.slidingPaneLayout
- slidingPane.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
-
- sharedViewModel.isSlidingPaneSlideable.value = slidingPane.isSlideable
-
- requireActivity().onBackPressedDispatcher.addCallback(
- viewLifecycleOwner,
- SlidingPaneBackPressedCallback(slidingPane)
- )
- }
-
- sharedViewModel.historyReadyEvent.observe(viewLifecycleOwner) {
- it.consume {
- (view.parent as? ViewGroup)?.doOnPreDraw {
- startPostponedEnterTransition()
- sharedViewModel.isFirstFragmentReady = true
- }
- }
- }
-
- sharedViewModel.closeSlidingPaneEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- if (binding.slidingPaneLayout.isOpen) {
- Log.i("$TAG Closing sliding pane")
- binding.slidingPaneLayout.closePane()
- }
- }
- }
-
- sharedViewModel.openSlidingPaneEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- if (!binding.slidingPaneLayout.isOpen) {
- Log.i("$TAG Opening sliding pane")
- binding.slidingPaneLayout.openPane()
- }
- }
- }
-
- sharedViewModel.showStartCallEvent.observe(viewLifecycleOwner) {
- it.consume {
- Log.i("$TAG Navigating to start call fragment")
- val action = HistoryFragmentDirections.actionHistoryFragmentToStartCallFragment()
- findNavController().navigate(action)
- }
- }
-
- sharedViewModel.showCallLogEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { callId ->
- Log.i("$TAG Displaying call log with call ID [$callId]")
- val navController = binding.historyNavContainer.findNavController()
- val action = HistoryContactFragmentDirections.actionGlobalHistoryContactFragment(
- callId
- )
- navController.navigate(action)
- }
- }
-
- sharedViewModel.navigateToContactsEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.historyFragment) {
- // To prevent any previously seen call log to show up when navigating back to here later
- binding.historyNavContainer.findNavController().popBackStack()
-
- val action = HistoryFragmentDirections.actionHistoryFragmentToContactsFragment()
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.navigateToConversationsEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.historyFragment) {
- // To prevent any previously seen call log to show up when navigating back to here later
- binding.historyNavContainer.findNavController().popBackStack()
-
- val action = HistoryFragmentDirections.actionHistoryFragmentToConversationsFragment()
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.navigateToMeetingsEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.historyFragment) {
- // To prevent any previously seen call log to show up when navigating back to here later
- binding.historyNavContainer.findNavController().popBackStack()
-
- val action = HistoryFragmentDirections.actionHistoryFragmentToMeetingsFragment()
- findNavController().navigate(action)
- }
- }
- }
- }
-
- override fun onResume() {
- super.onResume()
- sharedViewModel.currentlyDisplayedFragment.value = R.id.historyFragment
- }
-}
diff --git a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryListFragment.kt b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryListFragment.kt
index 1a3ca6448..0f4609407 100644
--- a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryListFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryListFragment.kt
@@ -22,17 +22,20 @@ package org.linphone.ui.main.history.fragment
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
-import android.content.res.Configuration
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.view.animation.Animation
+import android.view.animation.AnimationUtils
import android.widget.PopupWindow
import androidx.annotation.UiThread
import androidx.core.view.doOnPreDraw
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.findNavController
+import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
@@ -46,7 +49,6 @@ import org.linphone.ui.main.history.model.ConfirmationDialogModel
import org.linphone.ui.main.history.viewmodel.HistoryListViewModel
import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
-import org.linphone.utils.setKeyboardInsetListener
@UiThread
class HistoryListFragment : AbstractTopBarFragment() {
@@ -60,6 +62,22 @@ class HistoryListFragment : AbstractTopBarFragment() {
private lateinit var adapter: HistoryListAdapter
+ override fun onDefaultAccountChanged() {
+ Log.i(
+ "$TAG Default account changed, updating avatar in top bar & re-computing call logs"
+ )
+ listViewModel.update()
+ listViewModel.applyFilter()
+ }
+
+ override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
+ if (findNavController().currentDestination?.id == R.id.startCallFragment) {
+ // Holds fragment in place while new contact fragment slides over it
+ return AnimationUtils.loadAnimation(activity, R.anim.hold)
+ }
+ return super.onCreateAnimation(transit, enter, nextAnim)
+ }
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -130,8 +148,14 @@ class HistoryListFragment : AbstractTopBarFragment() {
adapter.callLogClickedEvent.observe(viewLifecycleOwner) {
it.consume { model ->
- Log.i("$TAG Show details for call log with ID [${model.id}]")
- sharedViewModel.showCallLogEvent.value = Event(model.id ?: "")
+ val uri = model.id
+ Log.i("$TAG Show details for call log with ID [$uri]")
+ if (!uri.isNullOrEmpty()) {
+ val navController = binding.historyNavContainer.findNavController()
+ val action =
+ HistoryContactFragmentDirections.actionGlobalHistoryContactFragment(uri)
+ navController.navigate(action)
+ }
}
}
@@ -155,7 +179,7 @@ class HistoryListFragment : AbstractTopBarFragment() {
(view.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
- sharedViewModel.historyReadyEvent.value = Event(true)
+ sharedViewModel.isFirstFragmentReady = true
}
}
@@ -180,7 +204,12 @@ class HistoryListFragment : AbstractTopBarFragment() {
}
binding.setStartCallClickListener {
- sharedViewModel.showStartCallEvent.value = Event(true)
+ if (findNavController().currentDestination?.id == R.id.historyListFragment) {
+ Log.i("$TAG Navigating to start call fragment")
+ val action =
+ HistoryListFragmentDirections.actionHistoryListFragmentToStartCallFragment()
+ findNavController().navigate(action)
+ }
}
// TopBarFragment related
@@ -191,20 +220,11 @@ class HistoryListFragment : AbstractTopBarFragment() {
getString(R.string.bottom_navigation_calls_label)
)
- binding.root.setKeyboardInsetListener { keyboardVisible ->
- val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE
- binding.bottomNavBar.root.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE
- }
+ initBottomNavBar(binding.bottomNavBar.root)
- sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) {
- it.consume {
- Log.i(
- "$TAG Default account changed, updating avatar in top bar & re-computing call logs"
- )
- listViewModel.update()
- listViewModel.applyFilter()
- }
- }
+ initSlidingPane(binding.slidingPaneLayout)
+
+ initNavigation(R.id.historyListFragment)
}
override fun onResume() {
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 caffb64d0..83512dedb 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
@@ -66,7 +66,7 @@ class MeetingFragment : GenericFragment() {
override fun goBack(): Boolean {
sharedViewModel.closeSlidingPaneEvent.value = Event(true)
- // If not done, when going back to ConversationsFragment this fragment will be created again
+ // If not done, when going back to MeetingsListFragment this fragment will be created again
return findNavController().popBackStack()
}
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsFragment.kt
deleted file mode 100644
index c6133b063..000000000
--- a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsFragment.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2010-2023 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.ui.main.meetings.fragment
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.view.animation.Animation
-import android.view.animation.AnimationUtils
-import androidx.annotation.UiThread
-import androidx.core.view.doOnPreDraw
-import androidx.navigation.findNavController
-import androidx.navigation.fragment.findNavController
-import androidx.slidingpanelayout.widget.SlidingPaneLayout
-import org.linphone.R
-import org.linphone.core.tools.Log
-import org.linphone.databinding.MeetingsFragmentBinding
-import org.linphone.ui.main.fragment.GenericFragment
-import org.linphone.utils.SlidingPaneBackPressedCallback
-
-@UiThread
-class MeetingsFragment : GenericFragment() {
- companion object {
- private const val TAG = "[Meetings Fragment]"
- }
-
- private lateinit var binding: MeetingsFragmentBinding
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- binding = MeetingsFragmentBinding.inflate(layoutInflater)
- return binding.root
- }
-
- override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
- if (
- findNavController().currentDestination?.id == R.id.scheduleMeetingFragment ||
- findNavController().currentDestination?.id == R.id.meetingWaitingRoomFragment
- ) {
- // Holds fragment in place while new contact fragment slides over it
- return AnimationUtils.loadAnimation(activity, R.anim.hold)
- }
- return super.onCreateAnimation(transit, enter, nextAnim)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- postponeEnterTransition()
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- binding.root.doOnPreDraw {
- val slidingPane = binding.slidingPaneLayout
- slidingPane.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
-
- sharedViewModel.isSlidingPaneSlideable.value = slidingPane.isSlideable
-
- requireActivity().onBackPressedDispatcher.addCallback(
- viewLifecycleOwner,
- SlidingPaneBackPressedCallback(slidingPane)
- )
- }
-
- sharedViewModel.meetingsReadyEvent.observe(viewLifecycleOwner) {
- it.consume {
- (view.parent as? ViewGroup)?.doOnPreDraw {
- startPostponedEnterTransition()
- sharedViewModel.isFirstFragmentReady = true
- }
- }
- }
-
- sharedViewModel.closeSlidingPaneEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- if (binding.slidingPaneLayout.isOpen) {
- Log.i("$TAG Closing sliding pane")
- binding.slidingPaneLayout.closePane()
- }
- }
- }
-
- sharedViewModel.openSlidingPaneEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- if (!binding.slidingPaneLayout.isOpen) {
- Log.i("$TAG Opening sliding pane")
- binding.slidingPaneLayout.openPane()
- }
- }
- }
-
- sharedViewModel.showScheduleMeetingEvent.observe(viewLifecycleOwner) {
- it.consume {
- Log.i("$TAG Navigating to schedule meeting fragment")
- val action = MeetingsFragmentDirections.actionMeetingsFragmentToScheduleMeetingFragment()
- findNavController().navigate(action)
- }
- }
-
- sharedViewModel.goToMeetingWaitingRoomEvent.observe(viewLifecycleOwner) {
- it.consume { uri ->
- Log.i("$TAG Navigating to meeting waiting room fragment with URI [$uri]")
- val action = MeetingsFragmentDirections.actionMeetingsFragmentToMeetingWaitingRoomFragment(
- uri
- )
- findNavController().navigate(action)
- }
- }
-
- sharedViewModel.showMeetingEvent.observe(viewLifecycleOwner) {
- it.consume { uri ->
- Log.i("$TAG Navigating to meeting fragment with URI [$uri]")
- val action = MeetingFragmentDirections.actionGlobalMeetingFragment(uri)
- binding.meetingsNavContainer.findNavController().navigate(action)
- }
- }
-
- sharedViewModel.navigateToContactsEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.meetingsFragment) {
- // To prevent any previously seen meeting to show up when navigating back to here later
- binding.meetingsNavContainer.findNavController().popBackStack()
-
- val action = MeetingsFragmentDirections.actionMeetingsFragmentToContactsFragment()
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.navigateToHistoryEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.meetingsFragment) {
- // To prevent any previously seen meeting to show up when navigating back to here later
- binding.meetingsNavContainer.findNavController().popBackStack()
-
- val action = MeetingsFragmentDirections.actionMeetingsFragmentToHistoryFragment()
- findNavController().navigate(action)
- }
- }
- }
-
- sharedViewModel.navigateToConversationsEvent.observe(viewLifecycleOwner) {
- it.consume {
- if (findNavController().currentDestination?.id == R.id.meetingsFragment) {
- // To prevent any previously seen meeting to show up when navigating back to here later
- binding.meetingsNavContainer.findNavController().popBackStack()
-
- val action = MeetingsFragmentDirections.actionMeetingsFragmentToConversationsFragment()
- findNavController().navigate(action)
- }
- }
- }
- }
-
- override fun onResume() {
- super.onResume()
- sharedViewModel.currentlyDisplayedFragment.value = R.id.meetingsFragment
- }
-}
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsListFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsListFragment.kt
index 8b0f3497d..f14bad2ca 100644
--- a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsListFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingsListFragment.kt
@@ -19,14 +19,17 @@
*/
package org.linphone.ui.main.meetings.fragment
-import android.content.res.Configuration
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.view.animation.Animation
+import android.view.animation.AnimationUtils
import androidx.annotation.UiThread
import androidx.core.view.doOnPreDraw
import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.findNavController
+import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import org.linphone.R
import org.linphone.core.tools.Log
@@ -35,9 +38,7 @@ import org.linphone.ui.main.fragment.AbstractTopBarFragment
import org.linphone.ui.main.meetings.adapter.MeetingsListAdapter
import org.linphone.ui.main.meetings.viewmodel.MeetingsListViewModel
import org.linphone.utils.AppUtils
-import org.linphone.utils.Event
import org.linphone.utils.RecyclerViewHeaderDecoration
-import org.linphone.utils.setKeyboardInsetListener
@UiThread
class MeetingsListFragment : AbstractTopBarFragment() {
@@ -51,6 +52,24 @@ class MeetingsListFragment : AbstractTopBarFragment() {
private lateinit var adapter: MeetingsListAdapter
+ override fun onDefaultAccountChanged() {
+ Log.i(
+ "$TAG Default account changed, updating avatar in top bar & re-computing meetings list"
+ )
+ listViewModel.applyFilter()
+ }
+
+ override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
+ if (
+ findNavController().currentDestination?.id == R.id.scheduleMeetingFragment ||
+ findNavController().currentDestination?.id == R.id.meetingWaitingRoomFragment
+ ) {
+ // Holds fragment in place while new contact fragment slides over it
+ return AnimationUtils.loadAnimation(activity, R.anim.hold)
+ }
+ return super.onCreateAnimation(transit, enter, nextAnim)
+ }
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -78,7 +97,12 @@ class MeetingsListFragment : AbstractTopBarFragment() {
binding.meetingsList.layoutManager = LinearLayoutManager(requireContext())
binding.setNewMeetingClicked {
- sharedViewModel.showScheduleMeetingEvent.value = Event(true)
+ if (findNavController().currentDestination?.id == R.id.meetingsListFragment) {
+ Log.i("$TAG Navigating to schedule meeting fragment")
+ val action =
+ MeetingsListFragmentDirections.actionMeetingsListFragmentToScheduleMeetingFragment()
+ findNavController().navigate(action)
+ }
}
binding.setTodayClickListener {
@@ -88,7 +112,8 @@ class MeetingsListFragment : AbstractTopBarFragment() {
adapter.meetingClickedEvent.observe(viewLifecycleOwner) {
it.consume { model ->
Log.i("$TAG Show conversation with ID [${model.id}]")
- sharedViewModel.showMeetingEvent.value = Event(model.id)
+ val action = MeetingFragmentDirections.actionGlobalMeetingFragment(model.id)
+ binding.meetingsNavContainer.findNavController().navigate(action)
}
}
@@ -100,7 +125,7 @@ class MeetingsListFragment : AbstractTopBarFragment() {
if (currentCount < it.size) {
(view.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
- sharedViewModel.meetingsReadyEvent.value = Event(true)
+ sharedViewModel.isFirstFragmentReady = true
scrollToToday()
}
}
@@ -113,6 +138,19 @@ class MeetingsListFragment : AbstractTopBarFragment() {
}
}
+ sharedViewModel.goToMeetingWaitingRoomEvent.observe(viewLifecycleOwner) {
+ it.consume { uri ->
+ if (findNavController().currentDestination?.id == R.id.meetingsListFragment) {
+ Log.i("$TAG Navigating to meeting waiting room fragment with URI [$uri]")
+ val action =
+ MeetingsListFragmentDirections.actionMeetingsListFragmentToMeetingWaitingRoomFragment(
+ uri
+ )
+ findNavController().navigate(action)
+ }
+ }
+ }
+
// TopBarFragment related
setViewModelAndTitle(
@@ -121,19 +159,11 @@ class MeetingsListFragment : AbstractTopBarFragment() {
getString(R.string.bottom_navigation_meetings_label)
)
- binding.root.setKeyboardInsetListener { keyboardVisible ->
- val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE
- binding.bottomNavBar.root.visibility = if (!portraitOrientation || !keyboardVisible) View.VISIBLE else View.GONE
- }
+ initBottomNavBar(binding.bottomNavBar.root)
- sharedViewModel.defaultAccountChangedEvent.observe(viewLifecycleOwner) {
- it.consume {
- Log.i(
- "$TAG Default account changed, updating avatar in top bar & re-computing meetings list"
- )
- listViewModel.applyFilter()
- }
- }
+ initSlidingPane(binding.slidingPaneLayout)
+
+ initNavigation(R.id.meetingsListFragment)
}
private fun scrollToToday() {
diff --git a/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt b/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt
index f1127ffdd..6bc11c5d7 100644
--- a/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt
+++ b/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt
@@ -76,8 +76,6 @@ class SharedMainViewModel @UiThread constructor() : ViewModel() {
/* Contacts related */
- val contactsReadyEvent = MutableLiveData>()
-
val showContactEvent: MutableLiveData> by lazy {
MutableLiveData>()
}
@@ -90,16 +88,6 @@ class SharedMainViewModel @UiThread constructor() : ViewModel() {
/* Call logs related */
- val historyReadyEvent = MutableLiveData>()
-
- val showStartCallEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val showCallLogEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
val forceRefreshCallLogsListEvent: MutableLiveData> by lazy {
MutableLiveData>()
}
@@ -110,12 +98,6 @@ class SharedMainViewModel @UiThread constructor() : ViewModel() {
/* Conversation related */
- val conversationsReadyEvent = MutableLiveData>()
-
- val showStartConversationEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
val filesToShareFromIntent = MutableLiveData>()
var displayedChatRoom: ChatRoom? = null // Prevents the need to go look for the chat room
@@ -128,16 +110,6 @@ class SharedMainViewModel @UiThread constructor() : ViewModel() {
/* Meetings related */
- val meetingsReadyEvent = MutableLiveData>()
-
- val showScheduleMeetingEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val showMeetingEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
val forceRefreshMeetingsListEvent: MutableLiveData> by lazy {
MutableLiveData>()
}
diff --git a/app/src/main/res/layout-land/chat_list_fragment.xml b/app/src/main/res/layout-land/chat_list_fragment.xml
index 01248af56..216b9cc34 100644
--- a/app/src/main/res/layout-land/chat_list_fragment.xml
+++ b/app/src/main/res/layout-land/chat_list_fragment.xml
@@ -16,107 +16,123 @@
type="org.linphone.ui.main.chat.viewmodel.ConversationsListViewModel" />
-
-
+ android:layout_height="match_parent">
-
-
-
+ android:background="@color/orange_main_500">
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/contacts_list_fragment.xml b/app/src/main/res/layout-land/contacts_list_fragment.xml
index 4b1813777..6e252c324 100644
--- a/app/src/main/res/layout-land/contacts_list_fragment.xml
+++ b/app/src/main/res/layout-land/contacts_list_fragment.xml
@@ -16,162 +16,178 @@
type="org.linphone.ui.main.contacts.viewmodel.ContactsListViewModel" />
-
-
+ android:layout_height="match_parent">
-
-
-
+ android:background="@color/orange_main_500">
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/history_list_fragment.xml b/app/src/main/res/layout-land/history_list_fragment.xml
index 18cb55905..ffd272aba 100644
--- a/app/src/main/res/layout-land/history_list_fragment.xml
+++ b/app/src/main/res/layout-land/history_list_fragment.xml
@@ -22,120 +22,136 @@
type="org.linphone.ui.main.history.viewmodel.HistoryListViewModel" />
-
-
+ android:layout_height="match_parent">
-
-
-
+ android:background="@color/orange_main_500">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ layout="@layout/operation_in_progress"
+ bind:visibility="@{viewModel.fetchInProgress}" />
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/meetings_list_fragment.xml b/app/src/main/res/layout-land/meetings_list_fragment.xml
index ba2b7629c..5c01d8ed4 100644
--- a/app/src/main/res/layout-land/meetings_list_fragment.xml
+++ b/app/src/main/res/layout-land/meetings_list_fragment.xml
@@ -19,120 +19,136 @@
type="org.linphone.ui.main.meetings.viewmodel.MeetingsListViewModel" />
-
-
+ android:layout_height="match_parent">
-
-
-
+ android:background="@color/orange_main_500">
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/chat_fragment.xml b/app/src/main/res/layout/chat_fragment.xml
deleted file mode 100644
index c842ffcc0..000000000
--- a/app/src/main/res/layout/chat_fragment.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/chat_list_fragment.xml b/app/src/main/res/layout/chat_list_fragment.xml
index 0d2287a2d..d2764a69b 100644
--- a/app/src/main/res/layout/chat_list_fragment.xml
+++ b/app/src/main/res/layout/chat_list_fragment.xml
@@ -16,107 +16,123 @@
type="org.linphone.ui.main.chat.viewmodel.ConversationsListViewModel" />
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ app:defaultNavHost="false"
+ app:navGraph="@navigation/chat_nav_graph"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/contacts_fragment.xml b/app/src/main/res/layout/contacts_fragment.xml
deleted file mode 100644
index 62ffef7f3..000000000
--- a/app/src/main/res/layout/contacts_fragment.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/contacts_list_fragment.xml b/app/src/main/res/layout/contacts_list_fragment.xml
index 48783f863..8a89d2924 100644
--- a/app/src/main/res/layout/contacts_list_fragment.xml
+++ b/app/src/main/res/layout/contacts_list_fragment.xml
@@ -16,164 +16,180 @@
type="org.linphone.ui.main.contacts.viewmodel.ContactsListViewModel" />
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ app:defaultNavHost="false"
+ app:navGraph="@navigation/contacts_nav_graph"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/history_fragment.xml b/app/src/main/res/layout/history_fragment.xml
deleted file mode 100644
index b31826fac..000000000
--- a/app/src/main/res/layout/history_fragment.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/history_list_fragment.xml b/app/src/main/res/layout/history_list_fragment.xml
index d8b55aa5b..f89116411 100644
--- a/app/src/main/res/layout/history_list_fragment.xml
+++ b/app/src/main/res/layout/history_list_fragment.xml
@@ -22,120 +22,136 @@
type="org.linphone.ui.main.history.viewmodel.HistoryListViewModel" />
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ app:defaultNavHost="false"
+ app:navGraph="@navigation/history_nav_graph"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/meetings_fragment.xml b/app/src/main/res/layout/meetings_fragment.xml
deleted file mode 100644
index 9ce57120b..000000000
--- a/app/src/main/res/layout/meetings_fragment.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/meetings_list_fragment.xml b/app/src/main/res/layout/meetings_list_fragment.xml
index 74f0dcedd..41ad2e65e 100644
--- a/app/src/main/res/layout/meetings_list_fragment.xml
+++ b/app/src/main/res/layout/meetings_list_fragment.xml
@@ -19,120 +19,136 @@
type="org.linphone.ui.main.meetings.viewmodel.MeetingsListViewModel" />
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ app:defaultNavHost="false"
+ app:navGraph="@navigation/meetings_nav_graph"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml
index a461b8a87..72fe2929a 100644
--- a/app/src/main/res/navigation/main_nav_graph.xml
+++ b/app/src/main/res/navigation/main_nav_graph.xml
@@ -1,36 +1,35 @@
-
+ app:startDestination="@id/historyListFragment">
+ android:id="@+id/contactsListFragment"
+ android:name="org.linphone.ui.main.contacts.fragment.ContactsListFragment"
+ android:label="ContactsListFragment"
+ tools:layout="@layout/contacts_list_fragment">
+ android:id="@+id/historyListFragment"
+ android:name="org.linphone.ui.main.history.fragment.HistoryListFragment"
+ android:label="HistoryListFragment"
+ tools:layout="@layout/history_list_fragment">
+ android:id="@+id/conversationsListFragment"
+ android:name="org.linphone.ui.main.chat.fragment.ConversationsListFragment"
+ android:label="ConversationsListFragment"
+ tools:layout="@layout/chat_list_fragment" >
+ android:id="@+id/meetingsListFragment"
+ android:name="org.linphone.ui.main.meetings.fragment.MeetingsListFragment"
+ android:label="MeetingsListFragment"
+ tools:layout="@layout/meetings_list_fragment">
-
- 450dp
- 0dp
-
110dp
125dp
235dp
diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml
index 0cdc33642..05290e043 100644
--- a/app/src/main/res/values/dimen.xml
+++ b/app/src/main/res/values/dimen.xml
@@ -5,7 +5,6 @@
32dp
75dp
- 300dp
300dp
14dp