diff --git a/changelog.d/6436.misc b/changelog.d/6436.misc new file mode 100644 index 0000000000..a170b624ce --- /dev/null +++ b/changelog.d/6436.misc @@ -0,0 +1 @@ +Let your Activity or Fragment implement `VectorMenuProvider` if they provide a menu. diff --git a/dependencies.gradle b/dependencies.gradle index ee506f59b9..bd03a1c48b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -29,7 +29,7 @@ def bigImageViewer = "1.8.1" def jjwt = "0.11.5" def vanniktechEmoji = "0.15.0" -def fragment = "1.4.1" +def fragment = "1.5.0" // Testing def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819 @@ -50,7 +50,7 @@ ext.libs = [ ], androidx : [ 'annotation' : "androidx.annotation:annotation:1.4.0", - 'activity' : "androidx.activity:activity:1.4.0", + 'activity' : "androidx.activity:activity:1.5.0", 'annotations' : "androidx.annotation:annotation:1.3.0", 'appCompat' : "androidx.appcompat:appcompat:1.4.2", 'biometric' : "androidx.biometric:biometric:1.1.0", diff --git a/library/ui-styles/build.gradle b/library/ui-styles/build.gradle index eabd0f36f6..c85f26dbc4 100644 --- a/library/ui-styles/build.gradle +++ b/library/ui-styles/build.gradle @@ -53,6 +53,7 @@ android { dependencies { implementation libs.androidx.appCompat + implementation libs.androidx.fragmentKtx implementation libs.google.material // Pref theme implementation libs.androidx.preferenceKtx diff --git a/library/ui-styles/src/debug/java/im/vector/lib/ui/styles/debug/DebugMaterialThemeActivity.kt b/library/ui-styles/src/debug/java/im/vector/lib/ui/styles/debug/DebugMaterialThemeActivity.kt index 553d495e22..412d6fdc1c 100644 --- a/library/ui-styles/src/debug/java/im/vector/lib/ui/styles/debug/DebugMaterialThemeActivity.kt +++ b/library/ui-styles/src/debug/java/im/vector/lib/ui/styles/debug/DebugMaterialThemeActivity.kt @@ -18,8 +18,12 @@ package im.vector.lib.ui.styles.debug import android.os.Bundle import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem import android.widget.Toast import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import im.vector.lib.ui.styles.R @@ -31,6 +35,7 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setupMenu() val views = ActivityDebugMaterialThemeBinding.inflate(layoutInflater) setContentView(views.root) @@ -72,6 +77,27 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() { } } + private fun setupMenu() { + addMenuProvider( + object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.menu_debug, menu) + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + Toast.makeText( + this@DebugMaterialThemeActivity, + "Menu ${menuItem.title} clicked!", + Toast.LENGTH_SHORT + ).show() + return true + } + }, + this, + Lifecycle.State.RESUMED + ) + } + private fun showTestDialog(theme: Int) { MaterialAlertDialogBuilder(this, theme) .setTitle("Dialog title") @@ -82,9 +108,4 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() { .setNeutralButton("Neutral", null) .show() } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.menu_debug, menu) - return true - } } diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index 962a14843d..b12f15fa5d 100755 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -180,3 +180,8 @@ System\.currentTimeMillis\(\)===2 ### Remove extra space between the name and the description \* @\w+ \w+ + + +### Please use the MenuProvider interface now +onCreateOptionsMenu +onOptionsItemSelected +onPrepareOptionsMenu diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index 571d2d38c0..9bad0f8e90 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -19,11 +19,11 @@ package im.vector.app.core.platform import android.annotation.SuppressLint import android.app.Activity import android.content.Context -import android.content.res.Configuration import android.os.Build import android.os.Bundle import android.os.Parcelable import android.view.Menu +import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.WindowInsetsController @@ -31,15 +31,18 @@ import android.view.WindowManager import android.widget.TextView import androidx.annotation.CallSuper import androidx.annotation.MainThread -import androidx.annotation.MenuRes import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.app.MultiWindowModeChangedInfo import androidx.core.content.ContextCompat +import androidx.core.util.Consumer +import androidx.core.view.MenuProvider import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentFactory import androidx.fragment.app.FragmentManager +import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.viewbinding.ViewBinding @@ -86,6 +89,7 @@ import im.vector.app.features.themes.ThemeUtils import im.vector.app.receivers.DebugReceiver import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.failure.InitialSyncRequestReason @@ -199,6 +203,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver supportFragmentManager.fragmentFactory = fragmentFactory viewModelFactory = activityEntryPoint.viewModelFactory() super.onCreate(savedInstanceState) + addOnMultiWindowModeChangedListener(onMultiWindowModeChangedListener) + setupMenu() configurationViewModel = viewModelProvider.get(ConfigurationViewModel::class.java) bugReporter = singletonEntryPoint.bugReporter() pinLocker = singletonEntryPoint.pinLocker() @@ -249,6 +255,32 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver } } + private fun setupMenu() { + // Always add a MenuProvider to handle the back action from the Toolbar + val vectorMenuProvider = this as? VectorMenuProvider + addMenuProvider( + object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + vectorMenuProvider?.let { + menuInflater.inflate(it.getMenuRes(), menu) + it.handlePostCreateMenu(menu) + } + } + + override fun onPrepareMenu(menu: Menu) { + vectorMenuProvider?.handlePrepareMenu(menu) + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return vectorMenuProvider?.handleMenuItemSelected(menuItem).orFalse() || + handleMenuItemHome(menuItem) + } + }, + this, + Lifecycle.State.RESUMED + ) + } + /** * This method has to be called for the font size setting be supported correctly. */ @@ -332,6 +364,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver } override fun onDestroy() { + removeOnMultiWindowModeChangedListener(onMultiWindowModeChangedListener) super.onDestroy() Timber.i("onDestroy Activity ${javaClass.simpleName}") } @@ -417,11 +450,9 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver } } - override fun onMultiWindowModeChanged(isInMultiWindowMode: Boolean, newConfig: Configuration?) { - super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig) - - Timber.w("onMultiWindowModeChanged. isInMultiWindowMode: $isInMultiWindowMode") - bugReporter.inMultiWindowMode = isInMultiWindowMode + private val onMultiWindowModeChangedListener = Consumer { + Timber.w("onMultiWindowModeChanged. isInMultiWindowMode: ${it.isInMultiWindowMode}") + bugReporter.inMultiWindowMode = it.isInMultiWindowMode } protected fun createFragment(fragmentClass: Class, argsParcelable: Parcelable? = null): Fragment { @@ -463,28 +494,14 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver } } - /* ========================================================================================== - * MENU MANAGEMENT - * ========================================================================================== */ - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - val menuRes = getMenuRes() - - if (menuRes != -1) { - menuInflater.inflate(menuRes, menu) - return true + private fun handleMenuItemHome(item: MenuItem): Boolean { + return when (item.itemId) { + android.R.id.home -> { + onBackPressed(true) + true + } + else -> false } - - return super.onCreateOptionsMenu(menu) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == android.R.id.home) { - onBackPressed(true) - return true - } - - return super.onOptionsItemSelected(item) } override fun onBackPressed() { @@ -587,9 +604,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver @StringRes open fun getTitleRes() = -1 - @MenuRes - open fun getMenuRes() = -1 - /** * Return a object containing other themes for this activity. */ diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt index 38667b774f..340c906a6d 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt @@ -22,12 +22,16 @@ import android.os.Parcelable import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup import androidx.annotation.CallSuper import androidx.annotation.MainThread import androidx.appcompat.app.AlertDialog +import androidx.core.view.MenuHost +import androidx.core.view.MenuProvider import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.viewbinding.ViewBinding @@ -126,9 +130,7 @@ abstract class VectorBaseFragment : Fragment(), MavericksView @CallSuper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (getMenuRes() != -1) { - setHasOptionsMenu(true) - } + Timber.i("onCreate Fragment ${javaClass.simpleName}") } final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -158,6 +160,31 @@ abstract class VectorBaseFragment : Fragment(), MavericksView override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) Timber.i("onViewCreated Fragment ${javaClass.simpleName}") + setupMenu() + } + + private fun setupMenu() { + if (this !is VectorMenuProvider) return + if (getMenuRes() == -1) return + val menuHost: MenuHost = requireActivity() + menuHost.addMenuProvider( + object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(getMenuRes(), menu) + handlePostCreateMenu(menu) + } + + override fun onPrepareMenu(menu: Menu) { + handlePrepareMenu(menu) + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return handleMenuItemSelected(menuItem) + } + }, + viewLifecycleOwner, + Lifecycle.State.RESUMED + ) } open fun showLoading(message: CharSequence?) { @@ -270,16 +297,6 @@ abstract class VectorBaseFragment : Fragment(), MavericksView * MENU MANAGEMENT * ========================================================================================== */ - open fun getMenuRes() = -1 - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - val menuRes = getMenuRes() - - if (menuRes != -1) { - inflater.inflate(menuRes, menu) - } - } - // This should be provided by the framework protected fun invalidateOptionsMenu() = requireActivity().invalidateOptionsMenu() diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorMenuProvider.kt b/vector/src/main/java/im/vector/app/core/platform/VectorMenuProvider.kt new file mode 100644 index 0000000000..05d710a185 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/platform/VectorMenuProvider.kt @@ -0,0 +1,37 @@ +/* + * 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.core.platform + +import android.view.Menu +import android.view.MenuItem +import androidx.annotation.MenuRes + +/** + * Let your Activity of Fragment implement this interface if they provide a Menu. + */ +interface VectorMenuProvider { + @MenuRes + fun getMenuRes(): Int + + // No op by default + fun handlePostCreateMenu(menu: Menu) {} + + // No op by default + fun handlePrepareMenu(menu: Menu) {} + + fun handleMenuItemSelected(item: MenuItem): Boolean +} diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt index dfe74fa47e..c3a4ae7df2 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt @@ -44,6 +44,7 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.insertBeforeLast import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.resources.ColorProvider import im.vector.app.core.time.Clock import im.vector.app.core.utils.OnSnapPositionChangeListener @@ -67,7 +68,9 @@ class AttachmentsPreviewFragment @Inject constructor( private val attachmentBigPreviewController: AttachmentBigPreviewController, private val colorProvider: ColorProvider, private val clock: Clock, -) : VectorBaseFragment(), AttachmentMiniaturePreviewController.Callback { +) : VectorBaseFragment(), + AttachmentMiniaturePreviewController.Callback, + VectorMenuProvider { private val fragmentArgs: AttachmentsPreviewArgs by args() private val viewModel: AttachmentsPreviewViewModel by fragmentViewModel() @@ -97,7 +100,7 @@ class AttachmentsPreviewFragment @Inject constructor( } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun handleMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.attachmentsPreviewRemoveAction -> { handleRemoveAction() @@ -107,20 +110,16 @@ class AttachmentsPreviewFragment @Inject constructor( handleEditAction() true } - else -> { - super.onOptionsItemSelected(item) - } + else -> false } } - override fun onPrepareOptionsMenu(menu: Menu) { + override fun handlePrepareMenu(menu: Menu) { withState(viewModel) { state -> val editMenuItem = menu.findItem(R.id.attachmentsPreviewEditAction) val showEditMenuItem = state.attachments.getOrNull(state.currentAttachmentIndex)?.isEditable().orFalse() editMenuItem.setVisible(showEditMenuItem) } - - super.onPrepareOptionsMenu(menu) } override fun getMenuRes() = R.menu.vector_attachments_preview diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index f507aa97ca..9d7ada9d63 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -22,7 +22,6 @@ import android.app.PictureInPictureParams import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP -import android.content.res.Configuration import android.graphics.Color import android.media.projection.MediaProjection import android.media.projection.MediaProjectionManager @@ -35,8 +34,10 @@ import android.view.View import android.view.WindowManager import androidx.activity.result.ActivityResult import androidx.annotation.StringRes +import androidx.core.app.PictureInPictureModeChangedInfo import androidx.core.content.ContextCompat import androidx.core.content.getSystemService +import androidx.core.util.Consumer import androidx.core.view.isInvisible import androidx.core.view.isVisible import com.airbnb.mvrx.Fail @@ -50,6 +51,7 @@ import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL import im.vector.app.core.utils.checkPermissions @@ -94,7 +96,10 @@ data class CallArgs( private val loggerTag = LoggerTag("VectorCallActivity", LoggerTag.VOIP) @AndroidEntryPoint -class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionListener { +class VectorCallActivity : + VectorBaseActivity(), + CallControlsView.InteractionListener, + VectorMenuProvider { override fun getBinding() = ActivityCallBinding.inflate(layoutInflater) @@ -128,6 +133,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro window.statusBarColor = Color.TRANSPARENT window.navigationBarColor = Color.BLACK super.onCreate(savedInstanceState) + addOnPictureInPictureModeChangedListener(pictureInPictureModeChangedInfoConsumer) Timber.tag(loggerTag.value).v("EXTRA_MODE is ${intent.getStringExtra(EXTRA_MODE)}") if (intent.getStringExtra(EXTRA_MODE) == INCOMING_RINGING) { @@ -210,25 +216,31 @@ class VectorCallActivity : VectorBaseActivity(), CallContro return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isInPictureInPictureMode } - override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) = withState(callViewModel) { - renderState(it) + private val pictureInPictureModeChangedInfoConsumer = Consumer { + withState(callViewModel) { + renderState(it) + } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.menu_call_open_chat) { - returnToChat() - return true - } else if (item.itemId == android.R.id.home) { - // We check here as we want PiP in some cases - onBackPressed() - return true + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.menu_call_open_chat -> { + returnToChat() + true + } + android.R.id.home -> { + // We check here as we want PiP in some cases + onBackPressed() + true + } + else -> false } - return super.onOptionsItemSelected(item) } override fun onDestroy() { detachRenderersIfNeeded() turnScreenOffAndKeyguardOn() + removeOnPictureInPictureModeChangedListener(pictureInPictureModeChangedInfoConsumer) super.onDestroy() } diff --git a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt index 86136eab15..5bf05d353c 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt @@ -19,12 +19,13 @@ package im.vector.app.features.call.conference import android.content.Context import android.content.Intent import android.content.pm.PackageManager -import android.content.res.Configuration import android.os.Build import android.os.Bundle import android.os.Parcelable import android.widget.FrameLayout import android.widget.Toast +import androidx.core.app.PictureInPictureModeChangedInfo +import androidx.core.util.Consumer import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import com.airbnb.mvrx.Fail @@ -66,6 +67,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMee override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + addOnPictureInPictureModeChangedListener(pictureInPictureModeChangedInfoConsumer) jitsiViewModel.onEach { renderState(it) @@ -109,6 +111,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMee ConferenceEventEmitter(this).emitConferenceEnded() } JitsiMeetActivityDelegate.onHostDestroy(this) + removeOnPictureInPictureModeChangedListener(pictureInPictureModeChangedInfoConsumer) super.onDestroy() } @@ -138,13 +141,9 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMee .show() } - override fun onPictureInPictureModeChanged( - isInPictureInPictureMode: Boolean, - newConfig: Configuration - ) { - super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig) + private val pictureInPictureModeChangedInfoConsumer = Consumer { checkIfActivityShouldBeFinished() - Timber.w("onPictureInPictureModeChanged($isInPictureInPictureMode)") + Timber.w("onPictureInPictureModeChanged(${it.isInPictureInPictureMode})") } private fun checkIfActivityShouldBeFinished() { diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferPagerAdapter.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferPagerAdapter.kt index 2bb544bdbb..3ec8f61978 100644 --- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferPagerAdapter.kt +++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferPagerAdapter.kt @@ -49,6 +49,7 @@ class CallTransferPagerAdapter( fragment.arguments = UserListFragmentArgs( title = "", menuResId = -1, + submitMenuItemId = -1, singleSelection = true, showInviteActions = false, showToolbar = false, diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index 6292217b67..12cd4ddab8 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -81,7 +81,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { when (action) { UserListSharedAction.Close -> finish() UserListSharedAction.GoBack -> onBackPressed() - is UserListSharedAction.OnMenuItemSelected -> onMenuItemSelected(action) + is UserListSharedAction.OnMenuItemSubmitClick -> handleOnMenuItemSubmitClick(action) UserListSharedAction.OpenPhoneBook -> openPhoneBook() UserListSharedAction.AddByQrCode -> openAddByQrCode() } @@ -93,7 +93,8 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { UserListFragment::class.java, UserListFragmentArgs( title = getString(R.string.fab_menu_create_chat), - menuResId = R.menu.vector_create_direct_room + menuResId = R.menu.vector_create_direct_room, + submitMenuItemId = R.id.action_create_direct_room, ) ) } @@ -159,10 +160,8 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { } } - private fun onMenuItemSelected(action: UserListSharedAction.OnMenuItemSelected) { - if (action.itemId == R.id.action_create_direct_room) { - viewModel.handle(CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers(action.selections)) - } + private fun handleOnMenuItemSubmitClick(action: UserListSharedAction.OnMenuItemSubmitClick) { + viewModel.handle(CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers(action.selections)) } private fun renderCreateAndInviteState(state: Async) { diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt index 7478adb165..077bcc2cf3 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt @@ -187,16 +187,6 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() { } } -// I think this code is useful, but it violates the code quality rules -// override fun onOptionsItemSelected(item: MenuItem): Boolean { -// if (item.itemId == android .R. id. home) { -// onBackPressed() -// return true -// } -// -// return super.onOptionsItemSelected(item) -// } - companion object { const val KEYS_VERSION = "KEYS_VERSION" const val MANUAL_EXPORT = "MANUAL_EXPORT" diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt index 6f661c5164..774460eb1f 100644 --- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt +++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt @@ -21,7 +21,6 @@ import android.content.Intent import android.os.Parcelable import android.view.Menu import android.view.MenuItem -import androidx.core.view.forEach import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import com.airbnb.mvrx.Fail @@ -36,6 +35,7 @@ import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.SimpleFragmentActivity +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.createJSonViewerStyleProvider import kotlinx.parcelize.Parcelize @@ -43,7 +43,10 @@ import org.billcarsonfr.jsonviewer.JSonViewerFragment import javax.inject.Inject @AndroidEntryPoint -class RoomDevToolActivity : SimpleFragmentActivity(), FragmentManager.OnBackStackChangedListener { +class RoomDevToolActivity : + SimpleFragmentActivity(), + FragmentManager.OnBackStackChangedListener, + VectorMenuProvider { @Inject lateinit var colorProvider: ColorProvider @@ -133,16 +136,18 @@ class RoomDevToolActivity : SimpleFragmentActivity(), FragmentManager.OnBackStac } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.menuItemEdit) { - viewModel.handle(RoomDevToolAction.MenuEdit) - return true + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.menuItemEdit -> { + viewModel.handle(RoomDevToolAction.MenuEdit) + true + } + R.id.menuItemSend -> { + viewModel.handle(RoomDevToolAction.MenuItemSend) + true + } + else -> false } - if (item.itemId == R.id.menuItemSend) { - viewModel.handle(RoomDevToolAction.MenuItemSend) - return true - } - return super.onOptionsItemSelected(item) } override fun onBackPressed() { @@ -174,21 +179,12 @@ class RoomDevToolActivity : SimpleFragmentActivity(), FragmentManager.OnBackStac super.onDestroy() } - override fun onPrepareOptionsMenu(menu: Menu?): Boolean = withState(viewModel) { state -> - menu?.forEach { - val isVisible = when (it.itemId) { - R.id.menuItemEdit -> { - state.displayMode is RoomDevToolViewState.Mode.StateEventDetail - } - R.id.menuItemSend -> { - state.displayMode is RoomDevToolViewState.Mode.EditEventContent || - state.displayMode is RoomDevToolViewState.Mode.SendEventForm - } - else -> true - } - it.isVisible = isVisible + override fun handlePrepareMenu(menu: Menu) { + withState(viewModel) { state -> + menu.findItem(R.id.menuItemEdit).isVisible = state.displayMode == RoomDevToolViewState.Mode.StateEventDetail + menu.findItem(R.id.menuItemSend).isVisible = state.displayMode == RoomDevToolViewState.Mode.EditEventContent || + state.displayMode is RoomDevToolViewState.Mode.SendEventForm } - return@withState true } companion object { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index f2690fa18a..1c66cdda64 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -43,6 +43,7 @@ import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.extensions.validateBackPressed import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.databinding.ActivityHomeBinding @@ -103,7 +104,8 @@ class HomeActivity : VectorBaseActivity(), NavigationInterceptor, SpaceInviteBottomSheet.InteractionListener, - MatrixToBottomSheet.InteractionListener { + MatrixToBottomSheet.InteractionListener, + VectorMenuProvider { private lateinit var sharedActionViewModel: HomeSharedActionViewModel @@ -547,47 +549,45 @@ class HomeActivity : override fun getMenuRes() = R.menu.home - override fun onPrepareOptionsMenu(menu: Menu): Boolean { + override fun handlePrepareMenu(menu: Menu) { menu.findItem(R.id.menu_home_init_sync_legacy).isVisible = vectorPreferences.developerMode() menu.findItem(R.id.menu_home_init_sync_optimized).isVisible = vectorPreferences.developerMode() - return super.onPrepareOptionsMenu(menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { R.id.menu_home_suggestion -> { bugReporter.openBugReportScreen(this, ReportType.SUGGESTION) - return true + true } R.id.menu_home_report_bug -> { bugReporter.openBugReportScreen(this, ReportType.BUG_REPORT) - return true + true } R.id.menu_home_init_sync_legacy -> { // Configure the SDK initialSyncStrategy = InitialSyncStrategy.Legacy // And clear cache MainActivity.restartApp(this, MainActivityArgs(clearCache = true)) - return true + true } R.id.menu_home_init_sync_optimized -> { // Configure the SDK initialSyncStrategy = InitialSyncStrategy.Optimized() // And clear cache MainActivity.restartApp(this, MainActivityArgs(clearCache = true)) - return true + true } R.id.menu_home_filter -> { navigator.openRoomsFiltering(this) - return true + true } R.id.menu_home_setting -> { navigator.openSettings(this) - return true + true } + else -> false } - - return super.onOptionsItemSelected(item) } override fun onBackPressed() { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index 9deae0970b..a3bc5144d1 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -36,6 +36,7 @@ import im.vector.app.core.extensions.toMvRxBundle import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.resources.ColorProvider import im.vector.app.core.ui.views.CurrentCallsView import im.vector.app.core.ui.views.CurrentCallsViewPresenter @@ -71,7 +72,8 @@ class HomeDetailFragment @Inject constructor( ) : VectorBaseFragment(), KeysBackupBanner.Delegate, CurrentCallsView.Callback, - OnBackPressed { + OnBackPressed, + VectorMenuProvider { private val viewModel: HomeDetailViewModel by fragmentViewModel() private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel() @@ -91,23 +93,21 @@ class HomeDetailFragment @Inject constructor( override fun getMenuRes() = R.menu.room_list - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { R.id.menu_home_mark_all_as_read -> { viewModel.handle(HomeDetailAction.MarkAllRoomsRead) - return true + true } + else -> false } - - return super.onOptionsItemSelected(item) } - override fun onPrepareOptionsMenu(menu: Menu) { + override fun handlePrepareMenu(menu: Menu) { withState(viewModel) { state -> val isRoomList = state.currentTab is HomeTab.RoomList menu.findItem(R.id.menu_home_mark_all_as_read).isVisible = isRoomList && hasUnreadRooms } - super.onPrepareOptionsMenu(menu) } override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentHomeDetailBinding { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index 855df14e60..97b82a0cc9 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -30,7 +30,6 @@ import android.view.HapticFeedbackConstants import android.view.KeyEvent import android.view.LayoutInflater import android.view.Menu -import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup @@ -89,6 +88,7 @@ import im.vector.app.core.hardware.vibrate import im.vector.app.core.intent.getFilenameFromUri import im.vector.app.core.intent.getMimeTypeFromUri import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.platform.lifecycleAwareLazy import im.vector.app.core.platform.showOptimizedSnackbar import im.vector.app.core.resources.ColorProvider @@ -280,7 +280,8 @@ class TimelineFragment @Inject constructor( AttachmentTypeSelectorView.Callback, AttachmentsHelper.Callback, GalleryOrCameraDialogHelper.Listener, - CurrentCallsView.Callback { + CurrentCallsView.Callback, + VectorMenuProvider { companion object { @@ -1055,15 +1056,14 @@ class TimelineFragment @Inject constructor( } @SuppressLint("RestrictedApi") - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun handlePostCreateMenu(menu: Menu) { if (isThreadTimeLine()) { if (menu is MenuBuilder) menu.setOptionalIconsVisible(true) } - super.onCreateOptionsMenu(menu, inflater) // We use a custom layout for this menu item, so we need to set a ClickListener menu.findItem(R.id.open_matrix_apps)?.let { menuItem -> menuItem.actionView.debouncedClicks { - onOptionsItemSelected(menuItem) + handleMenuItemSelected(menuItem) } } val joinConfItem = menu.findItem(R.id.join_conference) @@ -1073,13 +1073,13 @@ class TimelineFragment @Inject constructor( // Custom thread notification menu item menu.findItem(R.id.menu_timeline_thread_list)?.let { menuItem -> - menuItem.actionView.setOnClickListener { - onOptionsItemSelected(menuItem) + menuItem.actionView.debouncedClicks { + handleMenuItemSelected(menuItem) } } } - override fun onPrepareOptionsMenu(menu: Menu) { + override fun handlePrepareMenu(menu: Menu) { menu.forEach { it.isVisible = timelineViewModel.isMenuItemVisible(it.itemId) } @@ -1121,7 +1121,7 @@ class TimelineFragment @Inject constructor( } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun handleMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.invite -> { navigator.openInviteUsersToRoom(requireActivity(), timelineArgs.roomId) @@ -1174,7 +1174,7 @@ class TimelineFragment @Inject constructor( } true } - else -> super.onOptionsItemSelected(item) + else -> false } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt index 13bf056301..aaa9846c39 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt @@ -19,7 +19,6 @@ package im.vector.app.features.home.room.threads.list.views import android.os.Bundle import android.view.LayoutInflater import android.view.Menu -import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup @@ -31,6 +30,7 @@ import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.databinding.FragmentThreadListBinding import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.home.AvatarRenderer @@ -54,7 +54,8 @@ class ThreadListFragment @Inject constructor( private val threadListController: ThreadListController, val threadListViewModelFactory: ThreadListViewModel.Factory ) : VectorBaseFragment(), - ThreadListController.Listener { + ThreadListController.Listener, + VectorMenuProvider { private val threadListViewModel: ThreadListViewModel by fragmentViewModel() @@ -71,27 +72,26 @@ class ThreadListFragment @Inject constructor( analyticsScreenName = MobileScreen.ScreenName.ThreadList } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - super.onCreateOptionsMenu(menu, inflater) - + override fun handlePostCreateMenu(menu: Menu) { + // We use a custom layout for this menu item, so we need to set a ClickListener menu.findItem(R.id.menu_thread_list_filter)?.let { menuItem -> - menuItem.actionView.setOnClickListener { - onOptionsItemSelected(menuItem) + menuItem.actionView.debouncedClicks { + handleMenuItemSelected(menuItem) } } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun handleMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.menu_thread_list_filter -> { ThreadListBottomSheet().show(childFragmentManager, "Filtering") true } - else -> super.onOptionsItemSelected(item) + else -> false } } - override fun onPrepareOptionsMenu(menu: Menu) { + override fun handlePrepareMenu(menu: Menu) { withState(threadListViewModel) { state -> val filterIcon = menu.findItem(R.id.menu_thread_list_filter).actionView val filterBadge = filterIcon.findViewById(R.id.threadListFilterBadge) diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt index 304ec72ce2..883c879e90 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt @@ -71,7 +71,7 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() { when (sharedAction) { UserListSharedAction.Close -> finish() UserListSharedAction.GoBack -> onBackPressed() - is UserListSharedAction.OnMenuItemSelected -> onMenuItemSelected(sharedAction) + is UserListSharedAction.OnMenuItemSubmitClick -> handleOnMenuItemSubmitClick(sharedAction) UserListSharedAction.OpenPhoneBook -> openPhoneBook() // not exhaustive because it's a sharedAction else -> Unit @@ -85,6 +85,7 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() { UserListFragmentArgs( title = getString(R.string.invite_users_to_room_title), menuResId = R.menu.vector_invite_users_to_room, + submitMenuItemId = R.id.action_invite_users_to_room_invite, excludedUserIds = viewModel.getUserIdsOfRoomMembers(), showInviteActions = false ) @@ -94,10 +95,8 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() { viewModel.observeViewEvents { renderInviteEvents(it) } } - private fun onMenuItemSelected(action: UserListSharedAction.OnMenuItemSelected) { - if (action.itemId == R.id.action_invite_users_to_room_invite) { - viewModel.handle(InviteUsersToRoomAction.InviteSelectedUsers(action.selections)) - } + private fun handleOnMenuItemSubmitClick(action: UserListSharedAction.OnMenuItemSubmitClick) { + viewModel.handle(InviteUsersToRoomAction.InviteSelectedUsers(action.selections)) } private fun openPhoneBook() { diff --git a/vector/src/main/java/im/vector/app/features/location/LocationPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/location/LocationPreviewFragment.kt index 7fce09cad7..131119a7aa 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationPreviewFragment.kt @@ -26,6 +26,7 @@ import com.airbnb.mvrx.args import com.mapbox.mapboxsdk.maps.MapView import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.utils.openLocation import im.vector.app.databinding.FragmentLocationPreviewBinding import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider @@ -38,7 +39,8 @@ import javax.inject.Inject class LocationPreviewFragment @Inject constructor( private val urlMapProvider: UrlMapProvider, private val locationPinProvider: LocationPinProvider -) : VectorBaseFragment() { +) : VectorBaseFragment(), + VectorMenuProvider { private val args: LocationSharingArgs by args() @@ -99,14 +101,14 @@ class LocationPreviewFragment @Inject constructor( override fun getMenuRes() = R.menu.menu_location_preview - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { R.id.share_external -> { onShareLocationExternal() - return true + true } + else -> false } - return super.onOptionsItemSelected(item) } private fun onShareLocationExternal() { diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt index c761c498d4..c7f549c5cb 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt @@ -28,6 +28,7 @@ import com.airbnb.mvrx.withState import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.databinding.ActivityBugReportBinding import org.matrix.android.sdk.api.extensions.tryOrNull import timber.log.Timber @@ -36,7 +37,9 @@ import timber.log.Timber * Form to send a bug report. */ @AndroidEntryPoint -class BugReportActivity : VectorBaseActivity() { +class BugReportActivity : + VectorBaseActivity(), + VectorMenuProvider { override fun getBinding() = ActivityBugReportBinding.inflate(layoutInflater) @@ -120,29 +123,27 @@ class BugReportActivity : VectorBaseActivity() { override fun getMenuRes() = R.menu.bug_report - override fun onPrepareOptionsMenu(menu: Menu): Boolean { + override fun handlePrepareMenu(menu: Menu) { menu.findItem(R.id.ic_action_send_bug_report)?.let { val isValid = !views.bugReportMaskView.isVisible it.isEnabled = isValid it.icon.alpha = if (isValid) 255 else 100 } - - return super.onPrepareOptionsMenu(menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { R.id.ic_action_send_bug_report -> { if (views.bugReportEditText.text.toString().trim().length >= 10) { sendBugReport() } else { views.bugReportTextInputLayout.error = getString(R.string.bug_report_error_too_short) } - return true + true } + else -> false } - return super.onOptionsItemSelected(item) } /** diff --git a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt index f47b5b2411..f9be57b13f 100644 --- a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt @@ -21,7 +21,6 @@ import android.content.Intent import android.graphics.Typeface import android.util.TypedValue import android.view.Menu -import android.view.MenuInflater import android.view.MenuItem import android.widget.SearchView import androidx.core.view.isVisible @@ -33,6 +32,7 @@ import im.vector.app.EmojiCompatFontProvider import im.vector.app.R import im.vector.app.core.extensions.observeEvent import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.databinding.ActivityEmojiReactionPickerBinding import im.vector.app.features.reactions.data.EmojiDataSource import im.vector.lib.core.utils.flow.throttleFirst @@ -48,13 +48,17 @@ import javax.inject.Inject * TODO Finish Refactor to vector base activity */ @AndroidEntryPoint -class EmojiReactionPickerActivity : VectorBaseActivity(), - EmojiCompatFontProvider.FontProviderListener { +class EmojiReactionPickerActivity : + VectorBaseActivity(), + EmojiCompatFontProvider.FontProviderListener, + VectorMenuProvider { lateinit var viewModel: EmojiChooserViewModel override fun getMenuRes() = R.menu.menu_emoji_reaction_picker + override fun handleMenuItemSelected(item: MenuItem) = false + override fun getBinding() = ActivityEmojiReactionPickerBinding.inflate(layoutInflater) override fun getCoordinatorLayout() = views.coordinatorLayout @@ -138,10 +142,7 @@ class EmojiReactionPickerActivity : VectorBaseActivity searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { @@ -175,7 +176,6 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), - PublicRoomsController.Callback { + PublicRoomsController.Callback, + VectorMenuProvider { private val viewModel: RoomDirectoryViewModel by activityViewModel() private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel @@ -105,14 +107,13 @@ class PublicRoomsFragment @Inject constructor( super.onDestroyView() } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun handleMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.menu_room_directory_change_protocol -> { sharedActionViewModel.post(RoomDirectorySharedAction.ChangeProtocol) true } - else -> - super.onOptionsItemSelected(item) + else -> false } } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt index b82da8aa55..88a27f246c 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt @@ -42,6 +42,7 @@ import im.vector.app.core.extensions.copyOnLongClick import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.databinding.DialogBaseEditTextBinding import im.vector.app.databinding.DialogShareQrCodeBinding @@ -74,7 +75,8 @@ class RoomMemberProfileFragment @Inject constructor( private val roomDetailPendingActionStore: RoomDetailPendingActionStore, private val matrixItemColorProvider: MatrixItemColorProvider ) : VectorBaseFragment(), - RoomMemberProfileController.Callback { + RoomMemberProfileController.Callback, + VectorMenuProvider { private lateinit var headerViews: ViewStubRoomMemberProfileHeaderBinding @@ -160,14 +162,14 @@ class RoomMemberProfileFragment @Inject constructor( } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { R.id.roomMemberProfileShareAction -> { viewModel.handle(RoomMemberProfileAction.ShareRoomMemberProfile) - return true + true } + else -> false } - return super.onOptionsItemSelected(item) } private fun handleStartVerification(startVerification: RoomMemberProfileViewEvents.StartVerification) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 1b9912d2e0..2f8128b7af 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -39,6 +39,7 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.copyOnLongClick import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.databinding.FragmentMatrixProfileBinding @@ -70,7 +71,8 @@ class RoomProfileFragment @Inject constructor( private val roomDetailPendingActionStore: RoomDetailPendingActionStore, ) : VectorBaseFragment(), - RoomProfileController.Callback { + RoomProfileController.Callback, + VectorMenuProvider { private lateinit var headerViews: ViewStubRoomProfileHeaderBinding @@ -170,14 +172,14 @@ class RoomProfileFragment @Inject constructor( headerViews.roomProfileAliasView.copyOnLongClick() } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { R.id.roomProfileShareAction -> { roomProfileViewModel.handle(RoomProfileAction.ShareRoomProfile) - return true + true } + else -> false } - return super.onOptionsItemSelected(item) } private fun handleQuickActions(action: RoomListQuickActionsSharedAction) = when (action) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index 4f92524efc..45c8461fa7 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -36,6 +36,7 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.intent.getFilenameFromUri import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.resources.ColorProvider import im.vector.app.core.time.Clock import im.vector.app.core.utils.toast @@ -64,7 +65,8 @@ class RoomSettingsFragment @Inject constructor( VectorBaseFragment(), RoomSettingsController.Callback, OnBackPressed, - GalleryOrCameraDialogHelper.Listener { + GalleryOrCameraDialogHelper.Listener, + VectorMenuProvider { private val viewModel: RoomSettingsViewModel by fragmentViewModel() private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel @@ -139,18 +141,20 @@ class RoomSettingsFragment @Inject constructor( super.onDestroyView() } - override fun onPrepareOptionsMenu(menu: Menu) { + override fun handlePrepareMenu(menu: Menu) { withState(viewModel) { state -> menu.findItem(R.id.roomSettingsSaveAction).isVisible = state.showSaveAction } - super.onPrepareOptionsMenu(menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.roomSettingsSaveAction) { - viewModel.handle(RoomSettingsAction.Save) + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.roomSettingsSaveAction -> { + viewModel.handle(RoomSettingsAction.Save) + true + } + else -> false } - return super.onOptionsItemSelected(item) } override fun invalidate() = withState(viewModel) { viewState -> diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt index 4721fa7bfb..5684e941f1 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt @@ -26,8 +26,6 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.FragmentStateAdapter -import androidx.viewpager2.widget.ViewPager2 -import androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_IDLE import com.airbnb.mvrx.Loading import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -36,6 +34,7 @@ import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.safeOpenOutputStream import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.time.Clock import im.vector.app.core.utils.selectTxtFileToWrite import im.vector.app.databinding.FragmentDevtoolKeyrequestsBinding @@ -44,7 +43,8 @@ import javax.inject.Inject class KeyRequestsFragment @Inject constructor( private val clock: Clock, -) : VectorBaseFragment() { +) : VectorBaseFragment(), + VectorMenuProvider { override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDevtoolKeyrequestsBinding { return FragmentDevtoolKeyrequestsBinding.inflate(inflater, container, false) @@ -61,19 +61,6 @@ class KeyRequestsFragment @Inject constructor( override fun getMenuRes(): Int = R.menu.menu_audit - private val pageAdapterListener = object : ViewPager2.OnPageChangeCallback() { - override fun onPageSelected(position: Int) { - invalidateOptionsMenu() - } - - override fun onPageScrollStateChanged(state: Int) { - childFragmentManager.fragments.forEach { - it.setHasOptionsMenu(state == SCROLL_STATE_IDLE) - } - invalidateOptionsMenu() - } - } - override fun invalidate() = withState(viewModel) { when (it.exporting) { is Loading -> views.exportWaitingView.isVisible = true @@ -81,16 +68,10 @@ class KeyRequestsFragment @Inject constructor( } } - override fun onDestroy() { - invalidateOptionsMenu() - super.onDestroy() - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mPagerAdapter = KeyReqPagerAdapter(this) views.devToolKeyRequestPager.adapter = mPagerAdapter - views.devToolKeyRequestPager.registerOnPageChangeCallback(pageAdapterListener) TabLayoutMediator(views.devToolKeyRequestTabs, views.devToolKeyRequestPager) { tab, position -> when (position) { @@ -119,25 +100,26 @@ class KeyRequestsFragment @Inject constructor( } override fun onDestroyView() { - views.devToolKeyRequestPager.unregisterOnPageChangeCallback(pageAdapterListener) mPagerAdapter = null super.onDestroyView() } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.audit_export) { - selectTxtFileToWrite( - activity = requireActivity(), - activityResultLauncher = epxortAuditForActivityResult, - defaultFileName = "audit-export_${clock.epochMillis()}.txt", - chooserHint = "Export Audit" - ) - return true + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.audit_export -> { + selectTxtFileToWrite( + activity = requireActivity(), + activityResultLauncher = exportAuditForActivityResult, + defaultFileName = "audit-export_${clock.epochMillis()}.txt", + chooserHint = "Export Audit" + ) + true + } + else -> false } - return super.onOptionsItemSelected(item) } - private val epxortAuditForActivityResult = registerStartForActivityResult { activityResult -> + private val exportAuditForActivityResult = registerStartForActivityResult { activityResult -> if (activityResult.resultCode == Activity.RESULT_OK) { val uri = activityResult.data?.data if (uri != null) { diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt index 82462d7cc0..da06f067c6 100644 --- a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt @@ -29,6 +29,7 @@ import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.databinding.FragmentGenericRecyclerBinding import org.matrix.android.sdk.api.session.pushers.Pusher import javax.inject.Inject @@ -36,7 +37,8 @@ import javax.inject.Inject // Referenced in vector_settings_notifications.xml class PushGatewaysFragment @Inject constructor( private val epoxyController: PushGateWayController -) : VectorBaseFragment() { +) : VectorBaseFragment(), + VectorMenuProvider { override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { return FragmentGenericRecyclerBinding.inflate(inflater, container, false) @@ -46,14 +48,13 @@ class PushGatewaysFragment @Inject constructor( override fun getMenuRes() = R.menu.menu_push_gateways - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun handleMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.refresh -> { viewModel.handle(PushGatewayAction.Refresh) true } - else -> - super.onOptionsItemSelected(item) + else -> false } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt index 4cbbbc876d..3818f4278a 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt @@ -38,6 +38,7 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.colorizeMatchingText import im.vector.app.core.utils.isValidUrl @@ -67,7 +68,8 @@ class SpaceDirectoryFragment @Inject constructor( ) : VectorBaseFragment(), SpaceDirectoryController.InteractionListener, TimelineEventController.UrlClickCallback, - OnBackPressed { + OnBackPressed, + VectorMenuProvider { override fun getMenuRes() = R.menu.menu_space_directory @@ -177,40 +179,41 @@ class SpaceDirectoryFragment @Inject constructor( views.addOrCreateChatRoomButton.isVisible = state.canAddRooms } - override fun onPrepareOptionsMenu(menu: Menu) = withState(viewModel) { state -> - menu.findItem(R.id.spaceAddRoom)?.isVisible = state.canAddRooms - menu.findItem(R.id.spaceCreateRoom)?.isVisible = false // Not yet implemented + override fun handlePrepareMenu(menu: Menu) { + withState(viewModel) { state -> + menu.findItem(R.id.spaceAddRoom)?.isVisible = state.canAddRooms + menu.findItem(R.id.spaceCreateRoom)?.isVisible = false // Not yet implemented - menu.findItem(R.id.spaceSearch)?.let { searchItem -> - val searchView = searchItem.actionView as SearchView - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String?): Boolean { - return true - } + menu.findItem(R.id.spaceSearch)?.let { searchItem -> + val searchView = searchItem.actionView as SearchView + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + return true + } - override fun onQueryTextChange(newText: String?): Boolean { - onFilterQueryChanged(newText) - return true - } - }) + override fun onQueryTextChange(newText: String?): Boolean { + onFilterQueryChanged(newText) + return true + } + }) + } } - super.onPrepareOptionsMenu(menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { R.id.spaceAddRoom -> { withState(viewModel) { state -> addExistingRooms(state.spaceId) } - return true + true } R.id.spaceCreateRoom -> { // not implemented yet - return true + true } + else -> false } - return super.onOptionsItemSelected(item) } override fun onFilterQueryChanged(query: String?) { diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt index 071dadb3b4..de1273b8d5 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt @@ -32,6 +32,7 @@ import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.utils.ToggleableAppBarLayoutBehavior import im.vector.app.databinding.FragmentSpaceLeaveAdvancedBinding import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -40,7 +41,8 @@ import javax.inject.Inject class SpaceLeaveAdvancedFragment @Inject constructor( val controller: SelectChildrenController ) : VectorBaseFragment(), - SelectChildrenController.Listener { + SelectChildrenController.Listener, + VectorMenuProvider { override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = FragmentSpaceLeaveAdvancedBinding.inflate(layoutInflater, container, false) @@ -49,6 +51,8 @@ class SpaceLeaveAdvancedFragment @Inject constructor( override fun getMenuRes() = R.menu.menu_space_leave + override fun handleMenuItemSelected(item: MenuItem) = false + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -89,7 +93,7 @@ class SpaceLeaveAdvancedFragment @Inject constructor( } } - override fun onPrepareOptionsMenu(menu: Menu) { + override fun handlePrepareMenu(menu: Menu) { menu.findItem(R.id.menu_space_leave_search)?.let { searchItem -> searchItem.bind( onExpanded = { viewModel.handle(SpaceLeaveAdvanceViewAction.SetFilteringEnabled(isEnabled = true)) }, @@ -97,7 +101,6 @@ class SpaceLeaveAdvancedFragment @Inject constructor( onTextChanged = { viewModel.handle(SpaceLeaveAdvanceViewAction.UpdateFilter(it)) } ) } - super.onPrepareOptionsMenu(menu) } override fun onDestroyView() { diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt index 28d33bd1bf..848c17deb6 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt @@ -36,6 +36,7 @@ import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.databinding.FragmentSpaceAddRoomsBinding import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.debounce @@ -51,7 +52,9 @@ class SpaceAddRoomFragment @Inject constructor( private val roomEpoxyController: AddRoomListController, private val dmEpoxyController: AddRoomListController, ) : VectorBaseFragment(), - OnBackPressed, AddRoomListController.Listener { + OnBackPressed, + AddRoomListController.Listener, + VectorMenuProvider { override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = FragmentSpaceAddRoomsBinding.inflate(layoutInflater, container, false) @@ -151,17 +154,18 @@ class SpaceAddRoomFragment @Inject constructor( } } - override fun onPrepareOptionsMenu(menu: Menu) { - super.onPrepareOptionsMenu(menu) + override fun handlePrepareMenu(menu: Menu) { menu.findItem(R.id.spaceAddRoomSaveItem).isVisible = saveNeeded } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.spaceAddRoomSaveItem) { - viewModel.handle(SpaceAddRoomActions.Save) - return true + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.spaceAddRoomSaveItem -> { + viewModel.handle(SpaceAddRoomActions.Save) + true + } + else -> false } - return super.onOptionsItemSelected(item) } override fun onDestroyView() { diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt index b99fe0f025..eb1de4fe60 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt @@ -37,6 +37,7 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.intent.getFilenameFromUri import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.resources.ColorProvider import im.vector.app.core.time.Clock import im.vector.app.core.utils.toast @@ -66,7 +67,8 @@ class SpaceSettingsFragment @Inject constructor( ) : VectorBaseFragment(), SpaceSettingsController.Callback, GalleryOrCameraDialogHelper.Listener, - OnBackPressed { + OnBackPressed, + VectorMenuProvider { private val viewModel: RoomSettingsViewModel by fragmentViewModel() private val sharedViewModel: SpaceManageSharedViewModel by activityViewModel() @@ -111,18 +113,20 @@ class SpaceSettingsFragment @Inject constructor( super.onDestroyView() } - override fun onPrepareOptionsMenu(menu: Menu) { + override fun handlePrepareMenu(menu: Menu) { withState(viewModel) { state -> menu.findItem(R.id.roomSettingsSaveAction).isVisible = state.showSaveAction } - super.onPrepareOptionsMenu(menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.roomSettingsSaveAction) { - viewModel.handle(RoomSettingsAction.Save) + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.roomSettingsSaveAction -> { + viewModel.handle(RoomSettingsAction.Save) + true + } + else -> false } - return super.onOptionsItemSelected(item) } private fun renderRoomSummary(state: RoomSettingsViewState) { diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt index e893fdf0f3..b31833e37c 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt @@ -23,7 +23,6 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.ScrollView -import androidx.core.view.forEach import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.activityViewModel @@ -37,6 +36,7 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.setupAsSearch import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.showIdentityServerConsentDialog import im.vector.app.core.utils.startSharePlainTextIntent @@ -55,7 +55,8 @@ class UserListFragment @Inject constructor( private val userListController: UserListController, private val dimensionConverter: DimensionConverter, ) : VectorBaseFragment(), - UserListController.Callback { + UserListController.Callback, + VectorMenuProvider { private val args: UserListFragmentArgs by args() private val viewModel: UserListViewModel by activityViewModel() @@ -113,19 +114,24 @@ class UserListFragment @Inject constructor( super.onDestroyView() } - override fun onPrepareOptionsMenu(menu: Menu) { + override fun handlePrepareMenu(menu: Menu) { + if (args.submitMenuItemId == -1) return withState(viewModel) { val showMenuItem = it.pendingSelections.isNotEmpty() - menu.forEach { menuItem -> - menuItem.isVisible = showMenuItem - } + menu.findItem(args.submitMenuItemId).isVisible = showMenuItem } - super.onPrepareOptionsMenu(menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean = withState(viewModel) { - sharedActionViewModel.post(UserListSharedAction.OnMenuItemSelected(item.itemId, it.pendingSelections)) - return@withState true + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + args.submitMenuItemId -> { + withState(viewModel) { + sharedActionViewModel.post(UserListSharedAction.OnMenuItemSubmitClick(it.pendingSelections)) + } + true + } + else -> false + } } private fun setupRecyclerView() { diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt index 795d45272c..d6e55c29ae 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt @@ -23,6 +23,7 @@ import kotlinx.parcelize.Parcelize data class UserListFragmentArgs( val title: String, val menuResId: Int, + val submitMenuItemId: Int, val excludedUserIds: Set? = null, val singleSelection: Boolean = false, val showInviteActions: Boolean = true, diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedAction.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedAction.kt index fca771793b..fb63b05e2f 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedAction.kt @@ -21,7 +21,7 @@ import im.vector.app.core.platform.VectorSharedAction sealed class UserListSharedAction : VectorSharedAction { object Close : UserListSharedAction() object GoBack : UserListSharedAction() - data class OnMenuItemSelected(val itemId: Int, val selections: Set) : UserListSharedAction() + data class OnMenuItemSubmitClick(val selections: Set) : UserListSharedAction() object OpenPhoneBook : UserListSharedAction() object AddByQrCode : UserListSharedAction() } diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt index 0c2df7856f..954f622801 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt @@ -64,8 +64,6 @@ class WidgetActivity : VectorBaseActivity() { override fun getBinding() = ActivityWidgetBinding.inflate(layoutInflater) - override fun getMenuRes() = R.menu.menu_widget - override fun getTitleRes() = R.string.room_widget_activity_title override fun initUiAndData() { diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt index cbd4b8e1ee..5501031e92 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt @@ -42,6 +42,7 @@ import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.utils.openUrlInExternalBrowser import im.vector.app.databinding.FragmentRoomWidgetBinding import im.vector.app.features.webview.WebEventListener @@ -68,7 +69,8 @@ class WidgetFragment @Inject constructor( ) : VectorBaseFragment(), WebEventListener, - OnBackPressed { + OnBackPressed, + VectorMenuProvider { private val fragmentArgs: WidgetArgs by args() private val viewModel: WidgetViewModel by activityViewModel() @@ -79,7 +81,6 @@ class WidgetFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setHasOptionsMenu(true) views.widgetWebView.setupForWidget(this) if (fragmentArgs.kind.isAdmin()) { viewModel.getPostAPIMediator().setWebView(views.widgetWebView) @@ -136,53 +137,64 @@ class WidgetFragment @Inject constructor( } } - override fun onPrepareOptionsMenu(menu: Menu) = withState(viewModel) { state -> - val widget = state.asyncWidget() - menu.findItem(R.id.action_edit)?.isVisible = state.widgetKind != WidgetKind.INTEGRATION_MANAGER - if (widget == null) { - menu.findItem(R.id.action_refresh)?.isVisible = false - menu.findItem(R.id.action_widget_open_ext)?.isVisible = false - menu.findItem(R.id.action_delete)?.isVisible = false - menu.findItem(R.id.action_revoke)?.isVisible = false - } else { - menu.findItem(R.id.action_refresh)?.isVisible = true - menu.findItem(R.id.action_widget_open_ext)?.isVisible = true - menu.findItem(R.id.action_delete)?.isVisible = state.canManageWidgets && widget.isAddedByMe - menu.findItem(R.id.action_revoke)?.isVisible = state.status == WidgetStatus.WIDGET_ALLOWED && !widget.isAddedByMe + override fun getMenuRes() = R.menu.menu_widget + + override fun handlePrepareMenu(menu: Menu) { + withState(viewModel) { state -> + val widget = state.asyncWidget() + menu.findItem(R.id.action_edit)?.isVisible = state.widgetKind != WidgetKind.INTEGRATION_MANAGER + if (widget == null) { + menu.findItem(R.id.action_refresh)?.isVisible = false + menu.findItem(R.id.action_widget_open_ext)?.isVisible = false + menu.findItem(R.id.action_delete)?.isVisible = false + menu.findItem(R.id.action_revoke)?.isVisible = false + } else { + menu.findItem(R.id.action_refresh)?.isVisible = true + menu.findItem(R.id.action_widget_open_ext)?.isVisible = true + menu.findItem(R.id.action_delete)?.isVisible = state.canManageWidgets && widget.isAddedByMe + menu.findItem(R.id.action_revoke)?.isVisible = state.status == WidgetStatus.WIDGET_ALLOWED && !widget.isAddedByMe + } } - super.onPrepareOptionsMenu(menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean = withState(viewModel) { state -> - when (item.itemId) { - R.id.action_edit -> { - navigator.openIntegrationManager( - requireContext(), - integrationManagerActivityResultLauncher, - state.roomId, - state.widgetId, - state.widgetKind.screenId - ) - return@withState true - } - R.id.action_delete -> { - deleteWidget() - return@withState true - } - R.id.action_refresh -> if (state.formattedURL.complete) { - views.widgetWebView.reload() - return@withState true - } - R.id.action_widget_open_ext -> if (state.formattedURL.complete) { - openUrlInExternalBrowser(requireContext(), state.formattedURL.invoke()) - return@withState true - } - R.id.action_revoke -> if (state.status == WidgetStatus.WIDGET_ALLOWED) { - revokeWidget() - return@withState true + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return withState(viewModel) { state -> + return@withState when (item.itemId) { + R.id.action_edit -> { + navigator.openIntegrationManager( + requireContext(), + integrationManagerActivityResultLauncher, + state.roomId, + state.widgetId, + state.widgetKind.screenId + ) + true + } + R.id.action_delete -> { + deleteWidget() + true + } + R.id.action_refresh -> { + if (state.formattedURL.complete) { + views.widgetWebView.reload() + } + true + } + R.id.action_widget_open_ext -> { + if (state.formattedURL.complete) { + openUrlInExternalBrowser(requireContext(), state.formattedURL.invoke()) + } + true + } + R.id.action_revoke -> { + if (state.status == WidgetStatus.WIDGET_ALLOWED) { + revokeWidget() + } + true + } + else -> false } } - return@withState super.onOptionsItemSelected(item) } override fun onBackPressed(toolbarButton: Boolean): Boolean = withState(viewModel) { state ->