diff --git a/app/src/main/java/org/linphone/ui/contacts/ContactFragment.kt b/app/src/main/java/org/linphone/ui/contacts/ContactFragment.kt index da9649eee..1918eb72a 100644 --- a/app/src/main/java/org/linphone/ui/contacts/ContactFragment.kt +++ b/app/src/main/java/org/linphone/ui/contacts/ContactFragment.kt @@ -33,6 +33,7 @@ import org.linphone.R import org.linphone.databinding.ContactFragmentBinding import org.linphone.ui.contacts.viewmodel.ContactViewModel import org.linphone.ui.viewmodel.SharedMainViewModel +import org.linphone.utils.Event class ContactFragment : Fragment() { private lateinit var binding: ContactFragmentBinding @@ -76,7 +77,7 @@ class ContactFragment : Fragment() { viewModel.findContactByRefKey(refKey) binding.setBackClickListener { - requireActivity().onBackPressedDispatcher.onBackPressed() + sharedViewModel.closeSlidingPaneEvent.value = Event(true) } sharedViewModel.isSlidingPaneSlideable.observe(viewLifecycleOwner) { slideable -> diff --git a/app/src/main/java/org/linphone/ui/contacts/ContactsFragment.kt b/app/src/main/java/org/linphone/ui/contacts/ContactsFragment.kt index 9dc80145f..f41459f0e 100644 --- a/app/src/main/java/org/linphone/ui/contacts/ContactsFragment.kt +++ b/app/src/main/java/org/linphone/ui/contacts/ContactsFragment.kt @@ -19,53 +19,27 @@ */ package org.linphone.ui.contacts -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.core.view.doOnPreDraw import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider -import androidx.navigation.fragment.FragmentNavigatorExtras -import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController -import androidx.navigation.navGraphViewModels -import androidx.recyclerview.widget.LinearLayoutManager import androidx.slidingpanelayout.widget.SlidingPaneLayout import androidx.transition.AutoTransition import org.linphone.R import org.linphone.databinding.ContactsFragmentBinding -import org.linphone.ui.MainActivity -import org.linphone.ui.contacts.adapter.ContactsListAdapter -import org.linphone.ui.contacts.viewmodel.ContactsListViewModel import org.linphone.ui.viewmodel.SharedMainViewModel import org.linphone.utils.SlidingPaneBackPressedCallback -import org.linphone.utils.hideKeyboard -import org.linphone.utils.setKeyboardInsetListener -import org.linphone.utils.showKeyboard class ContactsFragment : Fragment() { private lateinit var binding: ContactsFragmentBinding private lateinit var sharedViewModel: SharedMainViewModel - private val listViewModel: ContactsListViewModel by navGraphViewModels( - R.id.contactsFragment - ) - - private lateinit var adapter: ContactsListAdapter - - 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 onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -84,15 +58,7 @@ class ContactsFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - postponeEnterTransition() - binding.lifecycleOwner = viewLifecycleOwner - binding.viewModel = listViewModel - - binding.root.setKeyboardInsetListener { keyboardVisible -> - val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE - listViewModel.bottomNavBarVisible.value = !portraitOrientation || !keyboardVisible - } binding.root.doOnPreDraw { val slidingPane = binding.slidingPaneLayout @@ -107,85 +73,39 @@ class ContactsFragment : Fragment() { slidingPane.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED } - adapter = ContactsListAdapter(viewLifecycleOwner) - binding.contactsView.contactsList.setHasFixedSize(true) - binding.contactsView.contactsList.adapter = adapter - - adapter.contactLongClickedEvent.observe(viewLifecycleOwner) { - it.consume { model -> - val modalBottomSheet = ContactsListMenuDialogFragment(model.friend) { - adapter.resetSelection() - } - modalBottomSheet.show(parentFragmentManager, ContactsListMenuDialogFragment.TAG) - } - } - - adapter.contactClickedEvent.observe(viewLifecycleOwner) { - it.consume { model -> - if (findNavController().currentDestination?.id == R.id.contactsFragment) { - val navHostFragment = childFragmentManager.findFragmentById( - R.id.contacts_nav_container - ) as NavHostFragment - val action = ContactFragmentDirections.actionGlobalContactFragment( - model.id ?: "" - ) - navHostFragment.navController.navigate(action) - - if (!binding.slidingPaneLayout.isOpen) { - binding.slidingPaneLayout.openPane() - } - } - } - } - - val layoutManager = LinearLayoutManager(requireContext()) - binding.contactsView.contactsList.layoutManager = layoutManager - - listViewModel.contactsList.observe( + sharedViewModel.closeSlidingPaneEvent.observe( viewLifecycleOwner ) { - adapter.submitList(it) - - (view.parent as? ViewGroup)?.doOnPreDraw { - startPostponedEnterTransition() - } - } - - listViewModel.searchFilter.observe( - viewLifecycleOwner - ) { - listViewModel.applyFilter() - } - - listViewModel.focusSearchBarEvent.observe(viewLifecycleOwner) { - it.consume { show -> - if (show) { - // To automatically open keyboard - binding.topBar.search.showKeyboard(requireActivity().window) - } else { - binding.topBar.search.hideKeyboard() + it.consume { close -> + if (close) { + binding.slidingPaneLayout.closePane() } } } - binding.setOnNewContactClicked { - if (findNavController().currentDestination?.id == R.id.contactsFragment) { - findNavController().navigate(R.id.action_contactsFragment_to_newContactFragment) - } - } - - binding.setOnConversationsClicked { - if (findNavController().currentDestination?.id == R.id.contactsFragment) { - val extras = FragmentNavigatorExtras( - binding.bottomNavBar.root to "bottom_nav_bar" + sharedViewModel.showContactEvent.observe( + viewLifecycleOwner + ) { + it.consume { refKey -> + val navController = binding.contactsRightNavContainer.findNavController() + val action = ContactFragmentDirections.actionGlobalContactFragment( + refKey ) - val action = ContactsFragmentDirections.actionContactsFragmentToConversationsFragment() - findNavController().navigate(action, extras) + navController.navigate(action) + + if (!binding.slidingPaneLayout.isOpen) { + binding.slidingPaneLayout.openPane() + } } } - binding.setOnAvatarClickListener { - (requireActivity() as MainActivity).toggleDrawerMenu() + sharedViewModel.navigateToConversationsEvent.observe(viewLifecycleOwner) { + it.consume { + if (findNavController().currentDestination?.id == R.id.contactsFragment) { + val action = ContactsFragmentDirections.actionContactsFragmentToConversationsFragment() + findNavController().navigate(action) + } + } } } } diff --git a/app/src/main/java/org/linphone/ui/contacts/ContactsListFragment.kt b/app/src/main/java/org/linphone/ui/contacts/ContactsListFragment.kt new file mode 100644 index 000000000..ddcb53053 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/contacts/ContactsListFragment.kt @@ -0,0 +1,153 @@ +/* + * 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.contacts + +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.core.view.doOnPreDraw +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController +import androidx.navigation.navGraphViewModels +import androidx.recyclerview.widget.LinearLayoutManager +import org.linphone.R +import org.linphone.databinding.ContactsListFragmentBinding +import org.linphone.ui.MainActivity +import org.linphone.ui.contacts.adapter.ContactsListAdapter +import org.linphone.ui.contacts.viewmodel.ContactsListViewModel +import org.linphone.ui.viewmodel.SharedMainViewModel +import org.linphone.utils.Event +import org.linphone.utils.hideKeyboard +import org.linphone.utils.setKeyboardInsetListener +import org.linphone.utils.showKeyboard + +class ContactsListFragment : Fragment() { + private lateinit var binding: ContactsListFragmentBinding + + private lateinit var sharedViewModel: SharedMainViewModel + + private val listViewModel: ContactsListViewModel by navGraphViewModels( + R.id.contactsListFragment + ) + + private lateinit var adapter: ContactsListAdapter + + 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 onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = ContactsListFragmentBinding.inflate(layoutInflater) + + sharedViewModel = requireActivity().run { + ViewModelProvider(this)[SharedMainViewModel::class.java] + } + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + postponeEnterTransition() + + binding.lifecycleOwner = viewLifecycleOwner + binding.viewModel = listViewModel + + binding.root.setKeyboardInsetListener { keyboardVisible -> + val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE + listViewModel.bottomNavBarVisible.value = !portraitOrientation || !keyboardVisible + } + + adapter = ContactsListAdapter(viewLifecycleOwner) + binding.contactsList.setHasFixedSize(true) + binding.contactsList.adapter = adapter + + adapter.contactLongClickedEvent.observe(viewLifecycleOwner) { + it.consume { model -> + val modalBottomSheet = ContactsListMenuDialogFragment(model.friend) { + adapter.resetSelection() + } + modalBottomSheet.show(parentFragmentManager, ContactsListMenuDialogFragment.TAG) + } + } + + adapter.contactClickedEvent.observe(viewLifecycleOwner) { + it.consume { model -> + sharedViewModel.showContactEvent.value = Event(model.id ?: "") + } + } + + val layoutManager = LinearLayoutManager(requireContext()) + binding.contactsList.layoutManager = layoutManager + + listViewModel.contactsList.observe( + viewLifecycleOwner + ) { + adapter.submitList(it) + + (view.parent as? ViewGroup)?.doOnPreDraw { + startPostponedEnterTransition() + } + } + + listViewModel.focusSearchBarEvent.observe(viewLifecycleOwner) { + it.consume { show -> + if (show) { + // To automatically open keyboard + binding.topBar.search.showKeyboard(requireActivity().window) + } else { + binding.topBar.search.hideKeyboard() + } + } + } + + listViewModel.searchFilter.observe(viewLifecycleOwner) { filter -> + listViewModel.applyFilter(filter) + } + + binding.setOnNewContactClicked { + if (findNavController().currentDestination?.id == R.id.contactsListFragment) { + findNavController().navigate(R.id.action_contactsListFragment_to_newContactFragment) + } + } + + binding.setOnConversationsClicked { + sharedViewModel.navigateToConversationsEvent.value = Event(true) + } + + binding.setOnAvatarClickListener { + (requireActivity() as MainActivity).toggleDrawerMenu() + } + } +} diff --git a/app/src/main/java/org/linphone/ui/contacts/NewContactFragment.kt b/app/src/main/java/org/linphone/ui/contacts/NewContactFragment.kt index c4a6329dc..0f273c446 100644 --- a/app/src/main/java/org/linphone/ui/contacts/NewContactFragment.kt +++ b/app/src/main/java/org/linphone/ui/contacts/NewContactFragment.kt @@ -25,6 +25,7 @@ import android.view.View import android.view.ViewGroup import android.view.animation.Animation import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController import org.linphone.databinding.NewContactFragmentBinding class NewContactFragment : Fragment() { @@ -55,7 +56,7 @@ class NewContactFragment : Fragment() { // postponeEnterTransition() binding.setCancelClickListener { - requireActivity().onBackPressedDispatcher.onBackPressed() + findNavController().popBackStack() } /*(view.parent as? ViewGroup)?.doOnPreDraw { diff --git a/app/src/main/java/org/linphone/ui/contacts/viewmodel/ContactsListViewModel.kt b/app/src/main/java/org/linphone/ui/contacts/viewmodel/ContactsListViewModel.kt index 25a8098e7..72e05fba2 100644 --- a/app/src/main/java/org/linphone/ui/contacts/viewmodel/ContactsListViewModel.kt +++ b/app/src/main/java/org/linphone/ui/contacts/viewmodel/ContactsListViewModel.kt @@ -25,40 +25,57 @@ import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.contacts.ContactsListener import org.linphone.core.Friend import org.linphone.core.MagicSearch +import org.linphone.core.MagicSearchListenerStub import org.linphone.core.SearchResult import org.linphone.core.tools.Log import org.linphone.ui.contacts.model.ContactModel import org.linphone.ui.viewmodel.TopBarViewModel class ContactsListViewModel : TopBarViewModel() { - val bottomNavBarVisible = MutableLiveData() - val contactsList = MutableLiveData>() + private var currentFilter = "" + private var previousFilter = "NotSet" + + private lateinit var magicSearch: MagicSearch + + private val magicSearchListener = object : MagicSearchListenerStub() { + override fun onSearchResultsReceived(magicSearch: MagicSearch) { + // Core thread + Log.i("[Contacts] Magic search contacts available") + processMagicSearchResults(magicSearch.lastSearch) + } + } + private val contactsListener = object : ContactsListener { override fun onContactsLoaded() { // Core thread - applyFilter() + applyFilter(currentFilter) } } init { title.value = "Contacts" bottomNavBarVisible.value = true - coreContext.postOnCoreThread { + + coreContext.postOnCoreThread { core -> coreContext.contactsManager.addListener(contactsListener) + magicSearch = core.createMagicSearch() + magicSearch.limitedSearch = false + magicSearch.addListener(magicSearchListener) } - applyFilter() + applyFilter(currentFilter) } override fun onCleared() { coreContext.postOnCoreThread { + magicSearch.removeListener(magicSearchListener) coreContext.contactsManager.removeListener(contactsListener) } super.onCleared() } - override fun processMagicSearchResults(results: Array) { + fun processMagicSearchResults(results: Array) { // Core thread Log.i("[Contacts List] Processing ${results.size} results") contactsList.value.orEmpty().forEach(ContactModel::destroy) @@ -85,9 +102,11 @@ class ContactsListViewModel : TopBarViewModel() { Log.i("[Contacts] Processed ${results.size} results") } - fun applyFilter() { + fun applyFilter(filter: String) { + // UI thread coreContext.postOnCoreThread { applyFilter( + filter, "", MagicSearch.Source.Friends.toInt(), MagicSearch.Aggregation.Friend @@ -95,6 +114,34 @@ class ContactsListViewModel : TopBarViewModel() { } } + private fun applyFilter( + filter: String, + domain: String, + sources: Int, + aggregation: MagicSearch.Aggregation + ) { + // Core thread + if (previousFilter.isNotEmpty() && ( + previousFilter.length > filter.length || + (previousFilter.length == filter.length && previousFilter != filter) + ) + ) { + magicSearch.resetSearchCache() + } + currentFilter = filter + previousFilter = filter + + Log.i( + "[Contacts] Asking Magic search for contacts matching filter [$filter], domain [$domain] and in sources [$sources]" + ) + magicSearch.getContactsListAsync( + filter, + domain, + sources, + aggregation + ) + } + private fun createFriendFromSearchResult(searchResult: SearchResult): Friend { // Core thread val searchResultFriend = searchResult.friend diff --git a/app/src/main/java/org/linphone/ui/conversations/ConversationsFragment.kt b/app/src/main/java/org/linphone/ui/conversations/ConversationsFragment.kt index b36cb7093..fd6b22559 100644 --- a/app/src/main/java/org/linphone/ui/conversations/ConversationsFragment.kt +++ b/app/src/main/java/org/linphone/ui/conversations/ConversationsFragment.kt @@ -166,11 +166,8 @@ class ConversationsFragment : Fragment() { binding.setOnContactsClicked { if (findNavController().currentDestination?.id == R.id.conversationsFragment) { - val extras = FragmentNavigatorExtras( - binding.bottomNavBar.root to "bottom_nav_bar" - ) val action = ConversationsFragmentDirections.actionConversationsFragmentToContactsFragment() - findNavController().navigate(action, extras) + findNavController().navigate(action) } } } diff --git a/app/src/main/java/org/linphone/ui/conversations/viewmodel/ConversationsListViewModel.kt b/app/src/main/java/org/linphone/ui/conversations/viewmodel/ConversationsListViewModel.kt index e6b5dfaf2..6ec39c850 100644 --- a/app/src/main/java/org/linphone/ui/conversations/viewmodel/ConversationsListViewModel.kt +++ b/app/src/main/java/org/linphone/ui/conversations/viewmodel/ConversationsListViewModel.kt @@ -27,7 +27,6 @@ import org.linphone.core.ChatMessage import org.linphone.core.ChatRoom import org.linphone.core.Core import org.linphone.core.CoreListenerStub -import org.linphone.core.SearchResult import org.linphone.core.tools.Log import org.linphone.ui.conversations.data.ChatRoomData import org.linphone.ui.viewmodel.TopBarViewModel @@ -114,10 +113,6 @@ class ConversationsListViewModel : TopBarViewModel() { super.onCleared() } - override fun processMagicSearchResults(results: Array) { - TODO("Not yet implemented") - } - private fun addChatRoomToList(chatRoom: ChatRoom) { val index = findChatRoomIndex(chatRoom) if (index != -1) { diff --git a/app/src/main/java/org/linphone/ui/viewmodel/SharedMainViewModel.kt b/app/src/main/java/org/linphone/ui/viewmodel/SharedMainViewModel.kt index f30268e95..6ac3a1e7f 100644 --- a/app/src/main/java/org/linphone/ui/viewmodel/SharedMainViewModel.kt +++ b/app/src/main/java/org/linphone/ui/viewmodel/SharedMainViewModel.kt @@ -21,7 +21,18 @@ package org.linphone.ui.viewmodel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import org.linphone.utils.Event class SharedMainViewModel : ViewModel() { + /* Sliding Pane & navigation related */ + val isSlidingPaneSlideable = MutableLiveData() + + val closeSlidingPaneEvent = MutableLiveData>() + + val navigateToConversationsEvent = MutableLiveData>() + + /* Contacts related */ + + val showContactEvent = MutableLiveData>() } diff --git a/app/src/main/java/org/linphone/ui/viewmodel/TopBarViewModel.kt b/app/src/main/java/org/linphone/ui/viewmodel/TopBarViewModel.kt index 42f9c2e2b..24188cdc9 100644 --- a/app/src/main/java/org/linphone/ui/viewmodel/TopBarViewModel.kt +++ b/app/src/main/java/org/linphone/ui/viewmodel/TopBarViewModel.kt @@ -21,11 +21,6 @@ package org.linphone.ui.viewmodel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import org.linphone.LinphoneApplication.Companion.coreContext -import org.linphone.core.MagicSearch -import org.linphone.core.MagicSearchListenerStub -import org.linphone.core.SearchResult -import org.linphone.core.tools.Log import org.linphone.utils.Event abstract class TopBarViewModel : ViewModel() { @@ -39,31 +34,13 @@ abstract class TopBarViewModel : ViewModel() { MutableLiveData>() } - private var previousFilter = "NotSet" - - private lateinit var magicSearch: MagicSearch - - private val magicSearchListener = object : MagicSearchListenerStub() { - override fun onSearchResultsReceived(magicSearch: MagicSearch) { - // Core thread - Log.i("[Contacts] Magic search contacts available") - processMagicSearchResults(magicSearch.lastSearch) - } - } + val bottomNavBarVisible = MutableLiveData() init { searchBarVisible.value = false - coreContext.postOnCoreThread { core -> - magicSearch = core.createMagicSearch() - magicSearch.limitedSearch = false - magicSearch.addListener(magicSearchListener) - } } override fun onCleared() { - coreContext.postOnCoreThread { core -> - magicSearch.removeListener(magicSearchListener) - } super.onCleared() } @@ -83,29 +60,4 @@ abstract class TopBarViewModel : ViewModel() { // UI thread searchFilter.value = "" } - - fun applyFilter(domain: String, sources: Int, aggregation: MagicSearch.Aggregation) { - // Core thread - val filterValue = searchFilter.value.orEmpty() - if (previousFilter.isNotEmpty() && ( - previousFilter.length > filterValue.length || - (previousFilter.length == filterValue.length && previousFilter != filterValue) - ) - ) { - magicSearch.resetSearchCache() - } - previousFilter = filterValue - - Log.i( - "[Contacts] Asking Magic search for contacts matching filter [$filterValue], domain [$domain] and in sources [$sources]" - ) - magicSearch.getContactsListAsync( - filterValue, - domain, - sources, - aggregation - ) - } - - abstract fun processMagicSearchResults(results: Array) } diff --git a/app/src/main/res/layout-land/bottom_nav_bar.xml b/app/src/main/res/layout-land/bottom_nav_bar.xml index 9a016b171..71c69d3ea 100644 --- a/app/src/main/res/layout-land/bottom_nav_bar.xml +++ b/app/src/main/res/layout-land/bottom_nav_bar.xml @@ -30,7 +30,6 @@ android:id="@+id/bottom_nav_bar" android:layout_width="75dp" android:layout_height="match_parent" - android:transitionName="bottom_nav_bar" android:background="@color/white"> + xmlns:app="http://schemas.android.com/apk/res-auto"> - - - - - - - - - - - - - - - + app:defaultNavHost="false" + app:navGraph="@navigation/contact_left_nav_graph"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bottom_nav_bar.xml b/app/src/main/res/layout/bottom_nav_bar.xml index 90253f780..e130a0e1f 100644 --- a/app/src/main/res/layout/bottom_nav_bar.xml +++ b/app/src/main/res/layout/bottom_nav_bar.xml @@ -27,7 +27,6 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> - - - - - - - - - - - + app:navGraph="@navigation/contact_right_nav_graph"/> diff --git a/app/src/main/res/layout/contacts_list_fragment.xml b/app/src/main/res/layout/contacts_list_fragment.xml index 43f0fc48d..1b640ffeb 100644 --- a/app/src/main/res/layout/contacts_list_fragment.xml +++ b/app/src/main/res/layout/contacts_list_fragment.xml @@ -5,6 +5,15 @@ + + + @@ -21,6 +30,12 @@ app:constraint_referenced_ids="no_contacts_image, no_contacts_label" android:visibility="@{viewModel.contactsList.empty ? View.VISIBLE : View.GONE}" /> + + + app:layout_constraintTop_toBottomOf="@id/top_bar" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/contact_left_nav_graph.xml b/app/src/main/res/navigation/contact_left_nav_graph.xml new file mode 100644 index 000000000..f707119b7 --- /dev/null +++ b/app/src/main/res/navigation/contact_left_nav_graph.xml @@ -0,0 +1,27 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/contact_nav_graph.xml b/app/src/main/res/navigation/contact_right_nav_graph.xml similarity index 93% rename from app/src/main/res/navigation/contact_nav_graph.xml rename to app/src/main/res/navigation/contact_right_nav_graph.xml index 09f39a722..afda7d6fc 100644 --- a/app/src/main/res/navigation/contact_nav_graph.xml +++ b/app/src/main/res/navigation/contact_right_nav_graph.xml @@ -2,7 +2,7 @@ - + app:destination="@id/conversationsFragment" /> - - - - - - \ No newline at end of file