Propose unread tab as a lab setting

This commit is contained in:
Valere 2020-07-11 18:38:03 +02:00
parent c6a5d05ffb
commit 7acbd42a45
10 changed files with 100 additions and 44 deletions

View File

@ -17,16 +17,13 @@
package im.vector.riotx.features.home package im.vector.riotx.features.home
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater
import android.view.View import android.view.View
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.forEachIndexed
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import com.google.android.material.bottomnavigation.BottomNavigationItemView import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
@ -44,10 +41,11 @@ import im.vector.riotx.features.call.VectorCallActivity
import im.vector.riotx.features.call.WebRtcPeerConnectionManager import im.vector.riotx.features.call.WebRtcPeerConnectionManager
import im.vector.riotx.features.home.room.list.RoomListFragment import im.vector.riotx.features.home.room.list.RoomListFragment
import im.vector.riotx.features.home.room.list.RoomListParams import im.vector.riotx.features.home.room.list.RoomListParams
import im.vector.riotx.features.home.room.list.UnreadCounterBadgeView
import im.vector.riotx.features.popup.PopupAlertManager import im.vector.riotx.features.popup.PopupAlertManager
import im.vector.riotx.features.popup.VerificationVectorAlert import im.vector.riotx.features.popup.VerificationVectorAlert
import im.vector.riotx.features.settings.VectorPreferences
import im.vector.riotx.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS import im.vector.riotx.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS
import im.vector.riotx.features.themes.ThemeUtils
import im.vector.riotx.features.workers.signout.BannerState import im.vector.riotx.features.workers.signout.BannerState
import im.vector.riotx.features.workers.signout.ServerBackupStatusViewModel import im.vector.riotx.features.workers.signout.ServerBackupStatusViewModel
import im.vector.riotx.features.workers.signout.ServerBackupStatusViewState import im.vector.riotx.features.workers.signout.ServerBackupStatusViewState
@ -55,20 +53,19 @@ import kotlinx.android.synthetic.main.fragment_home_detail.*
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private const val INDEX_CATCHUP = 0 private const val INDEX_PEOPLE = 0
private const val INDEX_PEOPLE = 1 private const val INDEX_ROOMS = 1
private const val INDEX_ROOMS = 2 private const val INDEX_CATCHUP = 2
class HomeDetailFragment @Inject constructor( class HomeDetailFragment @Inject constructor(
val homeDetailViewModelFactory: HomeDetailViewModel.Factory, val homeDetailViewModelFactory: HomeDetailViewModel.Factory,
private val serverBackupStatusViewModelFactory: ServerBackupStatusViewModel.Factory, private val serverBackupStatusViewModelFactory: ServerBackupStatusViewModel.Factory,
private val avatarRenderer: AvatarRenderer, private val avatarRenderer: AvatarRenderer,
private val alertManager: PopupAlertManager, private val alertManager: PopupAlertManager,
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
private val vectorPreferences: VectorPreferences
) : VectorBaseFragment(), KeysBackupBanner.Delegate, ActiveCallView.Callback, ServerBackupStatusViewModel.Factory { ) : VectorBaseFragment(), KeysBackupBanner.Delegate, ActiveCallView.Callback, ServerBackupStatusViewModel.Factory {
private val unreadCounterBadgeViews = arrayListOf<UnreadCounterBadgeView>()
private val viewModel: HomeDetailViewModel by fragmentViewModel() private val viewModel: HomeDetailViewModel by fragmentViewModel()
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel() private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
private val serverBackupStatusViewModel: ServerBackupStatusViewModel by activityViewModel() private val serverBackupStatusViewModel: ServerBackupStatusViewModel by activityViewModel()
@ -128,6 +125,25 @@ class HomeDetailFragment @Inject constructor(
}) })
} }
override fun onResume() {
super.onResume()
// update notification tab if needed
checkNotificationTabStatus()
}
private fun checkNotificationTabStatus() {
val wasVisible = bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible
bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
if (wasVisible && !vectorPreferences.labAddNotificationTab()) {
// As we hide it check if it's not the current item!
withState(viewModel) {
if (it.displayMode.toMenuId() == R.id.bottom_action_notification) {
viewModel.handle(HomeDetailAction.SwitchDisplayMode(RoomListDisplayMode.PEOPLE))
}
}
}
}
private fun promptForNewUnknownDevices(uid: String, state: UnknownDevicesState, newest: DeviceInfo) { private fun promptForNewUnknownDevices(uid: String, state: UnknownDevicesState, newest: DeviceInfo) {
val user = state.myMatrixItem val user = state.myMatrixItem
alertManager.postVectorAlert( alertManager.postVectorAlert(
@ -226,24 +242,27 @@ class HomeDetailFragment @Inject constructor(
} }
private fun setupBottomNavigationView() { private fun setupBottomNavigationView() {
bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
bottomNavigationView.setOnNavigationItemSelectedListener { bottomNavigationView.setOnNavigationItemSelectedListener {
val displayMode = when (it.itemId) { val displayMode = when (it.itemId) {
R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE
R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS
else -> RoomListDisplayMode.HOME else -> RoomListDisplayMode.NOTIFICATIONS
} }
viewModel.handle(HomeDetailAction.SwitchDisplayMode(displayMode)) viewModel.handle(HomeDetailAction.SwitchDisplayMode(displayMode))
true true
} }
val menuView = bottomNavigationView.getChildAt(0) as BottomNavigationMenuView // val menuView = bottomNavigationView.getChildAt(0) as BottomNavigationMenuView
menuView.forEachIndexed { index, view ->
val itemView = view as BottomNavigationItemView // bottomNavigationView.getOrCreateBadge()
val badgeLayout = LayoutInflater.from(requireContext()).inflate(R.layout.vector_home_badge_unread_layout, menuView, false) // menuView.forEachIndexed { index, view ->
val unreadCounterBadgeView: UnreadCounterBadgeView = badgeLayout.findViewById(R.id.actionUnreadCounterBadgeView) // val itemView = view as BottomNavigationItemView
itemView.addView(badgeLayout) // val badgeLayout = LayoutInflater.from(requireContext()).inflate(R.layout.vector_home_badge_unread_layout, menuView, false)
unreadCounterBadgeViews.add(index, unreadCounterBadgeView) // val unreadCounterBadgeView: UnreadCounterBadgeView = badgeLayout.findViewById(R.id.actionUnreadCounterBadgeView)
} // itemView.addView(badgeLayout)
// unreadCounterBadgeViews.add(index, unreadCounterBadgeView)
// }
} }
private fun switchDisplayMode(displayMode: RoomListDisplayMode) { private fun switchDisplayMode(displayMode: RoomListDisplayMode) {
@ -283,16 +302,28 @@ class HomeDetailFragment @Inject constructor(
override fun invalidate() = withState(viewModel) { override fun invalidate() = withState(viewModel) {
Timber.v(it.toString()) Timber.v(it.toString())
unreadCounterBadgeViews[INDEX_CATCHUP].render(UnreadCounterBadgeView.State(it.notificationCountCatchup, it.notificationHighlightCatchup)) bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
unreadCounterBadgeViews[INDEX_PEOPLE].render(UnreadCounterBadgeView.State(it.notificationCountPeople, it.notificationHighlightPeople)) bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
unreadCounterBadgeViews[INDEX_ROOMS].render(UnreadCounterBadgeView.State(it.notificationCountRooms, it.notificationHighlightRooms)) bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
syncStateView.render(it.syncState) syncStateView.render(it.syncState)
} }
private fun BadgeDrawable.render(count: Int, highlight: Boolean) {
isVisible = count > 0
number = count
maxCharacterCount = 3
badgeTextColor = ContextCompat.getColor(requireContext(), R.color.white)
backgroundColor = if (highlight) {
ContextCompat.getColor(requireContext(), R.color.riotx_notice)
} else {
ThemeUtils.getColor(requireContext(), R.attr.riotx_unread_room_badge)
}
}
private fun RoomListDisplayMode.toMenuId() = when (this) { private fun RoomListDisplayMode.toMenuId() = when (this) {
RoomListDisplayMode.PEOPLE -> R.id.bottom_action_people RoomListDisplayMode.PEOPLE -> R.id.bottom_action_people
RoomListDisplayMode.ROOMS -> R.id.bottom_action_rooms RoomListDisplayMode.ROOMS -> R.id.bottom_action_rooms
else -> R.id.bottom_action_home else -> R.id.bottom_action_notification
} }
override fun onTapToReturnToCall() { override fun onTapToReturnToCall() {

View File

@ -20,7 +20,7 @@ import androidx.annotation.StringRes
import im.vector.riotx.R import im.vector.riotx.R
enum class RoomListDisplayMode(@StringRes val titleRes: Int) { enum class RoomListDisplayMode(@StringRes val titleRes: Int) {
HOME(R.string.bottom_action_home), NOTIFICATIONS(R.string.bottom_action_notification),
PEOPLE(R.string.bottom_action_people_x), PEOPLE(R.string.bottom_action_people_x),
ROOMS(R.string.bottom_action_rooms), ROOMS(R.string.bottom_action_rooms),
FILTERED(/* Not used */ 0) FILTERED(/* Not used */ 0)

View File

@ -28,7 +28,7 @@ class RoomListDisplayModeFilter(private val displayMode: RoomListDisplayMode) :
return false return false
} }
return when (displayMode) { return when (displayMode) {
RoomListDisplayMode.HOME -> RoomListDisplayMode.NOTIFICATIONS ->
roomSummary.notificationCount > 0 || roomSummary.membership == Membership.INVITE || roomSummary.userDrafts.isNotEmpty() roomSummary.notificationCount > 0 || roomSummary.membership == Membership.INVITE || roomSummary.userDrafts.isNotEmpty()
RoomListDisplayMode.PEOPLE -> roomSummary.isDirect && roomSummary.membership.isActive() RoomListDisplayMode.PEOPLE -> roomSummary.isDirect && roomSummary.membership.isActive()
RoomListDisplayMode.ROOMS -> !roomSummary.isDirect && roomSummary.membership.isActive() RoomListDisplayMode.ROOMS -> !roomSummary.isDirect && roomSummary.membership.isActive()

View File

@ -138,7 +138,7 @@ class RoomListFragment @Inject constructor(
private fun setupCreateRoomButton() { private fun setupCreateRoomButton() {
when (roomListParams.displayMode) { when (roomListParams.displayMode) {
RoomListDisplayMode.HOME -> createChatFabMenu.isVisible = true RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.isVisible = true
RoomListDisplayMode.PEOPLE -> createChatRoomButton.isVisible = true RoomListDisplayMode.PEOPLE -> createChatRoomButton.isVisible = true
RoomListDisplayMode.ROOMS -> createGroupRoomButton.isVisible = true RoomListDisplayMode.ROOMS -> createGroupRoomButton.isVisible = true
else -> Unit // No button in this mode else -> Unit // No button in this mode
@ -164,7 +164,7 @@ class RoomListFragment @Inject constructor(
RecyclerView.SCROLL_STATE_DRAGGING, RecyclerView.SCROLL_STATE_DRAGGING,
RecyclerView.SCROLL_STATE_SETTLING -> { RecyclerView.SCROLL_STATE_SETTLING -> {
when (roomListParams.displayMode) { when (roomListParams.displayMode) {
RoomListDisplayMode.HOME -> createChatFabMenu.hide() RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.hide()
RoomListDisplayMode.PEOPLE -> createChatRoomButton.hide() RoomListDisplayMode.PEOPLE -> createChatRoomButton.hide()
RoomListDisplayMode.ROOMS -> createGroupRoomButton.hide() RoomListDisplayMode.ROOMS -> createGroupRoomButton.hide()
else -> Unit else -> Unit
@ -207,7 +207,7 @@ class RoomListFragment @Inject constructor(
private val showFabRunnable = Runnable { private val showFabRunnable = Runnable {
if (isAdded) { if (isAdded) {
when (roomListParams.displayMode) { when (roomListParams.displayMode) {
RoomListDisplayMode.HOME -> createChatFabMenu.show() RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.show()
RoomListDisplayMode.PEOPLE -> createChatRoomButton.show() RoomListDisplayMode.PEOPLE -> createChatRoomButton.show()
RoomListDisplayMode.ROOMS -> createGroupRoomButton.show() RoomListDisplayMode.ROOMS -> createGroupRoomButton.show()
else -> Unit else -> Unit
@ -258,7 +258,7 @@ class RoomListFragment @Inject constructor(
roomController.update(state) roomController.update(state)
// Mark all as read menu // Mark all as read menu
when (roomListParams.displayMode) { when (roomListParams.displayMode) {
RoomListDisplayMode.HOME, RoomListDisplayMode.NOTIFICATIONS,
RoomListDisplayMode.PEOPLE, RoomListDisplayMode.PEOPLE,
RoomListDisplayMode.ROOMS -> { RoomListDisplayMode.ROOMS -> {
val newValue = state.hasUnread val newValue = state.hasUnread
@ -288,7 +288,7 @@ class RoomListFragment @Inject constructor(
} }
.isNullOrEmpty() .isNullOrEmpty()
val emptyState = when (roomListParams.displayMode) { val emptyState = when (roomListParams.displayMode) {
RoomListDisplayMode.HOME -> { RoomListDisplayMode.NOTIFICATIONS -> {
if (hasNoRoom) { if (hasNoRoom) {
StateView.State.Empty( StateView.State.Empty(
getString(R.string.room_list_catchup_welcome_title), getString(R.string.room_list_catchup_welcome_title),

View File

@ -147,6 +147,7 @@ class VectorPreferences @Inject constructor(private val context: Context) {
private const val SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY = "SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY" private const val SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY = "SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY"
// SETTINGS_LABS_HIDE_TECHNICAL_E2E_ERRORS // SETTINGS_LABS_HIDE_TECHNICAL_E2E_ERRORS
private const val SETTINGS_LABS_MERGE_E2E_ERRORS = "SETTINGS_LABS_MERGE_E2E_ERRORS" private const val SETTINGS_LABS_MERGE_E2E_ERRORS = "SETTINGS_LABS_MERGE_E2E_ERRORS"
const val SETTINGS_LABS_UNREAD_NOTIFICATIONS_AS_TAB = "SETTINGS_LABS_UNREAD_NOTIFICATIONS_AS_TAB"
// analytics // analytics
const val SETTINGS_USE_ANALYTICS_KEY = "SETTINGS_USE_ANALYTICS_KEY" const val SETTINGS_USE_ANALYTICS_KEY = "SETTINGS_USE_ANALYTICS_KEY"
@ -276,6 +277,10 @@ class VectorPreferences @Inject constructor(private val context: Context) {
return developerMode() && defaultPrefs.getBoolean(SETTINGS_LABS_ALLOW_EXTENDED_LOGS, false) return developerMode() && defaultPrefs.getBoolean(SETTINGS_LABS_ALLOW_EXTENDED_LOGS, false)
} }
fun labAddNotificationTab(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_LABS_UNREAD_NOTIFICATIONS_AS_TAB, false)
}
fun failFast(): Boolean { fun failFast(): Boolean {
return BuildConfig.DEBUG || (developerMode() && defaultPrefs.getBoolean(SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY, false)) return BuildConfig.DEBUG || (developerMode() && defaultPrefs.getBoolean(SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY, false))
} }

View File

@ -34,6 +34,10 @@ class VectorSettingsLabsFragment @Inject constructor(
it.isChecked = vectorPreferences.labAllowedExtendedLogging() it.isChecked = vectorPreferences.labAllowedExtendedLogging()
} }
findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_LABS_UNREAD_NOTIFICATIONS_AS_TAB)?.let {
it.isChecked = vectorPreferences.labAddNotificationTab()
}
// val useCryptoPref = findPreference(VectorPreferences.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_PREFERENCE_KEY) as SwitchPreference // val useCryptoPref = findPreference(VectorPreferences.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_PREFERENCE_KEY) as SwitchPreference
// val cryptoIsEnabledPref = findPreference(VectorPreferences.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_IS_ACTIVE_PREFERENCE_KEY) // val cryptoIsEnabledPref = findPreference(VectorPreferences.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_IS_ACTIVE_PREFERENCE_KEY)

View File

@ -19,12 +19,16 @@ package im.vector.riotx.features.ui
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
import im.vector.riotx.features.home.RoomListDisplayMode import im.vector.riotx.features.home.RoomListDisplayMode
import im.vector.riotx.features.settings.VectorPreferences
import javax.inject.Inject import javax.inject.Inject
/** /**
* This class is used to persist UI state across application restart * This class is used to persist UI state across application restart
*/ */
class SharedPreferencesUiStateRepository @Inject constructor(private val sharedPreferences: SharedPreferences) : UiStateRepository { class SharedPreferencesUiStateRepository @Inject constructor(
private val sharedPreferences: SharedPreferences,
private val vectorPreferences: VectorPreferences
) : UiStateRepository {
override fun reset() { override fun reset() {
sharedPreferences.edit { sharedPreferences.edit {
@ -36,7 +40,11 @@ class SharedPreferencesUiStateRepository @Inject constructor(private val sharedP
return when (sharedPreferences.getInt(KEY_DISPLAY_MODE, VALUE_DISPLAY_MODE_CATCHUP)) { return when (sharedPreferences.getInt(KEY_DISPLAY_MODE, VALUE_DISPLAY_MODE_CATCHUP)) {
VALUE_DISPLAY_MODE_PEOPLE -> RoomListDisplayMode.PEOPLE VALUE_DISPLAY_MODE_PEOPLE -> RoomListDisplayMode.PEOPLE
VALUE_DISPLAY_MODE_ROOMS -> RoomListDisplayMode.ROOMS VALUE_DISPLAY_MODE_ROOMS -> RoomListDisplayMode.ROOMS
else -> RoomListDisplayMode.PEOPLE // RoomListDisplayMode.HOME else -> if (vectorPreferences.labAddNotificationTab()) {
RoomListDisplayMode.NOTIFICATIONS
} else {
RoomListDisplayMode.PEOPLE
}
} }
} }

View File

@ -1,13 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/bottom_action_home"
android:enabled="true"
android:icon="@drawable/ic_home_bottom_catchup"
android:title="@string/bottom_action_home"
android:visible="false" />
<item <item
android:id="@+id/bottom_action_people" android:id="@+id/bottom_action_people"
android:enabled="true" android:enabled="true"
@ -20,4 +13,11 @@
android:icon="@drawable/ic_home_bottom_group" android:icon="@drawable/ic_home_bottom_group"
android:title="@string/bottom_action_rooms" /> android:title="@string/bottom_action_rooms" />
<item
android:id="@+id/bottom_action_notification"
android:enabled="true"
android:icon="@drawable/ic_bell"
android:title="@string/bottom_action_notification"
android:visible="false" />
</menu> </menu>

View File

@ -130,6 +130,7 @@
<!-- Bottom navigation buttons --> <!-- Bottom navigation buttons -->
<string name="bottom_action_home">Home</string> <string name="bottom_action_home">Home</string>
<string name="bottom_action_notification">Notifications</string>
<string name="bottom_action_favourites">Favourites</string> <string name="bottom_action_favourites">Favourites</string>
<string name="bottom_action_people">People</string> <string name="bottom_action_people">People</string>
<string name="bottom_action_rooms">Rooms</string> <string name="bottom_action_rooms">Rooms</string>
@ -1760,6 +1761,7 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming
<string name="labs_swipe_to_reply_in_timeline">Enable swipe to reply in timeline</string> <string name="labs_swipe_to_reply_in_timeline">Enable swipe to reply in timeline</string>
<string name="labs_merge_e2e_in_timeline">Merge failed to decrypt message in timeline</string> <string name="labs_merge_e2e_in_timeline">Merge failed to decrypt message in timeline</string>
<string name="labs_show_unread_notifications_as_tab">Add a dedicated tab for unread notifications on main screen.</string>
<string name="link_copied_to_clipboard">Link copied to clipboard</string> <string name="link_copied_to_clipboard">Link copied to clipboard</string>

View File

@ -44,6 +44,12 @@
android:defaultValue="false" android:defaultValue="false"
android:key="SETTINGS_LABS_MERGE_E2E_ERRORS" android:key="SETTINGS_LABS_MERGE_E2E_ERRORS"
android:title="@string/labs_merge_e2e_in_timeline" /> android:title="@string/labs_merge_e2e_in_timeline" />
<im.vector.riotx.core.preference.VectorSwitchPreference
android:defaultValue="false"
android:key="SETTINGS_LABS_UNREAD_NOTIFICATIONS_AS_TAB"
android:title="@string/labs_show_unread_notifications_as_tab" />
<!--</im.vector.riotx.core.preference.VectorPreferenceCategory>--> <!--</im.vector.riotx.core.preference.VectorPreferenceCategory>-->
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>