Merge branch 'develop' into feature/fix_reply_tag

This commit is contained in:
Valere 2020-07-28 16:58:00 +02:00 committed by GitHub
commit a47ff99be7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 738 additions and 251 deletions

View File

@ -7,6 +7,8 @@ Features ✨:
Improvements 🙌: Improvements 🙌:
- Sending events is now retried only 3 times, so we avoid blocking the sending queue too long. - Sending events is now retried only 3 times, so we avoid blocking the sending queue too long.
- Display warning when fail to send events in room list - Display warning when fail to send events in room list
- Improve UI of edit role action in member profile
- Moderation | New screen to display list of banned users in room settings, with unban action
Bugfix 🐛: Bugfix 🐛:
- Fix theme issue on Room directory screen (#1613) - Fix theme issue on Room directory screen (#1613)
@ -17,6 +19,9 @@ Bugfix 🐛:
- Fix Infinite loop at startup when migrating account from Riot (#1699) - Fix Infinite loop at startup when migrating account from Riot (#1699)
- Fix Element crashes in loop after initial sync (#1709) - Fix Element crashes in loop after initial sync (#1709)
- Remove inner mx-reply tags before replying - Remove inner mx-reply tags before replying
- Fix timeline items not loading when there are only filtered events
- Fix "Voice & Video" grayed out in Settings (#1733)
- Fix Allow VOIP call in all rooms with 2 participants (even if not DM)
Translations 🗣: Translations 🗣:
- -

View File

@ -67,7 +67,7 @@ data class RoomSummary constructor(
get() = tags.any { it.name == RoomTag.ROOM_TAG_FAVOURITE } get() = tags.any { it.name == RoomTag.ROOM_TAG_FAVOURITE }
val canStartCall: Boolean val canStartCall: Boolean
get() = isDirect && joinedMembersCount == 2 get() = joinedMembersCount == 2
companion object { companion object {
const val NOT_IN_BREADCRUMBS = -1 const val NOT_IN_BREADCRUMBS = -1

View File

@ -169,7 +169,7 @@ internal class DefaultTimeline(
filteredEvents = nonFilteredEvents.where() filteredEvents = nonFilteredEvents.where()
.filterEventsWithSettings() .filterEventsWithSettings()
.findAll() .findAll()
filteredEvents.addChangeListener(eventsChangeListener) nonFilteredEvents.addChangeListener(eventsChangeListener)
handleInitialLoad() handleInitialLoad()
if (settings.shouldHandleHiddenReadReceipts()) { if (settings.shouldHandleHiddenReadReceipts()) {
hiddenReadReceipts.start(realm, filteredEvents, nonFilteredEvents, this) hiddenReadReceipts.start(realm, filteredEvents, nonFilteredEvents, this)

View File

@ -77,6 +77,7 @@ import im.vector.riotx.features.roommemberprofile.RoomMemberProfileFragment
import im.vector.riotx.features.roommemberprofile.devices.DeviceListFragment import im.vector.riotx.features.roommemberprofile.devices.DeviceListFragment
import im.vector.riotx.features.roommemberprofile.devices.DeviceTrustInfoActionFragment import im.vector.riotx.features.roommemberprofile.devices.DeviceTrustInfoActionFragment
import im.vector.riotx.features.roomprofile.RoomProfileFragment import im.vector.riotx.features.roomprofile.RoomProfileFragment
import im.vector.riotx.features.roomprofile.banned.RoomBannedMemberListFragment
import im.vector.riotx.features.roomprofile.members.RoomMemberListFragment import im.vector.riotx.features.roomprofile.members.RoomMemberListFragment
import im.vector.riotx.features.roomprofile.settings.RoomSettingsFragment import im.vector.riotx.features.roomprofile.settings.RoomSettingsFragment
import im.vector.riotx.features.roomprofile.uploads.RoomUploadsFragment import im.vector.riotx.features.roomprofile.uploads.RoomUploadsFragment
@ -534,4 +535,9 @@ interface FragmentModule {
@IntoMap @IntoMap
@FragmentKey(ContactsBookFragment::class) @FragmentKey(ContactsBookFragment::class)
fun bindPhoneBookFragment(fragment: ContactsBookFragment): Fragment fun bindPhoneBookFragment(fragment: ContactsBookFragment): Fragment
@Binds
@IntoMap
@FragmentKey(RoomBannedMemberListFragment::class)
fun bindRoomBannedMemberListFragment(fragment: RoomBannedMemberListFragment): Fragment
} }

View File

@ -16,7 +16,9 @@
package im.vector.riotx.core.epoxy package im.vector.riotx.core.epoxy
import android.widget.ProgressBar
import android.widget.TextView import android.widget.TextView
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R import im.vector.riotx.R
@ -26,14 +28,16 @@ import im.vector.riotx.core.extensions.setTextOrHide
abstract class LoadingItem : VectorEpoxyModel<LoadingItem.Holder>() { abstract class LoadingItem : VectorEpoxyModel<LoadingItem.Holder>() {
@EpoxyAttribute var loadingText: String? = null @EpoxyAttribute var loadingText: String? = null
@EpoxyAttribute var showLoader: Boolean = true
override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
holder.progressBar.isVisible = showLoader
holder.textView.setTextOrHide(loadingText) holder.textView.setTextOrHide(loadingText)
} }
class Holder : VectorEpoxyHolder() { class Holder : VectorEpoxyHolder() {
val textView by bind<TextView>(R.id.loadingText) val textView by bind<TextView>(R.id.loadingText)
val progressBar by bind<ProgressBar>(R.id.loadingProgress)
} }
} }

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020 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.riotx.core.epoxy.profiles
import android.view.View
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel
import im.vector.matrix.android.api.util.MatrixItem
import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.features.crypto.util.toImageRes
import im.vector.riotx.features.home.AvatarRenderer
abstract class BaseProfileMatrixItem<T : ProfileMatrixItem.Holder> : VectorEpoxyModel<T>() {
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute lateinit var matrixItem: MatrixItem
@EpoxyAttribute var editable: Boolean = true
@EpoxyAttribute
var userEncryptionTrustLevel: RoomEncryptionTrustLevel? = null
@EpoxyAttribute var clickListener: View.OnClickListener? = null
override fun bind(holder: T) {
super.bind(holder)
val bestName = matrixItem.getBestName()
val matrixId = matrixItem.id
.takeIf { it != bestName }
// Special case for ThreePid fake matrix item
.takeIf { it != "@" }
holder.view.setOnClickListener(clickListener?.takeIf { editable })
holder.titleView.text = bestName
holder.subtitleView.setTextOrHide(matrixId)
holder.editableView.isVisible = editable
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.avatarDecorationImageView.setImageResource(userEncryptionTrustLevel.toImageRes())
}
}

View File

@ -20,43 +20,14 @@ package im.vector.riotx.core.epoxy.profiles
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel
import im.vector.matrix.android.api.util.MatrixItem
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.epoxy.VectorEpoxyHolder import im.vector.riotx.core.epoxy.VectorEpoxyHolder
import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.features.crypto.util.toImageRes
import im.vector.riotx.features.home.AvatarRenderer
@EpoxyModelClass(layout = R.layout.item_profile_matrix_item) @EpoxyModelClass(layout = R.layout.item_profile_matrix_item)
abstract class ProfileMatrixItem : VectorEpoxyModel<ProfileMatrixItem.Holder>() { abstract class ProfileMatrixItem : BaseProfileMatrixItem<ProfileMatrixItem.Holder>() {
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer open class Holder : VectorEpoxyHolder() {
@EpoxyAttribute lateinit var matrixItem: MatrixItem
@EpoxyAttribute var editable: Boolean = true
@EpoxyAttribute var userEncryptionTrustLevel: RoomEncryptionTrustLevel? = null
@EpoxyAttribute var clickListener: View.OnClickListener? = null
override fun bind(holder: Holder) {
super.bind(holder)
val bestName = matrixItem.getBestName()
val matrixId = matrixItem.id
.takeIf { it != bestName }
// Special case for ThreePid fake matrix item
.takeIf { it != "@" }
holder.view.setOnClickListener(clickListener?.takeIf { editable })
holder.titleView.text = bestName
holder.subtitleView.setTextOrHide(matrixId)
holder.editableView.isVisible = editable
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.avatarDecorationImageView.setImageResource(userEncryptionTrustLevel.toImageRes())
}
class Holder : VectorEpoxyHolder() {
val titleView by bind<TextView>(R.id.matrixItemTitle) val titleView by bind<TextView>(R.id.matrixItemTitle)
val subtitleView by bind<TextView>(R.id.matrixItemSubtitle) val subtitleView by bind<TextView>(R.id.matrixItemSubtitle)
val avatarImageView by bind<ImageView>(R.id.matrixItemAvatar) val avatarImageView by bind<ImageView>(R.id.matrixItemAvatar)

View File

@ -0,0 +1,39 @@
/*
* Copyright 2020 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.riotx.core.epoxy.profiles
import android.widget.ProgressBar
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R
@EpoxyModelClass(layout = R.layout.item_profile_matrix_item_progress)
abstract class ProfileMatrixItemWithProgress : BaseProfileMatrixItem<ProfileMatrixItemWithProgress.Holder>() {
@EpoxyAttribute var inProgress: Boolean = true
override fun bind(holder: Holder) {
super.bind(holder)
holder.progress.isVisible = inProgress
}
class Holder : ProfileMatrixItem.Holder() {
val progress by bind<ProgressBar>(R.id.matrixItemProgress)
}
}

View File

@ -74,7 +74,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
fun onEncryptedMessageClicked(informationData: MessageInformationData, view: View) fun onEncryptedMessageClicked(informationData: MessageInformationData, view: View)
fun onImageMessageClicked(messageImageContent: MessageImageInfoContent, mediaData: ImageContentRenderer.Data, view: View) fun onImageMessageClicked(messageImageContent: MessageImageInfoContent, mediaData: ImageContentRenderer.Data, view: View)
fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: VideoContentRenderer.Data, view: View) fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: VideoContentRenderer.Data, view: View)
// fun onFileMessageClicked(eventId: String, messageFileContent: MessageFileContent)
// fun onFileMessageClicked(eventId: String, messageFileContent: MessageFileContent)
// fun onAudioMessageClicked(messageAudioContent: MessageAudioContent) // fun onAudioMessageClicked(messageAudioContent: MessageAudioContent)
fun onEditedDecorationClicked(informationData: MessageInformationData) fun onEditedDecorationClicked(informationData: MessageInformationData)
@ -107,7 +108,6 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
fun onUrlLongClicked(url: String): Boolean fun onUrlLongClicked(url: String): Boolean
} }
private var showingForwardLoader = false
// Map eventId to adapter position // Map eventId to adapter position
private val adapterPositionMapping = HashMap<String, Int>() private val adapterPositionMapping = HashMap<String, Int>()
private val modelCache = arrayListOf<CacheItemData?>() private val modelCache = arrayListOf<CacheItemData?>()
@ -233,7 +233,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
override fun buildModels() { override fun buildModels() {
val timestamp = System.currentTimeMillis() val timestamp = System.currentTimeMillis()
showingForwardLoader = LoadingItem_()
val showingForwardLoader = LoadingItem_()
.id("forward_loading_item_$timestamp") .id("forward_loading_item_$timestamp")
.setVisibilityStateChangedListener(Timeline.Direction.FORWARDS) .setVisibilityStateChangedListener(Timeline.Direction.FORWARDS)
.addWhenLoading(Timeline.Direction.FORWARDS) .addWhenLoading(Timeline.Direction.FORWARDS)
@ -242,12 +243,13 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
add(timelineModels) add(timelineModels)
// Avoid displaying two loaders if there is no elements between them // Avoid displaying two loaders if there is no elements between them
if (!showingForwardLoader || timelineModels.isNotEmpty()) { val showBackwardsLoader = !showingForwardLoader || timelineModels.isNotEmpty()
LoadingItem_() // We can hide the loader but still add the item to controller so it can trigger backwards pagination
.id("backward_loading_item_$timestamp") LoadingItem_()
.setVisibilityStateChangedListener(Timeline.Direction.BACKWARDS) .id("backward_loading_item_$timestamp")
.addWhenLoading(Timeline.Direction.BACKWARDS) .setVisibilityStateChangedListener(Timeline.Direction.BACKWARDS)
} .showLoader(showBackwardsLoader)
.addWhenLoading(Timeline.Direction.BACKWARDS)
} }
// Timeline.LISTENER *************************************************************************** // Timeline.LISTENER ***************************************************************************

View File

@ -19,12 +19,10 @@ package im.vector.riotx.features.login
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.children
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
@ -73,14 +71,6 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
get() = supportFragmentManager.findFragmentById(R.id.loginFragmentContainer) get() = supportFragmentManager.findFragmentById(R.id.loginFragmentContainer)
private val commonOption: (FragmentTransaction) -> Unit = { ft -> private val commonOption: (FragmentTransaction) -> Unit = { ft ->
// Find the loginLogo on the current Fragment, this should not return null
(topFragment?.view as? ViewGroup)
// Find findViewById does not work, I do not know why
// findViewById<View?>(R.id.loginLogo)
?.children
?.firstOrNull { it.id == R.id.loginLogo }
?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") }
// TODO
ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim) ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim)
} }
@ -145,7 +135,6 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(R.id.loginFragmentContainer,
LoginServerSelectionFragment::class.java, LoginServerSelectionFragment::class.java,
option = { ft -> option = { ft ->
findViewById<View?>(R.id.loginSplashLogo)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") }
findViewById<View?>(R.id.loginSplashTitle)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") } findViewById<View?>(R.id.loginSplashTitle)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") }
findViewById<View?>(R.id.loginSplashSubmit)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") } findViewById<View?>(R.id.loginSplashSubmit)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") }
// TODO Disabled because it provokes a flickering // TODO Disabled because it provokes a flickering

View File

@ -236,10 +236,12 @@ class RoomMemberProfileController @Inject constructor(
if (canEditPowerLevel) { if (canEditPowerLevel) {
buildProfileAction( buildProfileAction(
id = "edit_power_level", id = "edit_power_level",
editable = false, editable = true,
title = powerLevelsStr, title = stringProvider.getString(R.string.power_level_title),
subtitle = powerLevelsStr,
divider = canKick || canBan, divider = canKick || canBan,
dividerColor = dividerColor, dividerColor = dividerColor,
editableRes = R.drawable.ic_edit,
action = { callback?.onEditPowerLevel(userPowerLevel) } action = { callback?.onEditPowerLevel(userPowerLevel) }
) )
} }

View File

@ -32,6 +32,7 @@ import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.features.room.RequireActiveMembershipViewEvents import im.vector.riotx.features.room.RequireActiveMembershipViewEvents
import im.vector.riotx.features.room.RequireActiveMembershipViewModel import im.vector.riotx.features.room.RequireActiveMembershipViewModel
import im.vector.riotx.features.room.RequireActiveMembershipViewState import im.vector.riotx.features.room.RequireActiveMembershipViewState
import im.vector.riotx.features.roomprofile.banned.RoomBannedMemberListFragment
import im.vector.riotx.features.roomprofile.members.RoomMemberListFragment import im.vector.riotx.features.roomprofile.members.RoomMemberListFragment
import im.vector.riotx.features.roomprofile.settings.RoomSettingsFragment import im.vector.riotx.features.roomprofile.settings.RoomSettingsFragment
import im.vector.riotx.features.roomprofile.uploads.RoomUploadsFragment import im.vector.riotx.features.roomprofile.uploads.RoomUploadsFragment
@ -81,9 +82,10 @@ class RoomProfileActivity :
.observe() .observe()
.subscribe { sharedAction -> .subscribe { sharedAction ->
when (sharedAction) { when (sharedAction) {
is RoomProfileSharedAction.OpenRoomMembers -> openRoomMembers() is RoomProfileSharedAction.OpenRoomMembers -> openRoomMembers()
is RoomProfileSharedAction.OpenRoomSettings -> openRoomSettings() is RoomProfileSharedAction.OpenRoomSettings -> openRoomSettings()
is RoomProfileSharedAction.OpenRoomUploads -> openRoomUploads() is RoomProfileSharedAction.OpenRoomUploads -> openRoomUploads()
is RoomProfileSharedAction.OpenBannedRoomMembers -> openBannedRoomMembers()
} }
} }
.disposeOnDestroy() .disposeOnDestroy()
@ -114,6 +116,10 @@ class RoomProfileActivity :
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs) addFragmentToBackstack(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs)
} }
private fun openBannedRoomMembers() {
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomBannedMemberListFragment::class.java, roomProfileArgs)
}
override fun configure(toolbar: Toolbar) { override fun configure(toolbar: Toolbar) {
configureToolbar(toolbar) configureToolbar(toolbar)
} }

View File

@ -41,6 +41,7 @@ class RoomProfileController @Inject constructor(
interface Callback { interface Callback {
fun onLearnMoreClicked() fun onLearnMoreClicked()
fun onMemberListClicked() fun onMemberListClicked()
fun onBannedMemberListClicked()
fun onNotificationsClicked() fun onNotificationsClicked()
fun onUploadsClicked() fun onUploadsClicked()
fun onSettingsClicked() fun onSettingsClicked()
@ -92,6 +93,16 @@ class RoomProfileController @Inject constructor(
accessory = R.drawable.ic_shield_warning.takeIf { hasWarning } ?: 0, accessory = R.drawable.ic_shield_warning.takeIf { hasWarning } ?: 0,
action = { callback?.onMemberListClicked() } action = { callback?.onMemberListClicked() }
) )
if (data.bannedMembership.invoke()?.isNotEmpty() == true) {
buildProfileAction(
id = "banned_list",
title = stringProvider.getString(R.string.room_settings_banned_users_title),
dividerColor = dividerColor,
icon = R.drawable.ic_settings_root_labs,
action = { callback?.onBannedMemberListClicked() }
)
}
buildProfileAction( buildProfileAction(
id = "uploads", id = "uploads",
title = stringProvider.getString(R.string.room_profile_section_more_uploads), title = stringProvider.getString(R.string.room_profile_section_more_uploads),

View File

@ -206,6 +206,10 @@ class RoomProfileFragment @Inject constructor(
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomMembers) roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomMembers)
} }
override fun onBannedMemberListClicked() {
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenBannedRoomMembers)
}
override fun onSettingsClicked() { override fun onSettingsClicked() {
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomSettings) roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomSettings)
} }

View File

@ -25,4 +25,5 @@ sealed class RoomProfileSharedAction : VectorSharedAction {
object OpenRoomSettings : RoomProfileSharedAction() object OpenRoomSettings : RoomProfileSharedAction()
object OpenRoomUploads : RoomProfileSharedAction() object OpenRoomUploads : RoomProfileSharedAction()
object OpenRoomMembers : RoomProfileSharedAction() object OpenRoomMembers : RoomProfileSharedAction()
object OpenBannedRoomMembers : RoomProfileSharedAction()
} }

View File

@ -26,6 +26,8 @@ import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.permalinks.PermalinkFactory import im.vector.matrix.android.api.permalinks.PermalinkFactory
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.room.members.roomMemberQueryParams
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
import im.vector.matrix.rx.rx import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap import im.vector.matrix.rx.unwrap
@ -61,7 +63,8 @@ class RoomProfileViewModel @AssistedInject constructor(@Assisted private val ini
} }
private fun observeRoomSummary() { private fun observeRoomSummary() {
room.rx().liveRoomSummary() val rxRoom = room.rx()
rxRoom.liveRoomSummary()
.unwrap() .unwrap()
.execute { .execute {
copy(roomSummary = it) copy(roomSummary = it)
@ -73,10 +76,17 @@ class RoomProfileViewModel @AssistedInject constructor(@Assisted private val ini
.subscribe { .subscribe {
val powerLevelsHelper = PowerLevelsHelper(it) val powerLevelsHelper = PowerLevelsHelper(it)
setState { setState {
copy(canChangeAvatar = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR)) copy(canChangeAvatar = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR))
} }
} }
.disposeOnClear() .disposeOnClear()
rxRoom.liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) })
.execute {
copy(
bannedMembership = it
)
}
} }
override fun handle(action: RoomProfileAction) = when (action) { override fun handle(action: RoomProfileAction) = when (action) {

View File

@ -20,11 +20,13 @@ package im.vector.riotx.features.roomprofile
import com.airbnb.mvrx.Async import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
data class RoomProfileViewState( data class RoomProfileViewState(
val roomId: String, val roomId: String,
val roomSummary: Async<RoomSummary> = Uninitialized, val roomSummary: Async<RoomSummary> = Uninitialized,
val bannedMembership: Async<List<RoomMemberSummary>> = Uninitialized,
val canChangeAvatar: Boolean = false val canChangeAvatar: Boolean = false
) : MvRxState { ) : MvRxState {

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 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.riotx.features.roomprofile.banned
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.riotx.core.platform.VectorViewModelAction
sealed class RoomBannedListMemberAction : VectorViewModelAction {
data class QueryInfo(val roomMemberSummary: RoomMemberSummary) : RoomBannedListMemberAction()
data class UnBanUser(val roomMemberSummary: RoomMemberSummary) : RoomBannedListMemberAction()
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2020 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.riotx.features.roomprofile.banned
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.query.QueryStringValue
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.members.roomMemberQueryParams
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomMemberContent
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
import im.vector.matrix.android.internal.util.awaitCallback
import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.powerlevel.PowerLevelsObservableFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class RoomBannedListMemberViewModel @AssistedInject constructor(@Assisted initialState: RoomBannedMemberListViewState,
private val stringProvider: StringProvider,
private val session: Session)
: VectorViewModel<RoomBannedMemberListViewState, RoomBannedListMemberAction, RoomBannedViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
fun create(initialState: RoomBannedMemberListViewState): RoomBannedListMemberViewModel
}
private val room = session.getRoom(initialState.roomId)!!
init {
val rxRoom = room.rx()
room.rx().liveRoomSummary()
.unwrap()
.execute { async ->
copy(roomSummary = async)
}
rxRoom.liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) })
.execute {
copy(
bannedMemberSummaries = it
)
}
val powerLevelsContentLive = PowerLevelsObservableFactory(room).createObservable()
powerLevelsContentLive.subscribe {
val powerLevelsHelper = PowerLevelsHelper(it)
setState { copy(canUserBan = powerLevelsHelper.isUserAbleToBan(session.myUserId)) }
}.disposeOnClear()
}
companion object : MvRxViewModelFactory<RoomBannedListMemberViewModel, RoomBannedMemberListViewState> {
@JvmStatic
override fun create(viewModelContext: ViewModelContext, state: RoomBannedMemberListViewState): RoomBannedListMemberViewModel? {
val fragment: RoomBannedMemberListFragment = (viewModelContext as FragmentViewModelContext).fragment()
return fragment.viewModelFactory.create(state)
}
}
override fun handle(action: RoomBannedListMemberAction) {
when (action) {
is RoomBannedListMemberAction.QueryInfo -> onQueryBanInfo(action.roomMemberSummary)
is RoomBannedListMemberAction.UnBanUser -> unBanUser(action.roomMemberSummary)
}
}
private fun onQueryBanInfo(roomMemberSummary: RoomMemberSummary) {
val bannedEvent = room.getStateEvent(EventType.STATE_ROOM_MEMBER, QueryStringValue.Equals(roomMemberSummary.userId))
val content = bannedEvent?.getClearContent().toModel<RoomMemberContent>()
if (content?.membership != Membership.BAN) {
// may be report error?
return
}
val reason = content.reason
val bannedBy = bannedEvent?.senderId ?: return
_viewEvents.post(RoomBannedViewEvents.ShowBannedInfo(bannedBy, reason ?: "", roomMemberSummary))
}
private fun unBanUser(roomMemberSummary: RoomMemberSummary) {
setState {
copy(onGoingModerationAction = this.onGoingModerationAction + roomMemberSummary.userId)
}
viewModelScope.launch(Dispatchers.IO) {
try {
awaitCallback<Unit> {
room.unban(roomMemberSummary.userId, null, it)
}
} catch (failure: Throwable) {
_viewEvents.post(RoomBannedViewEvents.ToastError(stringProvider.getString(R.string.failed_to_unban)))
} finally {
setState {
copy(
onGoingModerationAction = onGoingModerationAction - roomMemberSummary.userId
)
}
}
}
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2020 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.riotx.features.roomprofile.banned
import com.airbnb.epoxy.TypedEpoxyController
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.riotx.R
import im.vector.riotx.core.epoxy.dividerItem
import im.vector.riotx.core.epoxy.profiles.buildProfileSection
import im.vector.riotx.core.epoxy.profiles.profileMatrixItemWithProgress
import im.vector.riotx.core.extensions.join
import im.vector.riotx.core.resources.ColorProvider
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.ui.list.genericFooterItem
import im.vector.riotx.features.home.AvatarRenderer
import javax.inject.Inject
class RoomBannedMemberListController @Inject constructor(
private val avatarRenderer: AvatarRenderer,
private val stringProvider: StringProvider,
colorProvider: ColorProvider
) : TypedEpoxyController<RoomBannedMemberListViewState>() {
interface Callback {
fun onUnbanClicked(roomMember: RoomMemberSummary)
}
private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color)
var callback: Callback? = null
init {
setData(null)
}
override fun buildModels(data: RoomBannedMemberListViewState?) {
val bannedList = data?.bannedMemberSummaries?.invoke() ?: return
buildProfileSection(
stringProvider.getString(R.string.room_settings_banned_users_title)
)
bannedList.join(
each = { _, roomMember ->
val actionInProgress = data.onGoingModerationAction.contains(roomMember.userId)
profileMatrixItemWithProgress {
id(roomMember.userId)
matrixItem(roomMember.toMatrixItem())
avatarRenderer(avatarRenderer)
apply {
if (actionInProgress) {
inProgress(true)
editable(false)
} else {
inProgress(false)
editable(true)
clickListener { _ ->
callback?.onUnbanClicked(roomMember)
}
}
}
}
},
between = { _, roomMemberBefore ->
dividerItem {
id("divider_${roomMemberBefore.userId}")
color(dividerColor)
}
}
)
genericFooterItem {
id("footer")
text(stringProvider.getQuantityString(R.plurals.room_settings_banned_users_count, bannedList.size, bannedList.size))
}
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2020 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.riotx.features.roomprofile.banned
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.riotx.R
import im.vector.riotx.core.extensions.cleanup
import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.toast
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.roomprofile.RoomProfileArgs
import kotlinx.android.synthetic.main.fragment_room_setting_generic.*
import javax.inject.Inject
class RoomBannedMemberListFragment @Inject constructor(
val viewModelFactory: RoomBannedListMemberViewModel.Factory,
private val roomMemberListController: RoomBannedMemberListController,
private val avatarRenderer: AvatarRenderer
) : VectorBaseFragment(), RoomBannedMemberListController.Callback {
private val viewModel: RoomBannedListMemberViewModel by fragmentViewModel()
private val roomProfileArgs: RoomProfileArgs by args()
override fun getLayoutResId() = R.layout.fragment_room_setting_generic
override fun onUnbanClicked(roomMember: RoomMemberSummary) {
viewModel.handle(RoomBannedListMemberAction.QueryInfo(roomMember))
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
roomMemberListController.callback = this
setupToolbar(roomSettingsToolbar)
recyclerView.configureWith(roomMemberListController, hasFixedSize = true)
viewModel.observeViewEvents {
when (it) {
is RoomBannedViewEvents.ShowBannedInfo -> {
val canBan = withState(viewModel) { state -> state.canUserBan }
AlertDialog.Builder(requireActivity())
.setTitle(getString(R.string.member_banned_by, it.bannedByUserId))
.setMessage(getString(R.string.reason_colon, it.banReason))
.setPositiveButton(R.string.ok, null)
.apply {
if (canBan) {
setNegativeButton(R.string.room_participants_action_unban) { _, _ ->
viewModel.handle(RoomBannedListMemberAction.UnBanUser(it.roomMemberSummary))
}
}
}
.show()
}
is RoomBannedViewEvents.ToastError -> {
requireActivity().toast(it.info)
}
}
}
}
override fun onDestroyView() {
recyclerView.cleanup()
super.onDestroyView()
}
override fun invalidate() = withState(viewModel) { viewState ->
roomMemberListController.setData(viewState)
renderRoomSummary(viewState)
}
private fun renderRoomSummary(state: RoomBannedMemberListViewState) {
state.roomSummary()?.let {
roomSettingsToolbarTitleView.text = it.displayName
avatarRenderer.render(it.toMatrixItem(), roomSettingsToolbarAvatarImageView)
}
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2020 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.riotx.features.roomprofile.banned
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.Uninitialized
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotx.features.roomprofile.RoomProfileArgs
data class RoomBannedMemberListViewState(
val roomId: String,
val roomSummary: Async<RoomSummary> = Uninitialized,
val bannedMemberSummaries: Async<List<RoomMemberSummary>> = Uninitialized,
val onGoingModerationAction: List<String> = emptyList(),
val canUserBan: Boolean = false
) : MvRxState {
constructor(args: RoomProfileArgs) : this(roomId = args.roomId)
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 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.riotx.features.roomprofile.banned
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.riotx.core.platform.VectorViewEvents
sealed class RoomBannedViewEvents : VectorViewEvents {
data class ShowBannedInfo(val bannedByUserId: String, val banReason: String, val roomMemberSummary: RoomMemberSummary) : RoomBannedViewEvents()
data class ToastError(val info: String) : RoomBannedViewEvents()
}

View File

@ -28,7 +28,6 @@ import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.login.LoginMode import im.vector.riotx.features.login.LoginMode
import im.vector.riotx.features.signout.soft.epoxy.loginCenterButtonItem import im.vector.riotx.features.signout.soft.epoxy.loginCenterButtonItem
import im.vector.riotx.features.signout.soft.epoxy.loginErrorWithRetryItem import im.vector.riotx.features.signout.soft.epoxy.loginErrorWithRetryItem
import im.vector.riotx.features.signout.soft.epoxy.loginHeaderItem
import im.vector.riotx.features.signout.soft.epoxy.loginPasswordFormItem import im.vector.riotx.features.signout.soft.epoxy.loginPasswordFormItem
import im.vector.riotx.features.signout.soft.epoxy.loginRedButtonItem import im.vector.riotx.features.signout.soft.epoxy.loginRedButtonItem
import im.vector.riotx.features.signout.soft.epoxy.loginTextItem import im.vector.riotx.features.signout.soft.epoxy.loginTextItem
@ -65,9 +64,6 @@ class SoftLogoutController @Inject constructor(
} }
private fun buildHeader(state: SoftLogoutViewState) { private fun buildHeader(state: SoftLogoutViewState) {
loginHeaderItem {
id("header")
}
loginTitleItem { loginTitleItem {
id("title") id("title")
text(stringProvider.getString(R.string.soft_logout_title)) text(stringProvider.getString(R.string.soft_logout_title))

View File

@ -1,27 +0,0 @@
/*
* Copyright 2019 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.riotx.features.signout.soft.epoxy
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
import im.vector.riotx.core.epoxy.VectorEpoxyModel
@EpoxyModelClass(layout = R.layout.item_login_header)
abstract class LoginHeaderItem : VectorEpoxyModel<LoginHeaderItem.Holder>() {
class Holder : VectorEpoxyHolder()
}

View File

@ -1,27 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="155dp"
android:height="33dp"
android:viewportWidth="155"
android:viewportHeight="33">
<path
android:pathData="M21.533,22.855H4.969C5.165,24.595 5.794,25.985 6.856,27.023C7.918,28.034 9.316,28.539 11.05,28.539C12.196,28.539 13.23,28.258 14.153,27.697C15.075,27.135 15.732,26.378 16.124,25.423H21.156C20.485,27.641 19.227,29.437 17.382,30.812C15.564,32.16 13.412,32.833 10.924,32.833C7.681,32.833 5.053,31.753 3.04,29.591C1.055,27.43 0.063,24.694 0.063,21.381C0.063,18.153 1.069,15.445 3.082,13.255C5.095,11.066 7.695,9.972 10.882,9.972C14.069,9.972 16.641,11.052 18.598,13.213C20.583,15.347 21.575,18.041 21.575,21.297L21.533,22.855ZM10.882,14.056C9.316,14.056 8.016,14.519 6.982,15.445C5.947,16.371 5.304,17.606 5.053,19.15H16.627C16.403,17.606 15.788,16.371 14.782,15.445C13.775,14.519 12.475,14.056 10.882,14.056Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M25.009,25.802V0.751H30V25.886C30,27.009 30.615,27.57 31.845,27.57L32.725,27.528V32.286C32.25,32.37 31.747,32.412 31.216,32.412C29.063,32.412 27.483,31.865 26.477,30.77C25.499,29.676 25.009,28.02 25.009,25.802Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M55.966,22.855H39.401C39.597,24.595 40.226,25.985 41.289,27.023C42.351,28.034 43.749,28.539 45.482,28.539C46.628,28.539 47.663,28.258 48.585,27.697C49.508,27.135 50.165,26.378 50.556,25.423H55.588C54.917,27.641 53.659,29.437 51.814,30.812C49.997,32.16 47.844,32.833 45.356,32.833C42.113,32.833 39.485,31.753 37.472,29.591C35.487,27.43 34.495,24.694 34.495,21.381C34.495,18.153 35.501,15.445 37.514,13.255C39.527,11.066 42.127,9.972 45.314,9.972C48.501,9.972 51.073,11.052 53.03,13.213C55.015,15.347 56.008,18.041 56.008,21.297L55.966,22.855ZM45.314,14.056C43.749,14.056 42.449,14.519 41.414,15.445C40.38,16.371 39.737,17.606 39.485,19.15H51.059C50.836,17.606 50.221,16.371 49.214,15.445C48.208,14.519 46.908,14.056 45.314,14.056Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M78.48,19.781V32.328H73.49V19.234C73.49,15.922 72.12,14.266 69.38,14.266C67.899,14.266 66.711,14.743 65.816,15.698C64.949,16.652 64.516,17.957 64.516,19.613V32.328H59.526V10.477H64.138V13.382C64.67,12.399 65.48,11.585 66.571,10.94C67.661,10.294 69.017,9.972 70.638,9.972C73.658,9.972 75.838,11.122 77.18,13.424C79.025,11.122 81.486,9.972 84.561,9.972C87.105,9.972 89.062,10.771 90.432,12.371C91.802,13.943 92.487,16.02 92.487,18.603V32.328H87.496V19.234C87.496,15.922 86.126,14.266 83.387,14.266C81.877,14.266 80.675,14.757 79.78,15.74C78.914,16.694 78.48,18.041 78.48,19.781Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M117.304,22.855H100.739C100.935,24.595 101.564,25.985 102.627,27.023C103.689,28.034 105.087,28.539 106.82,28.539C107.966,28.539 109.001,28.258 109.923,27.697C110.846,27.135 111.503,26.378 111.894,25.423H116.926C116.255,27.641 114.997,29.437 113.152,30.812C111.335,32.16 109.182,32.833 106.694,32.833C103.451,32.833 100.823,31.753 98.811,29.591C96.826,27.43 95.833,24.694 95.833,21.381C95.833,18.153 96.84,15.445 98.852,13.255C100.865,11.066 103.465,9.972 106.652,9.972C109.839,9.972 112.411,11.052 114.368,13.213C116.353,15.347 117.346,18.041 117.346,21.297L117.304,22.855ZM106.652,14.056C105.087,14.056 103.787,14.519 102.752,15.445C101.718,16.371 101.075,17.606 100.823,19.15H112.397C112.174,17.606 111.559,16.371 110.552,15.445C109.546,14.519 108.246,14.056 106.652,14.056Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M125.477,10.477V13.382C125.98,12.427 126.804,11.628 127.951,10.982C129.125,10.308 130.537,9.972 132.186,9.972C134.758,9.972 136.743,10.757 138.141,12.329C139.567,13.901 140.28,15.992 140.28,18.603V32.328H135.289V19.234C135.289,17.69 134.926,16.483 134.199,15.613C133.5,14.715 132.424,14.266 130.97,14.266C129.376,14.266 128.118,14.743 127.196,15.698C126.301,16.652 125.854,17.971 125.854,19.655V32.328H120.864V10.477H125.477Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M154.854,27.865V32.202C154.239,32.37 153.372,32.454 152.254,32.454C148.004,32.454 145.88,30.307 145.88,26.013V14.476H142.567V10.477H145.88V4.793H150.87V10.477H154.938V14.476H150.87V25.507C150.87,27.22 151.681,28.076 153.302,28.076L154.854,27.865Z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -0,0 +1,43 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="369dp"
android:height="211dp"
android:viewportWidth="369"
android:viewportHeight="211">
<path
android:pathData="M51.155,186.5H11.69C12.156,190.633 13.655,193.933 16.186,196.4C18.717,198.8 22.047,200 26.177,200C28.908,200 31.373,199.333 33.571,198C35.769,196.667 37.334,194.867 38.267,192.6H50.256C48.658,197.867 45.66,202.133 41.264,205.4C36.934,208.6 31.806,210.2 25.877,210.2C18.151,210.2 11.89,207.633 7.094,202.5C2.365,197.367 0,190.867 0,183C0,175.333 2.398,168.9 7.194,163.7C11.99,158.5 18.184,155.9 25.778,155.9C33.371,155.9 39.499,158.467 44.161,163.6C48.891,168.667 51.255,175.067 51.255,182.8L51.155,186.5ZM25.778,165.6C22.047,165.6 18.95,166.7 16.486,168.9C14.021,171.1 12.489,174.033 11.89,177.7H39.466C38.933,174.033 37.467,171.1 35.069,168.9C32.672,166.7 29.574,165.6 25.778,165.6Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M59.437,193.5V134H71.327V193.7C71.327,196.367 72.792,197.7 75.723,197.7L77.821,197.6V208.9C76.689,209.1 75.49,209.2 74.224,209.2C69.095,209.2 65.332,207.9 62.934,205.3C60.603,202.7 59.437,198.767 59.437,193.5Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M133.193,186.5H93.728C94.194,190.633 95.693,193.933 98.224,196.4C100.755,198.8 104.085,200 108.215,200C110.946,200 113.41,199.333 115.609,198C117.807,196.667 119.372,194.867 120.304,192.6H132.294C130.695,197.867 127.698,202.133 123.302,205.4C118.972,208.6 113.843,210.2 107.915,210.2C100.189,210.2 93.927,207.633 89.132,202.5C84.402,197.367 82.038,190.867 82.038,183C82.038,175.333 84.436,168.9 89.231,163.7C94.027,158.5 100.222,155.9 107.815,155.9C115.409,155.9 121.537,158.467 126.199,163.6C130.928,168.667 133.293,175.067 133.293,182.8L133.193,186.5ZM107.815,165.6C104.085,165.6 100.988,166.7 98.523,168.9C96.059,171.1 94.527,174.033 93.927,177.7H121.503C120.971,174.033 119.505,171.1 117.107,168.9C114.709,166.7 111.612,165.6 107.815,165.6Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M186.835,179.2V209H174.946V177.9C174.946,170.033 171.682,166.1 165.154,166.1C161.624,166.1 158.793,167.233 156.662,169.5C154.597,171.767 153.564,174.867 153.564,178.8V209H141.675V157.1H152.665V164C153.931,161.667 155.862,159.733 158.46,158.2C161.058,156.667 164.288,155.9 168.152,155.9C175.345,155.9 180.541,158.633 183.738,164.1C188.134,158.633 193.996,155.9 201.323,155.9C207.384,155.9 212.047,157.8 215.311,161.6C218.574,165.333 220.206,170.267 220.206,176.4V209H208.317V177.9C208.317,170.033 205.053,166.1 198.525,166.1C194.928,166.1 192.064,167.267 189.933,169.6C187.868,171.867 186.835,175.067 186.835,179.2Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M279.335,186.5H239.87C240.336,190.633 241.835,193.933 244.366,196.4C246.897,198.8 250.227,200 254.357,200C257.088,200 259.552,199.333 261.751,198C263.949,196.667 265.514,194.867 266.447,192.6H278.436C276.837,197.867 273.84,202.133 269.444,205.4C265.114,208.6 259.985,210.2 254.057,210.2C246.331,210.2 240.069,207.633 235.274,202.5C230.544,197.367 228.18,190.867 228.18,183C228.18,175.333 230.578,168.9 235.374,163.7C240.169,158.5 246.364,155.9 253.957,155.9C261.551,155.9 267.679,158.467 272.341,163.6C277.071,168.667 279.435,175.067 279.435,182.8L279.335,186.5ZM253.957,165.6C250.227,165.6 247.13,166.7 244.665,168.9C242.201,171.1 240.669,174.033 240.069,177.7H267.645C267.113,174.033 265.647,171.1 263.249,168.9C260.851,166.7 257.754,165.6 253.957,165.6Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M298.807,157.1V164C300.006,161.733 301.971,159.833 304.702,158.3C307.5,156.7 310.863,155.9 314.793,155.9C320.921,155.9 325.651,157.767 328.981,161.5C332.378,165.233 334.077,170.2 334.077,176.4V209H322.187V177.9C322.187,174.233 321.321,171.367 319.589,169.3C317.924,167.167 315.36,166.1 311.896,166.1C308.099,166.1 305.102,167.233 302.904,169.5C300.772,171.767 299.707,174.9 299.707,178.9V209H287.817V157.1H298.807Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M368.8,198.4V208.7C367.335,209.1 365.27,209.3 362.606,209.3C352.481,209.3 347.419,204.2 347.419,194V166.6H339.526V157.1H347.419V143.6H359.308V157.1H369V166.6H359.308V192.8C359.308,196.867 361.24,198.9 365.103,198.9L368.8,198.4Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M171,6C171,2.686 173.686,0 177,0C199.091,0 217,17.909 217,40C217,43.314 214.314,46 211,46C207.686,46 205,43.314 205,40C205,24.536 192.464,12 177,12C173.686,12 171,9.314 171,6Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M199,94C199,97.314 196.314,100 193,100C170.909,100 153,82.091 153,60C153,56.686 155.686,54 159,54C162.314,54 165,56.686 165,60C165,75.464 177.536,88 193,88C196.314,88 199,90.686 199,94Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M141,64C137.686,64 135,61.314 135,58C135,35.909 152.909,18 175,18C178.314,18 181,20.686 181,24C181,27.314 178.314,30 175,30C159.536,30 147,42.536 147,58C147,61.314 144.314,64 141,64Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M229,36C232.314,36 235,38.686 235,42C235,64.091 217.091,82 195,82C191.686,82 189,79.314 189,76C189,72.686 191.686,70 195,70C210.464,70 223,57.464 223,42C223,38.686 225.686,36 229,36Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

View File

@ -1,22 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="21dp" android:width="24dp"
android:height="22dp" android:height="24dp"
android:viewportWidth="21" android:viewportWidth="24"
android:viewportHeight="22"> android:viewportHeight="24">
<path <path
android:pathData="M9.4969,3.0606L2.8882,3.0606C1.8454,3.0606 1,3.9289 1,5L1,18.5758C1,19.6469 1.8454,20.5152 2.8882,20.5152L16.1056,20.5152C17.1484,20.5152 17.9938,19.6469 17.9938,18.5758L17.9938,11.7879" android:pathData="M4,18.6666L20,18.6666"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="2"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#9E9E9E" android:strokeColor="#000000"
android:fillType="evenOdd"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
<path <path
android:pathData="M16.5776,1.6061C17.3598,0.8027 18.6278,0.8027 19.4099,1.6061C20.1921,2.4094 20.1921,3.7118 19.4099,4.5152L10.441,13.7273L6.6646,14.697L7.6087,10.8182L16.5776,1.6061Z" android:pathData="M6.6667,14L16.0001,4.6666"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="2"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#9E9E9E" android:strokeColor="#000000"
android:fillType="evenOdd"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
</vector> </vector>

View File

@ -6,11 +6,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -7,11 +7,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -6,11 +6,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<!-- No scroll view in the screen, but use the style --> <!-- No scroll view in the screen, but use the style -->
<LinearLayout <LinearLayout

View File

@ -7,11 +7,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -6,11 +6,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -5,11 +5,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -5,11 +5,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -6,11 +6,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints,UnusedAttribute" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -7,11 +7,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -6,11 +6,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -18,28 +18,17 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ImageView
android:id="@+id/loginSplashLogo"
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@drawable/element_logo_green"
android:transitionName="loginLogoTransition"
app:layout_constraintBottom_toTopOf="@+id/logoType"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<ImageView <ImageView
android:id="@+id/logoType" android:id="@+id/logoType"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="44dp" android:layout_height="102dp"
android:layout_marginTop="8dp" android:src="@drawable/element_logotype_combined"
android:src="@drawable/element_logotype"
android:tint="?colorAccent" android:tint="?colorAccent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/loginSplashLogo" /> app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView <TextView
android:id="@+id/loginSplashTitle" android:id="@+id/loginSplashTitle"

View File

@ -6,11 +6,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -6,11 +6,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_background"> android:background="?riotx_background">
<!-- Missing attributes are in the style -->
<ImageView
style="@style/LoginLogo"
tools:ignore="ContentDescription,MissingConstraints" />
<!-- Missing attributes are in the style --> <!-- Missing attributes are in the style -->
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
style="@style/LoginFormScrollView" style="@style/LoginFormScrollView"

View File

@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="1dp"
android:background="?riotx_background" android:background="?riotx_background"
android:orientation="vertical"> android:orientation="vertical">

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@id/loginLogo"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="32dp"
android:importantForAccessibility="no"
android:src="@drawable/element_logo_green" />

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?riotx_background"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:minHeight="64dp"
android:paddingLeft="@dimen/layout_horizontal_margin"
android:paddingTop="8dp"
android:paddingRight="@dimen/layout_horizontal_margin"
android:paddingBottom="8dp">
<ImageView
android:id="@+id/matrixItemAvatar"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_centerVertical="true"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<ImageView
android:id="@+id/matrixItemAvatarDecoration"
android:layout_width="20dp"
android:layout_height="20dp"
app:layout_constraintCircle="@+id/matrixItemAvatar"
app:layout_constraintCircleAngle="135"
app:layout_constraintCircleRadius="16dp"
tools:ignore="MissingConstraints"
tools:src="@drawable/ic_shield_trusted" />
<TextView
android:id="@+id/matrixItemTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:drawablePadding="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?riotx_text_primary"
android:textSize="16sp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@+id/matrixItemSubtitle"
app:layout_constraintEnd_toStartOf="@+id/matrixItemProgress"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/matrixItemAvatar"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginStart="0dp"
tools:text="@sample/matrix.json/data/displayName" />
<TextView
android:id="@+id/matrixItemSubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:drawablePadding="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?riotx_text_secondary"
android:textSize="12sp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/matrixItemProgress"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/matrixItemAvatar"
app:layout_constraintTop_toBottomOf="@id/matrixItemTitle"
app:layout_goneMarginStart="0dp"
tools:text="@sample/matrix.json/data/mxid" />
<ProgressBar
android:id="@+id/matrixItemProgress"
style="?android:attr/progressBarStyle"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="8dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/matrixItemEditable"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<ImageView
android:id="@+id/matrixItemEditable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_right"
android:tint="?riotx_text_secondary"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,19 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<!-- We will improve this later
<style name="LoginLogo" parent="LoginLogoBase">
<item name="layout_constraintEnd_toStartOf">@id/loginFormContainer</item>
<item name="layout_constraintBottom_toBottomOf">parent</item>
<item name="android:layout_height">0dp</item>
<item name="layout_constraintHorizontal_chainStyle">packed</item>
</style>
<style name="LoginFormContainer" parent="LoginFormContainerBase">
<item name="layout_constraintWidth_percent">0.6</item>
<item name="layout_constraintStart_toEndOf">@id/loginLogo</item>
<item name="layout_constraintTop_toTopOf">parent</item>
</style>
-->
</resources> </resources>

View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="LoginLogo.v21" parent="LoginLogoBase">
<item name="android:transitionName">loginLogoTransition</item>
</style>
</resources> </resources>

View File

@ -992,6 +992,10 @@
<!-- Room settings: banned users --> <!-- Room settings: banned users -->
<string name="room_settings_banned_users_title">Banned users</string> <string name="room_settings_banned_users_title">Banned users</string>
<plurals name="room_settings_banned_users_count">
<item quantity="one">1 banned user</item>
<item quantity="other">%d banned users</item>
</plurals>
<!-- advanced --> <!-- advanced -->
<string name="room_settings_category_advanced_title">Advanced</string> <string name="room_settings_category_advanced_title">Advanced</string>
@ -2499,6 +2503,7 @@ Not all features in Riot are implemented in Element yet. Main missing (and comin
<string name="identity_server_set_alternative_notice_no_default">Enter the URL of an identity server</string> <string name="identity_server_set_alternative_notice_no_default">Enter the URL of an identity server</string>
<string name="identity_server_set_alternative_submit">Submit</string> <string name="identity_server_set_alternative_submit">Submit</string>
<string name="power_level_edit_title">Set role</string> <string name="power_level_edit_title">Set role</string>
<string name="power_level_title">Role</string>
<string name="a11y_open_chat">Open chat</string> <string name="a11y_open_chat">Open chat</string>
<string name="a11y_mute_microphone">Mute the microphone</string> <string name="a11y_mute_microphone">Mute the microphone</string>
<string name="a11y_unmute_microphone">Unmute the microphone</string> <string name="a11y_unmute_microphone">Unmute the microphone</string>
@ -2560,4 +2565,7 @@ Not all features in Riot are implemented in Element yet. Main missing (and comin
<string name="three_pid_revoke_invite_dialog_title">Revoke invite</string> <string name="three_pid_revoke_invite_dialog_title">Revoke invite</string>
<string name="three_pid_revoke_invite_dialog_content">Revoke invite to %1$s?</string> <string name="three_pid_revoke_invite_dialog_content">Revoke invite to %1$s?</string>
<string name="member_banned_by">Banned by %1$s</string>
<string name="failed_to_unban">Failed to UnBan user</string>
</resources> </resources>

View File

@ -8,27 +8,9 @@
<item name="android:paddingEnd">36dp</item> <item name="android:paddingEnd">36dp</item>
</style> </style>
<item name="loginLogo" type="id" />
<item name="loginFormScrollView" type="id" /> <item name="loginFormScrollView" type="id" />
<item name="loginFormContainer" type="id" /> <item name="loginFormContainer" type="id" />
<style name="LoginLogoBase">
<item name="android:id">@id/loginLogo</item>
<item name="android:layout_width">60dp</item>
<item name="android:layout_height">60dp</item>
<item name="android:src">@drawable/element_logo_green</item>
<item name="android:importantForAccessibility">no</item>
<item name="layout_constraintTop_toTopOf">parent</item>
<item name="layout_constraintStart_toStartOf">parent</item>
</style>
<style name="LoginLogo.v21" parent="LoginLogoBase" />
<style name="LoginLogo" parent="LoginLogo.v21">
<item name="layout_constraintEnd_toEndOf">parent</item>
<item name="android:layout_marginTop">48dp</item>
</style>
<style name="LoginFormContainer"> <style name="LoginFormContainer">
<item name="android:id">@id/loginFormContainer</item> <item name="android:id">@id/loginFormContainer</item>
<item name="android:paddingStart">36dp</item> <item name="android:paddingStart">36dp</item>
@ -49,10 +31,10 @@
</style> </style>
<style name="LoginFormScrollView" parent="LoginFormScrollViewBase"> <style name="LoginFormScrollView" parent="LoginFormScrollViewBase">
<item name="layout_constraintTop_toBottomOf">@id/loginLogo</item> <item name="layout_constraintTop_toTopOf">parent</item>
<item name="layout_constraintStart_toStartOf">parent</item> <item name="layout_constraintStart_toStartOf">parent</item>
<item name="android:layout_height">0dp</item> <item name="android:layout_height">0dp</item>
<item name="android:layout_marginTop">24dp</item> <item name="android:layout_marginTop">72dp</item>
</style> </style>
<style name="Style.Vector.Login.Button" parent="VectorButtonStyle"> <style name="Style.Vector.Login.Button" parent="VectorButtonStyle">

View File

@ -24,6 +24,7 @@
app:fragment="im.vector.riotx.features.settings.VectorSettingsPreferencesFragment" /> app:fragment="im.vector.riotx.features.settings.VectorSettingsPreferencesFragment" />
<im.vector.riotx.core.preference.VectorPreference <im.vector.riotx.core.preference.VectorPreference
app:isPreferenceVisible="@bool/false_not_implemented"
android:enabled="@bool/false_not_implemented" android:enabled="@bool/false_not_implemented"
android:icon="@drawable/ic_settings_root_call" android:icon="@drawable/ic_settings_root_call"
android:title="@string/preference_voice_and_video" android:title="@string/preference_voice_and_video"