diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationEphemeralLifetimeFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationEphemeralLifetimeFragment.kt index 9704a51bf..16c9dc2f5 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationEphemeralLifetimeFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationEphemeralLifetimeFragment.kt @@ -11,11 +11,11 @@ import androidx.navigation.fragment.navArgs import org.linphone.core.tools.Log import org.linphone.databinding.ChatEphemeralLifetimeFragmentBinding import org.linphone.ui.main.chat.viewmodel.ConversationEphemeralLifetimeViewModel -import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.fragment.SlidingPaneChildFragment import org.linphone.utils.Event @UiThread -class ConversationEphemeralLifetimeFragment : GenericFragment() { +class ConversationEphemeralLifetimeFragment : SlidingPaneChildFragment() { companion object { private const val TAG = "[Conversation Ephemeral Lifetime Fragment]" } @@ -40,9 +40,6 @@ class ConversationEphemeralLifetimeFragment : GenericFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // This fragment is displayed in a SlidingPane "child" area - isSlidingPaneChild = true - super.onViewCreated(view, savedInstanceState) binding.lifecycleOwner = viewLifecycleOwner 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 454353193..b1c91c299 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 @@ -72,7 +72,7 @@ import org.linphone.ui.main.chat.view.RichEditText import org.linphone.ui.main.chat.viewmodel.ConversationViewModel import org.linphone.ui.main.chat.viewmodel.ConversationViewModel.Companion.SCROLLING_POSITION_NOT_SET import org.linphone.ui.main.chat.viewmodel.SendMessageInConversationViewModel -import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.fragment.SlidingPaneChildFragment import org.linphone.utils.Event import org.linphone.utils.FileUtils import org.linphone.utils.LinphoneUtils @@ -84,7 +84,7 @@ import org.linphone.utils.setKeyboardInsetListener import org.linphone.utils.showKeyboard @UiThread -class ConversationFragment : GenericFragment() { +class ConversationFragment : SlidingPaneChildFragment() { companion object { private const val TAG = "[Conversation Fragment]" } @@ -212,9 +212,6 @@ class ConversationFragment : GenericFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // This fragment is displayed in a SlidingPane "child" area - isSlidingPaneChild = true - super.onViewCreated(view, savedInstanceState) binding.lifecycleOwner = viewLifecycleOwner diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt index 5c65cd62c..7bead3371 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt @@ -41,12 +41,12 @@ import org.linphone.ui.main.chat.adapter.ConversationParticipantsAdapter import org.linphone.ui.main.chat.model.ConversationEditSubjectDialogModel import org.linphone.ui.main.chat.model.ParticipantModel import org.linphone.ui.main.chat.viewmodel.ConversationInfoViewModel -import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.fragment.SlidingPaneChildFragment import org.linphone.utils.DialogUtils import org.linphone.utils.Event @UiThread -class ConversationInfoFragment : GenericFragment() { +class ConversationInfoFragment : SlidingPaneChildFragment() { companion object { private const val TAG = "[Conversation Info Fragment]" } @@ -79,9 +79,6 @@ class ConversationInfoFragment : GenericFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // This fragment is displayed in a SlidingPane "child" area - isSlidingPaneChild = true - postponeEnterTransition() super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactFragment.kt index db6d68346..959af9de3 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactFragment.kt @@ -45,13 +45,13 @@ import org.linphone.ui.main.MainActivity import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel import org.linphone.ui.main.contacts.model.TrustCallDialogModel import org.linphone.ui.main.contacts.viewmodel.ContactViewModel -import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.fragment.SlidingPaneChildFragment import org.linphone.ui.main.history.model.ConfirmationDialogModel import org.linphone.utils.DialogUtils import org.linphone.utils.Event @UiThread -class ContactFragment : GenericFragment() { +class ContactFragment : SlidingPaneChildFragment() { companion object { private const val TAG = "[Contact Fragment]" } @@ -82,9 +82,6 @@ class ContactFragment : GenericFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // This fragment is displayed in a SlidingPane "child" area - isSlidingPaneChild = true - postponeEnterTransition() super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/EditContactFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/EditContactFragment.kt index 38a0d9dc4..9ee6d37e5 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/EditContactFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/fragment/EditContactFragment.kt @@ -43,13 +43,13 @@ import org.linphone.databinding.ContactNewOrEditFragmentBinding import org.linphone.ui.main.MainActivity import org.linphone.ui.main.contacts.model.NewOrEditNumberOrAddressModel import org.linphone.ui.main.contacts.viewmodel.ContactNewOrEditViewModel -import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.fragment.SlidingPaneChildFragment import org.linphone.ui.main.history.model.ConfirmationDialogModel import org.linphone.utils.DialogUtils import org.linphone.utils.FileUtils @UiThread -class EditContactFragment : GenericFragment() { +class EditContactFragment : SlidingPaneChildFragment() { companion object { private const val TAG = "[Edit Contact Fragment]" } @@ -97,9 +97,6 @@ class EditContactFragment : GenericFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // This fragment is displayed in a SlidingPane "child" area - isSlidingPaneChild = true - postponeEnterTransition() super.onViewCreated(view, savedInstanceState) 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 127360176..549370d39 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 @@ -60,8 +60,10 @@ abstract class AbstractTopBarFragment : GenericFragment() { view?.doOnPreDraw { slidingPane.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED - sharedViewModel.isSlidingPaneSlideable.value = slidingPane.isSlideable - slidingPaneBackPressedCallback.isEnabled = slidingPane.isSlideable + val slideable = slidingPane.isSlideable + sharedViewModel.isSlidingPaneSlideable.value = slideable + slidingPaneBackPressedCallback.isEnabled = slideable && slidingPane.isOpen + Log.d("$TAG Sliding Pane is ${if (slideable) "slideable" else "flat"}") } sharedViewModel.closeSlidingPaneEvent.observe( @@ -69,7 +71,7 @@ abstract class AbstractTopBarFragment : GenericFragment() { ) { it.consume { if (slidingPane.isOpen && slidingPane.isSlideable) { - Log.i("$TAG Closing sliding pane") + Log.d("$TAG Closing sliding pane") slidingPane.closePane() } } @@ -80,7 +82,7 @@ abstract class AbstractTopBarFragment : GenericFragment() { ) { it.consume { if (!slidingPane.isOpen) { - Log.i("$TAG Opening sliding pane") + Log.d("$TAG Opening sliding pane") slidingPane.openPane() } } diff --git a/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt index 528467707..7fba7f8f8 100644 --- a/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt @@ -62,9 +62,6 @@ class AddParticipantsFragment : GenericAddressPickerFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // This fragment is displayed in a SlidingPane "child" area - isSlidingPaneChild = true - viewModel = ViewModelProvider(this)[AddParticipantsViewModel::class.java] postponeEnterTransition() diff --git a/app/src/main/java/org/linphone/ui/main/fragment/GenericFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/GenericFragment.kt index 1c07298d6..205d36285 100644 --- a/app/src/main/java/org/linphone/ui/main/fragment/GenericFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/fragment/GenericFragment.kt @@ -21,11 +21,9 @@ package org.linphone.ui.main.fragment import android.os.Bundle import android.view.View -import androidx.activity.OnBackPressedCallback import androidx.annotation.UiThread import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider -import androidx.navigation.fragment.findNavController import org.linphone.core.tools.Log import org.linphone.ui.main.viewmodel.SharedMainViewModel @@ -37,71 +35,15 @@ abstract class GenericFragment : Fragment() { protected lateinit var sharedViewModel: SharedMainViewModel - protected var isSlidingPaneChild: Boolean = false - - private val onBackPressedCallback = object : OnBackPressedCallback(false) { - override fun handleOnBackPressed() { - Log.d("$TAG ${getFragmentRealClassName()} handleOnBackPressed") - try { - if (!goBack()) { - Log.d( - "$TAG ${getFragmentRealClassName()}'s goBack() method returned false, trying other things" - ) - val navController = findNavController() - if (!navController.popBackStack()) { - Log.d("$TAG ${getFragmentRealClassName()} couldn't pop") - if (!navController.navigateUp()) { - Log.d( - "$TAG ${getFragmentRealClassName()} couldn't navigate up" - ) - // Disable this callback & start a new back press event - isEnabled = false - try { - requireActivity().onBackPressedDispatcher.onBackPressed() - } catch (ise: IllegalStateException) { - Log.w( - "$TAG ${getFragmentRealClassName()}.goBack() can't go back: $ise" - ) - } - } - } - } - } catch (ise: IllegalStateException) { - Log.e( - "$TAG ${getFragmentRealClassName()}.handleOnBackPressed() Can't go back: $ise" - ) - } - } - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedViewModel = requireActivity().run { ViewModelProvider(this)[SharedMainViewModel::class.java] } - - sharedViewModel.isSlidingPaneSlideable.observe(viewLifecycleOwner) { - val enabled = backPressedCallBackEnabled() - onBackPressedCallback.isEnabled = enabled - Log.d( - "$TAG ${getFragmentRealClassName()} Our own back press callback is ${if (enabled) "enabled" else "disabled"}" - ) - } - - requireActivity().onBackPressedDispatcher.addCallback( - viewLifecycleOwner, - onBackPressedCallback - ) } - override fun onDestroyView() { - super.onDestroyView() - - onBackPressedCallback.remove() - } - - private fun getFragmentRealClassName(): String { + protected fun getFragmentRealClassName(): String { return this.javaClass.name } @@ -111,24 +53,8 @@ abstract class GenericFragment : Fragment() { requireActivity().onBackPressedDispatcher.onBackPressed() } catch (ise: IllegalStateException) { Log.w("$TAG ${getFragmentRealClassName()}.goBack() can't go back: $ise") - onBackPressedCallback.handleOnBackPressed() + return false } return true } - - private fun backPressedCallBackEnabled(): Boolean { - // This allow to navigate a SlidingPane child nav graph. - // This only concerns fragments for which the nav graph is inside a SlidingPane layout. - // In our case it's all graphs except the main one. - if (!isSlidingPaneChild) { - Log.d("$TAG ${getFragmentRealClassName()} isn't a sliding pane child, disable callback") - return false - } - - val isSlidingPaneFlat = sharedViewModel.isSlidingPaneSlideable.value == false - Log.d( - "$TAG ${getFragmentRealClassName()} isSlidingPaneFlat ? $isSlidingPaneFlat" - ) - return !isSlidingPaneFlat - } } diff --git a/app/src/main/java/org/linphone/ui/main/fragment/SlidingPaneChildFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/SlidingPaneChildFragment.kt new file mode 100644 index 000000000..699561f66 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/fragment/SlidingPaneChildFragment.kt @@ -0,0 +1,113 @@ +/* + * 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.fragment + +import android.os.Bundle +import android.view.View +import androidx.activity.OnBackPressedCallback +import androidx.annotation.UiThread +import androidx.navigation.fragment.findNavController +import org.linphone.core.tools.Log + +@UiThread +abstract class SlidingPaneChildFragment : GenericFragment() { + companion object { + private const val TAG = "[Sliding Pane Child Fragment]" + } + + private val onBackPressedCallback = object : OnBackPressedCallback(false) { + override fun handleOnBackPressed() { + Log.d("$TAG ${getFragmentRealClassName()} handleOnBackPressed") + try { + if (!goBack()) { + Log.d( + "$TAG ${getFragmentRealClassName()}'s goBack() method returned false, trying other things" + ) + val navController = findNavController() + if (!navController.popBackStack()) { + Log.d("$TAG ${getFragmentRealClassName()} couldn't pop") + if (!navController.navigateUp()) { + Log.d( + "$TAG ${getFragmentRealClassName()} couldn't navigate up" + ) + // Disable this callback & start a new back press event + isEnabled = false + try { + requireActivity().onBackPressedDispatcher.onBackPressed() + } catch (ise: IllegalStateException) { + Log.w( + "$TAG ${getFragmentRealClassName()}.goBack() can't go back: $ise" + ) + } + } + } + } + } catch (ise: IllegalStateException) { + Log.e( + "$TAG ${getFragmentRealClassName()}.handleOnBackPressed() Can't go back: $ise" + ) + } + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + requireActivity().onBackPressedDispatcher.addCallback( + viewLifecycleOwner, + onBackPressedCallback + ) + + sharedViewModel.isSlidingPaneSlideable.observe(viewLifecycleOwner) { slideable -> + val enabled = backPressedCallBackEnabled(slideable) + onBackPressedCallback.isEnabled = enabled + Log.d( + "$TAG ${getFragmentRealClassName()} Our own back press callback is ${if (enabled) "enabled" else "disabled"}" + ) + } + } + + override fun onDestroyView() { + super.onDestroyView() + + onBackPressedCallback.remove() + } + + override fun goBack(): Boolean { + if (!super.goBack()) { + if (onBackPressedCallback.isEnabled) { + onBackPressedCallback.handleOnBackPressed() + return true + } + return false + } + return true + } + + private fun backPressedCallBackEnabled(slideable: Boolean): Boolean { + // This allow to navigate a SlidingPane child nav graph. + // This only concerns fragments for which the nav graph is inside a SlidingPane layout. + // In our case it's all graphs except the main one. + Log.d( + "$TAG ${getFragmentRealClassName()} Sliding pane is ${if (slideable) "slideable" else "flat"}" + ) + return slideable + } +} diff --git a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt index 42c9e7e2f..5af25bcfc 100644 --- a/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/history/fragment/HistoryContactFragment.kt @@ -40,7 +40,7 @@ import org.linphone.core.tools.Log import org.linphone.databinding.HistoryContactFragmentBinding import org.linphone.databinding.HistoryContactPopupMenuBinding import org.linphone.ui.main.MainActivity -import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.fragment.SlidingPaneChildFragment import org.linphone.ui.main.history.adapter.ContactHistoryListAdapter import org.linphone.ui.main.history.model.ConfirmationDialogModel import org.linphone.ui.main.history.viewmodel.ContactHistoryViewModel @@ -48,7 +48,7 @@ import org.linphone.utils.DialogUtils import org.linphone.utils.Event @UiThread -class HistoryContactFragment : GenericFragment() { +class HistoryContactFragment : SlidingPaneChildFragment() { companion object { private const val TAG = "[Call Fragment]" } @@ -84,9 +84,6 @@ class HistoryContactFragment : GenericFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // This fragment is displayed in a SlidingPane "child" area - isSlidingPaneChild = true - postponeEnterTransition() super.onViewCreated(view, savedInstanceState) 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 a17110f1b..06244d9d7 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 @@ -42,12 +42,12 @@ import org.linphone.core.tools.Log import org.linphone.databinding.MeetingFragmentBinding import org.linphone.databinding.MeetingPopupMenuBinding import org.linphone.ui.main.MainActivity -import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.fragment.SlidingPaneChildFragment import org.linphone.ui.main.meetings.viewmodel.MeetingViewModel import org.linphone.utils.Event @UiThread -class MeetingFragment : GenericFragment() { +class MeetingFragment : SlidingPaneChildFragment() { companion object { private const val TAG = "[Meeting Fragment]" } @@ -74,9 +74,6 @@ class MeetingFragment : GenericFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // This fragment is displayed in a SlidingPane "child" area - isSlidingPaneChild = true - postponeEnterTransition() super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/org/linphone/utils/SlidingPaneBackPressCallback.kt b/app/src/main/java/org/linphone/utils/SlidingPaneBackPressCallback.kt index d7f607a80..70b834727 100644 --- a/app/src/main/java/org/linphone/utils/SlidingPaneBackPressCallback.kt +++ b/app/src/main/java/org/linphone/utils/SlidingPaneBackPressCallback.kt @@ -27,9 +27,7 @@ import org.linphone.core.tools.Log @UiThread class SlidingPaneBackPressedCallback(private val slidingPaneLayout: SlidingPaneLayout) : - OnBackPressedCallback( - slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen - ), + OnBackPressedCallback(false), SlidingPaneLayout.PanelSlideListener { companion object { private const val TAG = "[Sliding Pane Back Pressed Callback]" @@ -37,12 +35,21 @@ class SlidingPaneBackPressedCallback(private val slidingPaneLayout: SlidingPaneL init { slidingPaneLayout.addPanelSlideListener(this) + val enableCallback = slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen + Log.d( + "$TAG Sliding pane layout created, back press callback is ${if (enableCallback) "enabled" else "disabled"}" + ) + isEnabled = enableCallback } override fun handleOnBackPressed() { - Log.d("$TAG handleOnBackPressed: hiding keyboard & closing pane") - slidingPaneLayout.hideKeyboard() - slidingPaneLayout.closePane() + if (slidingPaneLayout.isOpen) { + Log.d("$TAG handleOnBackPressed: hiding keyboard & closing pane") + slidingPaneLayout.hideKeyboard() + slidingPaneLayout.closePane() + } else { + Log.w("$TAG handleOnBackPressed: sliding pane is not open!") + } } override fun onPanelOpened(panel: View) { @@ -56,7 +63,6 @@ class SlidingPaneBackPressedCallback(private val slidingPaneLayout: SlidingPaneL } override fun onPanelSlide(panel: View, slideOffset: Float) { - Log.d("$TAG Panel is sliding, enabling back press callback") isEnabled = true } }