Profile: handle ignore/unignore action + adjust UI
This commit is contained in:
parent
162f0949fa
commit
df4df81ef3
|
@ -20,16 +20,18 @@ package im.vector.riotx.core.animations
|
|||
import android.view.View
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
|
||||
class MatrixItemAppBarStateChangeListener(private val animationDuration: Long, private val views: List<View>) : AppBarStateChangeListener() {
|
||||
class MatrixItemAppBarStateChangeListener(private val headerView: View, private val toolbarViews: List<View>) : AppBarStateChangeListener() {
|
||||
|
||||
override fun onStateChanged(appBarLayout: AppBarLayout, state: State) {
|
||||
if (state == State.COLLAPSED) {
|
||||
views.forEach {
|
||||
it.animate().alpha(1f).duration = animationDuration + 100
|
||||
headerView.visibility = View.INVISIBLE
|
||||
toolbarViews.forEach {
|
||||
it.animate().alpha(1f).duration = 150
|
||||
}
|
||||
} else {
|
||||
views.forEach {
|
||||
it.animate().alpha(0f).duration = animationDuration - 100
|
||||
headerView.visibility = View.VISIBLE
|
||||
toolbarViews.forEach {
|
||||
it.animate().alpha(0f).duration = 150
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
|
|||
data class Error(val message: CharSequence? = null) : State()
|
||||
}
|
||||
|
||||
private var eventCallback: EventCallback? = null
|
||||
var eventCallback: EventCallback? = null
|
||||
|
||||
var contentView: View? = null
|
||||
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package im.vector.riotx.core.platform
|
||||
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
|
@ -59,6 +62,9 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
protected lateinit var navigator: Navigator
|
||||
protected lateinit var errorFormatter: ErrorFormatter
|
||||
|
||||
private var progress: ProgressDialog? = null
|
||||
|
||||
|
||||
/* ==========================================================================================
|
||||
* View model
|
||||
* ========================================================================================== */
|
||||
|
@ -177,6 +183,19 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
}
|
||||
}
|
||||
|
||||
protected fun showLoadingDialog(message: CharSequence, cancelable: Boolean = false) {
|
||||
progress = ProgressDialog(requireContext()).apply {
|
||||
setCancelable(cancelable)
|
||||
setMessage(message)
|
||||
setProgressStyle(ProgressDialog.STYLE_SPINNER)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun dismissLoadingDialog(){
|
||||
progress?.dismiss()
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
* Toolbar
|
||||
* ========================================================================================== */
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.riotx.core.utils
|
|||
import com.jakewharton.rxrelay2.BehaviorRelay
|
||||
import com.jakewharton.rxrelay2.PublishRelay
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
interface DataSource<T> {
|
||||
|
@ -37,7 +38,7 @@ open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableD
|
|||
private val behaviorRelay = createRelay()
|
||||
|
||||
override fun observe(): Observable<T> {
|
||||
return behaviorRelay.hide().observeOn(Schedulers.computation())
|
||||
return behaviorRelay.hide().observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
override fun post(value: T) {
|
||||
|
@ -61,7 +62,7 @@ open class PublishDataSource<T> : MutableDataSource<T> {
|
|||
private val publishRelay = PublishRelay.create<T>()
|
||||
|
||||
override fun observe(): Observable<T> {
|
||||
return publishRelay.hide()
|
||||
return publishRelay.hide().observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
override fun post(value: T) {
|
||||
|
|
|
@ -21,11 +21,7 @@ import im.vector.riotx.core.platform.VectorViewModelAction
|
|||
|
||||
sealed class RoomMemberProfileAction : VectorViewModelAction {
|
||||
|
||||
sealed class Displayable : RoomMemberProfileAction() {
|
||||
object JumpToReadReceipt : Displayable()
|
||||
object Ignore : Displayable()
|
||||
object Mention : Displayable()
|
||||
}
|
||||
|
||||
object RetryFetchingInfo: RoomMemberProfileAction()
|
||||
object IgnoreUser: RoomMemberProfileAction()
|
||||
|
||||
}
|
||||
|
|
|
@ -37,36 +37,33 @@ class RoomMemberProfileController @Inject constructor(private val stringProvider
|
|||
}
|
||||
|
||||
override fun buildModels(data: RoomMemberProfileViewState?) {
|
||||
if (data == null) {
|
||||
if (data?.userMatrixItem?.invoke() == null) {
|
||||
return
|
||||
}
|
||||
val roomMemberSummary = data.roomMemberSummary()
|
||||
val profileInfo = data.profileInfo()
|
||||
if (roomMemberSummary == null && profileInfo != null) {
|
||||
buildUserActions()
|
||||
} else if (roomMemberSummary != null) {
|
||||
if (data.showAsMember) {
|
||||
buildRoomMemberActions(data)
|
||||
} else {
|
||||
buildUserActions(data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildUserActions() {
|
||||
private fun buildUserActions(state: RoomMemberProfileViewState) {
|
||||
val ignoreActionTitle = state.buildIgnoreActionTitle() ?: return
|
||||
// More
|
||||
buildProfileSection(stringProvider.getString(R.string.room_profile_section_more))
|
||||
buildProfileAction(
|
||||
id = "ignore",
|
||||
title = stringProvider.getString(R.string.ignore),
|
||||
title = ignoreActionTitle,
|
||||
destructive = true,
|
||||
editable = false,
|
||||
action = { callback?.onIgnoreClicked() }
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildRoomMemberActions(data: RoomMemberProfileViewState) {
|
||||
val roomSummaryEntity = data.roomSummary() ?: return
|
||||
|
||||
private fun buildRoomMemberActions(state: RoomMemberProfileViewState) {
|
||||
// Security
|
||||
buildProfileSection(stringProvider.getString(R.string.room_profile_section_security))
|
||||
val learnMoreSubtitle = if (roomSummaryEntity.isEncrypted) {
|
||||
val learnMoreSubtitle = if (state.isRoomEncrypted) {
|
||||
R.string.room_profile_encrypted_subtitle
|
||||
} else {
|
||||
R.string.room_profile_not_encrypted_subtitle
|
||||
|
@ -80,7 +77,7 @@ class RoomMemberProfileController @Inject constructor(private val stringProvider
|
|||
)
|
||||
|
||||
// More
|
||||
if (!data.isMine) {
|
||||
if (!state.isMine) {
|
||||
buildProfileSection(stringProvider.getString(R.string.room_profile_section_more))
|
||||
buildProfileAction(
|
||||
id = "read_receipt",
|
||||
|
@ -94,15 +91,26 @@ class RoomMemberProfileController @Inject constructor(private val stringProvider
|
|||
editable = false,
|
||||
action = { callback?.onMentionClicked() }
|
||||
)
|
||||
buildProfileAction(
|
||||
id = "ignore",
|
||||
title = stringProvider.getString(R.string.ignore),
|
||||
destructive = true,
|
||||
editable = false,
|
||||
action = { callback?.onIgnoreClicked() }
|
||||
)
|
||||
val ignoreActionTitle = state.buildIgnoreActionTitle()
|
||||
if (ignoreActionTitle != null) {
|
||||
buildProfileAction(
|
||||
id = "ignore",
|
||||
title = ignoreActionTitle,
|
||||
destructive = true,
|
||||
editable = false,
|
||||
action = { callback?.onIgnoreClicked() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun RoomMemberProfileViewState.buildIgnoreActionTitle(): String? {
|
||||
val isIgnored = isIgnored() ?: return null
|
||||
return if (isIgnored) {
|
||||
stringProvider.getString(R.string.unignore)
|
||||
} else {
|
||||
stringProvider.getString(R.string.ignore)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,28 +15,26 @@
|
|||
*
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package im.vector.riotx.features.roommemberprofile
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.matrix.android.api.session.room.powerlevers.PowerLevelsConstants
|
||||
import im.vector.matrix.android.api.session.room.powerlevers.PowerLevelsHelper
|
||||
import im.vector.matrix.android.api.util.toMatrixItem
|
||||
import com.airbnb.mvrx.*
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.animations.AppBarStateChangeListener
|
||||
import im.vector.riotx.core.animations.MatrixItemAppBarStateChangeListener
|
||||
import im.vector.riotx.core.extensions.cleanup
|
||||
import im.vector.riotx.core.extensions.configureWith
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
import im.vector.riotx.core.platform.StateView
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
||||
import kotlinx.android.synthetic.main.fragment_matrix_profile.matrixProfileHeaderView
|
||||
import kotlinx.android.synthetic.main.view_stub_room_member_profile_header.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -62,14 +60,32 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupToolbar(matrixProfileToolbar)
|
||||
matrixProfileHeaderView.apply {
|
||||
layoutResource = R.layout.view_stub_room_member_profile_header
|
||||
inflate()
|
||||
val headerView = matrixProfileHeaderView.let {
|
||||
it.layoutResource = R.layout.view_stub_room_member_profile_header
|
||||
it.inflate()
|
||||
}
|
||||
memberProfileStateView.eventCallback = object : StateView.EventCallback {
|
||||
override fun onRetryClicked() {
|
||||
viewModel.handle(RoomMemberProfileAction.RetryFetchingInfo)
|
||||
}
|
||||
}
|
||||
memberProfileStateView.contentView = memberProfileInfoContainer
|
||||
matrixProfileRecyclerView.configureWith(roomMemberProfileController, hasFixedSize = true)
|
||||
roomMemberProfileController.callback = this
|
||||
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(matrixProfileCollapsingToolbarLayout.scrimAnimationDuration, listOf(matrixProfileToolbarAvatarImageView, matrixProfileToolbarTitleView))
|
||||
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(headerView, listOf(matrixProfileToolbarAvatarImageView,
|
||||
matrixProfileToolbarTitleView))
|
||||
matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
|
||||
viewModel.viewEvents
|
||||
.observe()
|
||||
.subscribe {
|
||||
dismissLoadingDialog()
|
||||
when (it) {
|
||||
is RoomMemberProfileViewEvents.Loading -> showLoadingDialog(it.message)
|
||||
is RoomMemberProfileViewEvents.Failure -> showErrorInSnackbar(it.throwable)
|
||||
}
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -81,42 +97,37 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
val memberMatrixItem = state.memberAsMatrixItem()
|
||||
if (memberMatrixItem != null) {
|
||||
memberProfileIdView.text = memberMatrixItem.id
|
||||
val bestName = memberMatrixItem.getBestName()
|
||||
memberProfileNameView.text = bestName
|
||||
matrixProfileToolbarTitleView.text = bestName
|
||||
avatarRenderer.render(memberMatrixItem, memberProfileAvatarView)
|
||||
avatarRenderer.render(memberMatrixItem, matrixProfileToolbarAvatarImageView)
|
||||
}
|
||||
|
||||
val roomSummary = state.roomSummary()
|
||||
val powerLevelsContent = state.powerLevelsContent()
|
||||
if (powerLevelsContent == null || roomSummary == null) {
|
||||
memberProfilePowerLevelView.visibility = View.GONE
|
||||
} else {
|
||||
val roomName = roomSummary.toMatrixItem().getBestName()
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
|
||||
val userPowerLevel = powerLevelsHelper.getUserPowerLevel(state.userId)
|
||||
val powerLevelText = if (userPowerLevel == PowerLevelsConstants.DEFAULT_ROOM_ADMIN_LEVEL) {
|
||||
getString(R.string.room_member_power_level_admin_in, roomName)
|
||||
} else if (userPowerLevel == PowerLevelsConstants.DEFAULT_ROOM_MODERATOR_LEVEL) {
|
||||
getString(R.string.room_member_power_level_moderator_in, roomName)
|
||||
} else if (userPowerLevel == PowerLevelsConstants.DEFAULT_ROOM_USER_LEVEL) {
|
||||
null
|
||||
} else {
|
||||
getString(R.string.room_member_power_level_custom_in, userPowerLevel, roomName)
|
||||
when (val asyncUserMatrixItem = state.userMatrixItem) {
|
||||
is Incomplete -> {
|
||||
matrixProfileToolbarTitleView.text = state.userId
|
||||
avatarRenderer.render(MatrixItem.UserItem(state.userId, null, null), matrixProfileToolbarAvatarImageView)
|
||||
memberProfileStateView.state = StateView.State.Loading
|
||||
}
|
||||
is Fail -> {
|
||||
avatarRenderer.render(MatrixItem.UserItem(state.userId, null, null), matrixProfileToolbarAvatarImageView)
|
||||
matrixProfileToolbarTitleView.text = state.userId
|
||||
val failureMessage = errorFormatter.toHumanReadable(asyncUserMatrixItem.error)
|
||||
memberProfileStateView.state = StateView.State.Error(failureMessage)
|
||||
}
|
||||
is Success -> {
|
||||
val userMatrixItem = asyncUserMatrixItem()
|
||||
memberProfileStateView.state = StateView.State.Content
|
||||
memberProfileIdView.text = userMatrixItem.id
|
||||
val bestName = userMatrixItem.getBestName()
|
||||
memberProfileNameView.text = bestName
|
||||
matrixProfileToolbarTitleView.text = bestName
|
||||
avatarRenderer.render(userMatrixItem, memberProfileAvatarView)
|
||||
avatarRenderer.render(userMatrixItem, matrixProfileToolbarAvatarImageView)
|
||||
}
|
||||
memberProfilePowerLevelView.setTextOrHide(powerLevelText)
|
||||
}
|
||||
memberProfilePowerLevelView.setTextOrHide(state.userPowerLevelString())
|
||||
roomMemberProfileController.setData(state)
|
||||
}
|
||||
|
||||
// RoomMemberProfileController.Callback
|
||||
|
||||
override fun onIgnoreClicked() {
|
||||
vectorBaseActivity.notImplemented("Ignore")
|
||||
viewModel.handle(RoomMemberProfileAction.IgnoreUser)
|
||||
}
|
||||
|
||||
override fun onLearnMoreClicked() {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.features.roommemberprofile
|
||||
|
||||
/**
|
||||
* Transient events for RoomProfile
|
||||
*/
|
||||
sealed class RoomMemberProfileViewEvents {
|
||||
data class Loading(val message: CharSequence) : RoomMemberProfileViewEvents()
|
||||
object OnIgnoreActionSuccess : RoomMemberProfileViewEvents()
|
||||
data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents()
|
||||
|
||||
}
|
|
@ -17,25 +17,43 @@
|
|||
|
||||
package im.vector.riotx.features.roommemberprofile
|
||||
|
||||
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.MatrixCallback
|
||||
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.profile.ProfileService
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.members.roomMemberQueryParams
|
||||
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.powerlevers.PowerLevelsConstants
|
||||
import im.vector.matrix.android.api.session.room.powerlevers.PowerLevelsHelper
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.matrix.android.api.util.toMatrixItem
|
||||
import im.vector.matrix.android.api.util.toOptional
|
||||
import im.vector.matrix.rx.mapOptional
|
||||
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 timber.log.Timber
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.core.utils.DataSource
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private val initialState: RoomMemberProfileViewState,
|
||||
private val stringProvider: StringProvider,
|
||||
private val session: Session)
|
||||
: VectorViewModel<RoomMemberProfileViewState, RoomMemberProfileAction>(initialState) {
|
||||
|
||||
|
@ -53,6 +71,9 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
|||
}
|
||||
}
|
||||
|
||||
private val _viewEvents = PublishDataSource<RoomMemberProfileViewEvents>()
|
||||
val viewEvents: DataSource<RoomMemberProfileViewEvents> = _viewEvents
|
||||
|
||||
private val room = if (initialState.roomId != null) {
|
||||
session.getRoom(initialState.roomId)
|
||||
} else {
|
||||
|
@ -61,65 +82,118 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
|||
|
||||
init {
|
||||
setState { copy(isMine = session.myUserId == this.userId) }
|
||||
observeRoomSummary()
|
||||
observeRoomMemberSummary()
|
||||
observePowerLevel()
|
||||
fetchProfileInfoIfRequired()
|
||||
observeIgnoredState()
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
// Do we have a room member for this id.
|
||||
val roomMember = withContext(Dispatchers.Default) {
|
||||
room?.getRoomMember(initialState.userId)
|
||||
}
|
||||
// If not, we look for profile info on the server
|
||||
if (room == null || roomMember == null) {
|
||||
fetchProfileInfo()
|
||||
} else {
|
||||
// otherwise we just start listening to db
|
||||
setState { copy(showAsMember = true) }
|
||||
observeRoomMemberSummary(room)
|
||||
observeRoomSummaryAndPowerLevels(room)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchProfileInfoIfRequired() {
|
||||
val roomMember = room?.getRoomMember(initialState.userId)
|
||||
if (roomMember != null) {
|
||||
return
|
||||
}
|
||||
session.rx().getProfileInfo(initialState.userId)
|
||||
private fun observeIgnoredState() {
|
||||
session.rx().liveIgnoredUsers()
|
||||
.map { ignored ->
|
||||
ignored.find {
|
||||
it.userId == initialState.userId
|
||||
} != null
|
||||
}
|
||||
.execute {
|
||||
copy(profileInfo = it)
|
||||
copy(isIgnored = it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(action: RoomMemberProfileAction) {
|
||||
Timber.v("Handle $action")
|
||||
when (action) {
|
||||
RoomMemberProfileAction.RetryFetchingInfo -> fetchProfileInfo()
|
||||
is RoomMemberProfileAction.IgnoreUser -> handleIgnoreAction()
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomSummary() {
|
||||
if (room == null) {
|
||||
return
|
||||
}
|
||||
room.rx().liveRoomSummary()
|
||||
.unwrap()
|
||||
.execute {
|
||||
copy(roomSummary = it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomMemberSummary() {
|
||||
if (room == null) {
|
||||
return
|
||||
}
|
||||
private fun observeRoomMemberSummary(room: Room) {
|
||||
val queryParams = roomMemberQueryParams {
|
||||
this.userId = QueryStringValue.Equals(initialState.userId, QueryStringValue.Case.SENSITIVE)
|
||||
}
|
||||
room.rx().liveRoomMembers(queryParams)
|
||||
.map { it.firstOrNull().toOptional() }
|
||||
.map { it.firstOrNull()?.toMatrixItem().toOptional() }
|
||||
.unwrap()
|
||||
.execute {
|
||||
copy(roomMemberSummary = it)
|
||||
copy(userMatrixItem = it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observePowerLevel() {
|
||||
if (room == null) {
|
||||
return
|
||||
}
|
||||
room.rx()
|
||||
.liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||
private fun fetchProfileInfo() {
|
||||
session.rx().getProfileInfo(initialState.userId)
|
||||
.map {
|
||||
MatrixItem.UserItem(
|
||||
id = initialState.userId,
|
||||
displayName = it[ProfileService.DISPLAY_NAME_KEY] as? String,
|
||||
avatarUrl = it[ProfileService.AVATAR_URL_KEY] as? String
|
||||
)
|
||||
}
|
||||
.execute {
|
||||
copy(userMatrixItem = it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomSummaryAndPowerLevels(room: Room) {
|
||||
val roomSummaryLive = room.rx().liveRoomSummary().unwrap()
|
||||
val powerLevelsContentLive = room.rx().liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||
.unwrap()
|
||||
.execute {
|
||||
copy(powerLevelsContent = it)
|
||||
|
||||
roomSummaryLive.execute {
|
||||
copy(isRoomEncrypted = it.invoke()?.isEncrypted == true)
|
||||
}
|
||||
Observable
|
||||
.combineLatest(
|
||||
roomSummaryLive,
|
||||
powerLevelsContentLive,
|
||||
BiFunction<RoomSummary, PowerLevelsContent, String> { roomSummary, powerLevelsContent ->
|
||||
val roomName = roomSummary.toMatrixItem().getBestName()
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
|
||||
val userPowerLevel = powerLevelsHelper.getUserPowerLevel(initialState.userId)
|
||||
if (userPowerLevel == PowerLevelsConstants.DEFAULT_ROOM_ADMIN_LEVEL) {
|
||||
stringProvider.getString(R.string.room_member_power_level_admin_in, roomName)
|
||||
} else if (userPowerLevel == PowerLevelsConstants.DEFAULT_ROOM_MODERATOR_LEVEL) {
|
||||
stringProvider.getString(R.string.room_member_power_level_moderator_in, roomName)
|
||||
} else if (userPowerLevel == PowerLevelsConstants.DEFAULT_ROOM_USER_LEVEL) {
|
||||
""
|
||||
} else {
|
||||
stringProvider.getString(R.string.room_member_power_level_custom_in, userPowerLevel, roomName)
|
||||
}
|
||||
}
|
||||
).execute {
|
||||
copy(userPowerLevelString = it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleIgnoreAction() = withState { state ->
|
||||
val isIgnored = state.isIgnored() ?: return@withState
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Loading(stringProvider.getString(R.string.please_wait)))
|
||||
val ignoreActionCallback = object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.OnIgnoreActionSuccess)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
|
||||
}
|
||||
}
|
||||
if (isIgnored) {
|
||||
session.unIgnoreUserIds(listOf(state.userId), ignoreActionCallback)
|
||||
} else {
|
||||
session.ignoreUserIds(listOf(initialState.userId), ignoreActionCallback)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,33 +20,23 @@ package im.vector.riotx.features.roommemberprofile
|
|||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.profile.ProfileService
|
||||
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
|
||||
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.util.JsonDict
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.matrix.android.api.util.toMatrixItem
|
||||
|
||||
typealias ProfileInfo = JsonDict
|
||||
|
||||
data class RoomMemberProfileViewState(
|
||||
val userId: String,
|
||||
val roomId: String?,
|
||||
val showAsMember: Boolean = false,
|
||||
val isMine: Boolean = false,
|
||||
val roomSummary: Async<RoomSummary> = Uninitialized,
|
||||
val roomMemberSummary: Async<RoomMemberSummary> = Uninitialized,
|
||||
val profileInfo: Async<ProfileInfo> = Uninitialized,
|
||||
val powerLevelsContent: Async<PowerLevelsContent> = Uninitialized
|
||||
val isIgnored: Async<Boolean> = Uninitialized,
|
||||
val isRoomEncrypted: Boolean = false,
|
||||
val userPowerLevelString: Async<String> = Uninitialized,
|
||||
val userMatrixItem: Async<MatrixItem> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: RoomMemberProfileArgs) : this(roomId = args.roomId, userId = args.userId)
|
||||
|
||||
fun memberAsMatrixItem(): MatrixItem? {
|
||||
return roomMemberSummary()?.toMatrixItem() ?: profileInfo()?.let {
|
||||
MatrixItem.UserItem(userId, it[ProfileService.DISPLAY_NAME_KEY] as? String, it[ProfileService.AVATAR_URL_KEY] as? String)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.commitTransaction
|
||||
import im.vector.riotx.core.extensions.commitTransactionNow
|
||||
import im.vector.riotx.core.extensions.addFragment
|
||||
import im.vector.riotx.core.extensions.addFragmentToBackstack
|
||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
import im.vector.riotx.features.roomprofile.members.RoomMemberListFragment
|
||||
|
@ -32,9 +32,6 @@ class RoomProfileActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
companion object {
|
||||
|
||||
private const val EXTRA_ROOM_PROFILE_ARGS = "EXTRA_ROOM_PROFILE_ARGS"
|
||||
private const val TAG_ROOM_PROFILE_FRAGMENT = "TAG_ROOM_PROFILE_FRAGMENT"
|
||||
private const val TAG_ROOM_MEMBER_LIST_FRAGMENT = "TAG_ROOM_MEMBER_LIST_FRAGMENT"
|
||||
|
||||
|
||||
fun newIntent(context: Context, roomId: String): Intent {
|
||||
val roomProfileArgs = RoomProfileArgs(roomId)
|
||||
|
@ -53,14 +50,7 @@ class RoomProfileActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
sharedActionViewModel = viewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
||||
roomProfileArgs = intent?.extras?.getParcelable(EXTRA_ROOM_PROFILE_ARGS) ?: return
|
||||
if (isFirstCreation()) {
|
||||
val argsBundle = roomProfileArgs.toMvRxBundle()
|
||||
val roomProfileFragment = createFragment(RoomProfileFragment::class.java, argsBundle)
|
||||
val roomMemberListFragment = createFragment(RoomMemberListFragment::class.java, argsBundle)
|
||||
supportFragmentManager.commitTransactionNow {
|
||||
add(R.id.simpleFragmentContainer, roomProfileFragment, TAG_ROOM_PROFILE_FRAGMENT)
|
||||
add(R.id.simpleFragmentContainer, roomMemberListFragment, TAG_ROOM_MEMBER_LIST_FRAGMENT)
|
||||
detach(roomMemberListFragment)
|
||||
}
|
||||
addFragment(R.id.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs)
|
||||
}
|
||||
sharedActionViewModel
|
||||
.observe()
|
||||
|
@ -83,15 +73,7 @@ class RoomProfileActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
}
|
||||
|
||||
private fun openRoomMembers() {
|
||||
val roomProfileFragment = supportFragmentManager.findFragmentByTag(TAG_ROOM_PROFILE_FRAGMENT)
|
||||
?: throw IllegalStateException("You should have a RoomProfileFragment")
|
||||
val roomMemberListFragment = supportFragmentManager.findFragmentByTag(TAG_ROOM_MEMBER_LIST_FRAGMENT)
|
||||
?: throw IllegalStateException("You should have a RoomMemberListFragment")
|
||||
supportFragmentManager.commitTransaction {
|
||||
hide(roomProfileFragment)
|
||||
attach(roomMemberListFragment)
|
||||
addToBackStack(null)
|
||||
}
|
||||
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs)
|
||||
}
|
||||
|
||||
override fun configure(toolbar: Toolbar) {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package im.vector.riotx.features.roomprofile
|
||||
|
||||
import android.app.ProgressDialog
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
|
@ -58,7 +57,6 @@ class RoomProfileFragment @Inject constructor(
|
|||
val roomProfileViewModelFactory: RoomProfileViewModel.Factory
|
||||
) : VectorBaseFragment(), RoomProfileController.Callback {
|
||||
|
||||
private var progress: ProgressDialog? = null
|
||||
private val roomProfileArgs: RoomProfileArgs by args()
|
||||
private lateinit var roomListQuickActionsSharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
||||
private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
|
||||
|
@ -73,36 +71,32 @@ class RoomProfileFragment @Inject constructor(
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
roomListQuickActionsSharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
||||
roomProfileSharedActionViewModel = activityViewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
||||
matrixProfileHeaderView.apply {
|
||||
layoutResource = R.layout.view_stub_room_profile_header
|
||||
inflate()
|
||||
val headerView = matrixProfileHeaderView.let {
|
||||
it.layoutResource = R.layout.view_stub_room_profile_header
|
||||
it.inflate()
|
||||
}
|
||||
setupToolbar(matrixProfileToolbar)
|
||||
setupRecyclerView()
|
||||
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(matrixProfileCollapsingToolbarLayout.scrimAnimationDuration, listOf(matrixProfileToolbarAvatarImageView, matrixProfileToolbarTitleView))
|
||||
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(headerView, listOf(matrixProfileToolbarAvatarImageView,
|
||||
matrixProfileToolbarTitleView))
|
||||
matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
|
||||
roomProfileViewModel.viewEvents
|
||||
.observe()
|
||||
.subscribe {
|
||||
progress?.dismiss()
|
||||
dismissLoadingDialog()
|
||||
when (it) {
|
||||
RoomProfileViewEvents.Loading -> showLoading()
|
||||
is RoomProfileViewEvents.Loading -> showLoadingDialog(it.message)
|
||||
RoomProfileViewEvents.OnLeaveRoomSuccess -> onLeaveRoom()
|
||||
is RoomProfileViewEvents.Failure -> showError(it.throwable)
|
||||
}
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
roomListQuickActionsSharedActionViewModel
|
||||
.observe()
|
||||
.subscribe { handleQuickActions(it) }
|
||||
.disposeOnDestroyView()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setupToolbar(matrixProfileToolbar)
|
||||
}
|
||||
|
||||
private fun handleQuickActions(action: RoomListQuickActionsSharedAction) = when (action) {
|
||||
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
||||
roomProfileViewModel.handle(RoomProfileAction.ChangeRoomNotificationState(RoomNotificationState.ALL_MESSAGES_NOISY))
|
||||
|
@ -124,15 +118,7 @@ class RoomProfileFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun showError(throwable: Throwable) {
|
||||
vectorBaseActivity.showSnackbar(errorFormatter.toHumanReadable(throwable))
|
||||
}
|
||||
|
||||
private fun showLoading() {
|
||||
progress = ProgressDialog(requireContext()).apply {
|
||||
setMessage(getString(R.string.room_profile_leaving_room))
|
||||
setProgressStyle(ProgressDialog.STYLE_SPINNER)
|
||||
show()
|
||||
}
|
||||
showErrorInSnackbar(throwable)
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
|
|
|
@ -19,7 +19,7 @@ package im.vector.riotx.features.roomprofile
|
|||
* Transient events for RoomProfile
|
||||
*/
|
||||
sealed class RoomProfileViewEvents {
|
||||
object Loading: RoomProfileViewEvents()
|
||||
data class Loading(val message: CharSequence): RoomProfileViewEvents()
|
||||
object OnLeaveRoomSuccess: RoomProfileViewEvents()
|
||||
data class Failure(val throwable: Throwable) : RoomProfileViewEvents()
|
||||
|
||||
|
|
|
@ -26,13 +26,16 @@ import im.vector.matrix.android.api.MatrixCallback
|
|||
import im.vector.matrix.android.api.session.Session
|
||||
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.core.utils.DataSource
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import im.vector.riotx.features.home.room.list.RoomListAction
|
||||
import im.vector.riotx.features.home.room.list.RoomListViewEvents
|
||||
|
||||
class RoomProfileViewModel @AssistedInject constructor(@Assisted initialState: RoomProfileViewState,
|
||||
private val stringProvider: StringProvider,
|
||||
private val session: Session)
|
||||
: VectorViewModel<RoomProfileViewState, RoomProfileAction>(initialState) {
|
||||
|
||||
|
@ -84,7 +87,7 @@ class RoomProfileViewModel @AssistedInject constructor(@Assisted initialState: R
|
|||
}
|
||||
|
||||
private fun handleLeaveRoom() {
|
||||
_viewEvents.post(RoomProfileViewEvents.Loading)
|
||||
_viewEvents.post(RoomProfileViewEvents.Loading(stringProvider.getString(R.string.room_profile_leaving_room)))
|
||||
room.leave(null, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
_viewEvents.post(RoomProfileViewEvents.OnLeaveRoomSuccess)
|
||||
|
|
|
@ -48,12 +48,8 @@ class RoomMemberListFragment @Inject constructor(
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
roomMemberListController.callback = this
|
||||
recyclerView.configureWith(roomMemberListController, hasFixedSize = true)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setupToolbar(roomMemberListToolbar)
|
||||
recyclerView.configureWith(roomMemberListController, hasFixedSize = true)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:id="@+id/vector_coordinator_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?riotx_header_panel_background">
|
||||
|
@ -19,6 +20,7 @@
|
|||
android:layout_height="match_parent"
|
||||
app:contentScrim="?riotx_background"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||
app:scrimVisibleHeightTrigger="80dp"
|
||||
app:scrimAnimationDuration="250"
|
||||
app:titleEnabled="false"
|
||||
app:toolbarId="@+id/matrixProfileToolbar">
|
||||
|
@ -40,6 +42,7 @@
|
|||
app:layout_collapseMode="pin">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/matrixProfileToolbarContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
@ -50,10 +53,10 @@
|
|||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:alpha="0"
|
||||
tools:alpha="1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:alpha="1"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
|
@ -62,9 +65,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:ellipsize="end"
|
||||
android:alpha="0"
|
||||
tools:alpha="1"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?vctr_toolbar_primary_text_color"
|
||||
android:textSize="18sp"
|
||||
|
@ -72,6 +74,7 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/matrixProfileToolbarAvatarImageView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:alpha="1"
|
||||
tools:text="@sample/matrix.json/data/roomName" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/actionTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
|
@ -44,13 +44,13 @@
|
|||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@id/actionIcon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_default="wrap"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_goneMarginStart="0dp"
|
||||
tools:text="Learn more" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/actionSubtitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
|
@ -64,7 +64,7 @@
|
|||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@id/actionIcon"
|
||||
app:layout_constraintTop_toBottomOf="@id/actionTitle"
|
||||
app:layout_constraintWidth_default="wrap"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_goneMarginStart="0dp"
|
||||
tools:text="Messages in this room are not end-to-end encrypted" />
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/matrixItemTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
|
@ -41,13 +41,13 @@
|
|||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@id/matrixItemAvatar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_default="wrap"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_goneMarginStart="0dp"
|
||||
tools:text="@sample/matrix.json/data/displayName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/matrixItemSubtitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
|
@ -61,7 +61,7 @@
|
|||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@id/matrixItemAvatar"
|
||||
app:layout_constraintTop_toBottomOf="@id/matrixItemTitle"
|
||||
app:layout_constraintWidth_default="wrap"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_goneMarginStart="0dp"
|
||||
tools:text="@sample/matrix.json/data/mxid" />
|
||||
|
||||
|
|
|
@ -1,70 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<im.vector.riotx.core.platform.StateView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/matrixProfileHeaderView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/memberProfileStateView"
|
||||
android:background="?riotx_background"
|
||||
android:padding="16dp"
|
||||
android:orientation="vertical">
|
||||
android:padding="16dp">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/memberProfileAvatarView"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="16dp"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/memberProfileNameView"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:id="@+id/memberProfileInfoContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/Vector.Toolbar.Title"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="@sample/matrix.json/data/displayName" />
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/memberProfileIdView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:singleLine="true"
|
||||
android:textStyle="bold"
|
||||
android:textAppearance="@style/Vector.Toolbar.Title"
|
||||
android:textSize="14sp"
|
||||
tools:text="@sample/matrix.json/data/mxid" />
|
||||
<ImageView
|
||||
android:id="@+id/memberProfileAvatarView"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="16dp"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/memberProfilePowerLevelView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center"
|
||||
android:textSize="12sp"
|
||||
tools:text="Admin in Matrix" />
|
||||
<TextView
|
||||
android:id="@+id/memberProfileNameView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/Vector.Toolbar.Title"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="@sample/matrix.json/data/displayName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/memberProfileStatusView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:gravity="center"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
tools:text="Here is a room topic, it can be multi-line but should always be displayed in full 🍱" />
|
||||
<TextView
|
||||
android:id="@+id/memberProfileIdView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/Vector.Toolbar.Title"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="@sample/matrix.json/data/mxid" />
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/memberProfilePowerLevelView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center"
|
||||
android:textSize="12sp"
|
||||
tools:text="Admin in Matrix" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/memberProfileStatusView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:gravity="center"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
tools:text="Here is a room topic, it can be multi-line but should always be displayed in full 🍱" />
|
||||
|
||||
</LinearLayout>
|
||||
</im.vector.riotx.core.platform.StateView>
|
|
@ -47,5 +47,7 @@
|
|||
|
||||
<string name="room_member_jump_to_read_receipt">Jump to read receipt</string>
|
||||
|
||||
<string name="unignore">Unignore</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue