Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/6436.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Let your Activity or Fragment implement `VectorMenuProvider` if they provide a menu.
4 changes: 2 additions & 2 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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",
Expand Down
1 change: 1 addition & 0 deletions library/ui-styles/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ android {

dependencies {
implementation libs.androidx.appCompat
implementation libs.androidx.fragmentKtx
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be able to useaddMenuProvider in DebugMaterialThemeActivity

implementation libs.google.material
// Pref theme
implementation libs.androidx.preferenceKtx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)

Expand Down Expand Up @@ -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()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this toast to have a visual feedback

return true
}
},
this,
Lifecycle.State.RESUMED
)
}

private fun showTestDialog(theme: Int) {
MaterialAlertDialogBuilder(this, theme)
.setTitle("Dialog title")
Expand All @@ -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
}
}
5 changes: 5 additions & 0 deletions tools/check/forbidden_strings_in_code.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not deprecated (yet?) on Activities, and better to avoid using a mix of solutions (this was not working well)

Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,30 @@ 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
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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -199,6 +203,8 @@ abstract class VectorBaseActivity<VB : ViewBinding> : 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()
Expand Down Expand Up @@ -249,6 +255,32 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
}
}

private fun setupMenu() {
// Always add a MenuProvider to handle the back action from the Toolbar
Copy link
Member Author

@bmarty bmarty Jul 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean even if getMenuRes() returns -1

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.
*/
Expand Down Expand Up @@ -332,6 +364,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
}

override fun onDestroy() {
removeOnMultiWindowModeChangedListener(onMultiWindowModeChangedListener)
super.onDestroy()
Timber.i("onDestroy Activity ${javaClass.simpleName}")
}
Expand Down Expand Up @@ -417,11 +450,9 @@ abstract class VectorBaseActivity<VB : ViewBinding> : 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<MultiWindowModeChangedInfo> {
Timber.w("onMultiWindowModeChanged. isInMultiWindowMode: ${it.isInMultiWindowMode}")
bugReporter.inMultiWindowMode = it.isInMultiWindowMode
}

protected fun createFragment(fragmentClass: Class<out Fragment>, argsParcelable: Parcelable? = null): Fragment {
Expand Down Expand Up @@ -463,28 +494,14 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
}
}

/* ==========================================================================================
* MENU MANAGEMENT
* ========================================================================================== */

override fun onCreateOptionsMenu(menu: Menu): Boolean {
val menuRes = getMenuRes()

if (menuRes != -1) {
menuInflater.inflate(menuRes, menu)
return true
}

return super.onCreateOptionsMenu(menu)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed(true)
return true
private fun handleMenuItemHome(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
onBackPressed(true)
true
}
else -> false
}

return super.onOptionsItemSelected(item)
}

override fun onBackPressed() {
Expand Down Expand Up @@ -587,9 +604,6 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
@StringRes
open fun getTitleRes() = -1

@MenuRes
open fun getMenuRes() = -1

/**
* Return a object containing other themes for this activity.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -126,9 +130,7 @@ abstract class VectorBaseFragment<VB : ViewBinding> : 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? {
Expand Down Expand Up @@ -158,6 +160,31 @@ abstract class VectorBaseFragment<VB : ViewBinding> : 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?) {
Expand Down Expand Up @@ -270,16 +297,6 @@ abstract class VectorBaseFragment<VB : ViewBinding> : 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()

Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
Loading