diff --git a/changelog.d/6787.wip b/changelog.d/6787.wip
new file mode 100644
index 0000000000..ace2b04d9e
--- /dev/null
+++ b/changelog.d/6787.wip
@@ -0,0 +1 @@
+[App Layout] Dialpad moved from bottom navigation tab to a separate activity accessed via home screen context menu
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index beee800b4a..bed0b618d0 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -348,6 +348,7 @@
+
diff --git a/vector/src/main/java/im/vector/app/features/call/dialpad/PstnDialActivity.kt b/vector/src/main/java/im/vector/app/features/call/dialpad/PstnDialActivity.kt
new file mode 100644
index 0000000000..a0d6e29849
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/call/dialpad/PstnDialActivity.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.call.dialpad
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatDialog
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.error.ErrorFormatter
+import im.vector.app.core.extensions.addFragment
+import im.vector.app.core.platform.SimpleFragmentActivity
+import im.vector.app.features.call.webrtc.WebRtcCallManager
+import im.vector.app.features.createdirect.DirectRoomHelper
+import im.vector.app.features.settings.VectorLocale
+import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
+import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.session.Session
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class PstnDialActivity : SimpleFragmentActivity() {
+
+ @Inject lateinit var callManager: WebRtcCallManager
+ @Inject lateinit var directRoomHelper: DirectRoomHelper
+ @Inject lateinit var session: Session
+ @Inject lateinit var errorFormatter: ErrorFormatter
+
+ private var progress: AppCompatDialog? = null
+
+ override fun getTitleRes(): Int = R.string.call
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (isFirstCreation()) {
+ addFragment(
+ views.container,
+ createDialPadFragment()
+ )
+ }
+ }
+
+ private fun handleStartCallWithPhoneNumber(rawNumber: String) {
+ lifecycleScope.launch {
+ try {
+ showLoadingDialog()
+ val result = DialPadLookup(session, callManager, directRoomHelper).lookupPhoneNumber(rawNumber)
+ callManager.startOutgoingCall(result.roomId, result.userId, isVideoCall = false)
+ dismissLoadingDialog()
+ finish()
+ } catch (failure: Throwable) {
+ dismissLoadingDialog()
+ displayErrorDialog(failure)
+ }
+ }
+ }
+
+ private fun createDialPadFragment(): Fragment {
+ val fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, DialPadFragment::class.java.name)
+ return (fragment as DialPadFragment).apply {
+ arguments = Bundle().apply {
+ putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true)
+ putBoolean(DialPadFragment.EXTRA_ENABLE_OK, true)
+ putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country)
+ }
+ callback = object : DialPadFragment.Callback {
+ override fun onOkClicked(formatted: String?, raw: String?) {
+ if (raw.isNullOrEmpty()) return
+ handleStartCallWithPhoneNumber(raw)
+ }
+ }
+ }
+ }
+
+ private fun showLoadingDialog() {
+ progress?.dismiss()
+ progress = MaterialProgressDialog(this)
+ .show(getString(R.string.please_wait))
+ }
+
+ private fun dismissLoadingDialog() {
+ progress?.dismiss()
+ }
+
+ private fun displayErrorDialog(throwable: Throwable) {
+ MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.dialog_title_error)
+ .setMessage(errorFormatter.toHumanReadable(throwable))
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt
index 839ae6da88..d45aaeb762 100644
--- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt
@@ -16,13 +16,13 @@
package im.vector.app.features.home
+import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
-import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.fragmentViewModel
@@ -42,12 +42,11 @@ import im.vector.app.core.ui.views.KeysBackupBanner
import im.vector.app.databinding.FragmentNewHomeDetailBinding
import im.vector.app.features.call.SharedKnownCallsViewModel
import im.vector.app.features.call.VectorCallActivity
-import im.vector.app.features.call.dialpad.DialPadFragment
+import im.vector.app.features.call.dialpad.PstnDialActivity
import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.home.room.list.home.HomeRoomListFragment
import im.vector.app.features.popup.PopupAlertManager
import im.vector.app.features.popup.VerificationVectorAlert
-import im.vector.app.features.settings.VectorLocale
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS
import im.vector.app.features.themes.ThemeUtils
@@ -99,6 +98,10 @@ class NewHomeDetailFragment @Inject constructor(
viewModel.handle(HomeDetailAction.MarkAllRoomsRead)
true
}
+ R.id.menu_home_dialpad -> {
+ startActivity(Intent(requireContext(), PstnDialActivity::class.java))
+ true
+ }
else -> false
}
}
@@ -107,6 +110,7 @@ class NewHomeDetailFragment @Inject constructor(
withState(viewModel) { state ->
val isRoomList = state.currentTab is HomeTab.RoomList
menu.findItem(R.id.menu_home_mark_all_as_read).isVisible = isRoomList && hasUnreadRooms
+ menu.findItem(R.id.menu_home_dialpad).isVisible = state.showDialPadTab
}
}
@@ -138,14 +142,10 @@ class NewHomeDetailFragment @Inject constructor(
updateUIForTab(currentTab)
}
- viewModel.onEach(HomeDetailViewState::showDialPadTab) { showDialPadTab ->
- updateTabVisibilitySafely(R.id.bottom_action_dial_pad, showDialPadTab)
- }
-
viewModel.observeViewEvents { viewEvent ->
when (viewEvent) {
- HomeDetailViewEvents.CallStarted -> handleCallStarted()
- is HomeDetailViewEvents.FailToCall -> showFailure(viewEvent.failure)
+ HomeDetailViewEvents.CallStarted -> Unit
+ is HomeDetailViewEvents.FailToCall -> Unit
HomeDetailViewEvents.Loading -> showLoadingDialog()
}
}
@@ -186,12 +186,6 @@ class NewHomeDetailFragment @Inject constructor(
sharedActionViewModel.post(HomeActivitySharedAction.OnCloseSpace)
}
- private fun handleCallStarted() {
- dismissLoadingDialog()
- val fragmentTag = HomeTab.DialPad.toFragmentTag()
- (childFragmentManager.findFragmentByTag(fragmentTag) as? DialPadFragment)?.clear()
- }
-
override fun onDestroyView() {
currentCallsViewPresenter.unBind()
super.onDestroyView()
@@ -339,30 +333,15 @@ class NewHomeDetailFragment @Inject constructor(
add(R.id.roomListContainer, HomeRoomListFragment::class.java, null, fragmentTag)
}
is HomeTab.DialPad -> {
- add(R.id.roomListContainer, createDialPadFragment(), fragmentTag)
+ throw NotImplementedError("this tab shouldn't exists when app layout is enabled")
}
}
} else {
- if (tab is HomeTab.DialPad) {
- (fragmentToShow as? DialPadFragment)?.applyCallback()
- }
attach(fragmentToShow)
}
}
}
- private fun createDialPadFragment(): Fragment {
- val fragment = childFragmentManager.fragmentFactory.instantiate(vectorBaseActivity.classLoader, DialPadFragment::class.java.name)
- return (fragment as DialPadFragment).apply {
- arguments = Bundle().apply {
- putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true)
- putBoolean(DialPadFragment.EXTRA_ENABLE_OK, true)
- putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country)
- }
- applyCallback()
- }
- }
-
private fun updateTabVisibilitySafely(tabId: Int, isVisible: Boolean) {
val wasVisible = views.bottomNavigationView.menu.findItem(tabId).isVisible
views.bottomNavigationView.menu.findItem(tabId).isVisible = isVisible
@@ -439,16 +418,6 @@ class NewHomeDetailFragment @Inject constructor(
}
}
- private fun DialPadFragment.applyCallback(): DialPadFragment {
- callback = object : DialPadFragment.Callback {
- override fun onOkClicked(formatted: String?, raw: String?) {
- if (raw.isNullOrEmpty()) return
- viewModel.handle(HomeDetailAction.StartCallWithPhoneNumber(raw))
- }
- }
- return this
- }
-
override fun onBackPressed(toolbarButton: Boolean) = if (spaceStateHandler.getCurrentSpace() != null) {
navigateBack()
true
diff --git a/vector/src/main/res/menu/room_list.xml b/vector/src/main/res/menu/room_list.xml
index 60ffdcd87b..ad375d241b 100644
--- a/vector/src/main/res/menu/room_list.xml
+++ b/vector/src/main/res/menu/room_list.xml
@@ -1,9 +1,17 @@
-