mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Room member profile: branch the UI and fix some UI issues
This commit is contained in:
parent
171ec4fbdc
commit
ae1a24e948
@ -28,17 +28,20 @@ fun roomMemberQueryParams(init: (RoomMemberQueryParams.Builder.() -> Unit) = {})
|
|||||||
*/
|
*/
|
||||||
data class RoomMemberQueryParams(
|
data class RoomMemberQueryParams(
|
||||||
val displayName: QueryStringValue,
|
val displayName: QueryStringValue,
|
||||||
val memberships: List<Membership>
|
val memberships: List<Membership>,
|
||||||
|
val userId: QueryStringValue
|
||||||
) {
|
) {
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
|
|
||||||
|
var userId: QueryStringValue = QueryStringValue.NoCondition
|
||||||
var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
|
var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
|
||||||
var memberships: List<Membership> = Membership.all()
|
var memberships: List<Membership> = Membership.all()
|
||||||
|
|
||||||
fun build() = RoomMemberQueryParams(
|
fun build() = RoomMemberQueryParams(
|
||||||
displayName = displayName,
|
displayName = displayName,
|
||||||
memberships = memberships
|
memberships = memberships,
|
||||||
|
userId = userId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,7 @@ internal class DefaultMembershipService @AssistedInject constructor(@Assisted pr
|
|||||||
|
|
||||||
private fun roomMembersQuery(realm: Realm, queryParams: RoomMemberQueryParams): RealmQuery<RoomMemberSummaryEntity> {
|
private fun roomMembersQuery(realm: Realm, queryParams: RoomMemberQueryParams): RealmQuery<RoomMemberSummaryEntity> {
|
||||||
return RoomMemberHelper(realm, roomId).queryRoomMembersEvent()
|
return RoomMemberHelper(realm, roomId).queryRoomMembersEvent()
|
||||||
|
.process(RoomMemberSummaryEntityFields.USER_ID, queryParams.userId)
|
||||||
.process(RoomMemberSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
|
.process(RoomMemberSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
|
||||||
.process(RoomMemberSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
|
.process(RoomMemberSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.animations
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
|
||||||
|
class MatrixItemAppBarStateChangeListener(private val animationDuration: Long, private val views: List<View>) : AppBarStateChangeListener() {
|
||||||
|
|
||||||
|
override fun onStateChanged(appBarLayout: AppBarLayout, state: State) {
|
||||||
|
if (state == State.COLLAPSED) {
|
||||||
|
views.forEach {
|
||||||
|
it.animate().alpha(1f).duration = animationDuration + 100
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
views.forEach {
|
||||||
|
it.animate().alpha(0f).duration = animationDuration - 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,7 @@ fun EpoxyController.buildProfileAction(
|
|||||||
id: String,
|
id: String,
|
||||||
title: String,
|
title: String,
|
||||||
subtitle: String? = null,
|
subtitle: String? = null,
|
||||||
|
editable: Boolean = true,
|
||||||
@DrawableRes icon: Int = 0,
|
@DrawableRes icon: Int = 0,
|
||||||
destructive: Boolean = false,
|
destructive: Boolean = false,
|
||||||
divider: Boolean = true,
|
divider: Boolean = true,
|
||||||
@ -42,6 +43,7 @@ fun EpoxyController.buildProfileAction(
|
|||||||
iconRes(icon)
|
iconRes(icon)
|
||||||
id("action_$id")
|
id("action_$id")
|
||||||
subtitle(subtitle)
|
subtitle(subtitle)
|
||||||
|
editable(editable)
|
||||||
destructive(destructive)
|
destructive(destructive)
|
||||||
title(title)
|
title(title)
|
||||||
listener { _ ->
|
listener { _ ->
|
||||||
|
@ -23,11 +23,18 @@ import android.os.Parcelable
|
|||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.*
|
import androidx.annotation.AttrRes
|
||||||
|
import androidx.annotation.LayoutRes
|
||||||
|
import androidx.annotation.MainThread
|
||||||
|
import androidx.annotation.MenuRes
|
||||||
|
import androidx.annotation.Nullable
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentFactory
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
@ -41,7 +48,12 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import im.vector.matrix.android.api.failure.GlobalError
|
import im.vector.matrix.android.api.failure.GlobalError
|
||||||
import im.vector.riotx.BuildConfig
|
import im.vector.riotx.BuildConfig
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.di.*
|
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||||
|
import im.vector.riotx.core.di.DaggerScreenComponent
|
||||||
|
import im.vector.riotx.core.di.HasScreenInjector
|
||||||
|
import im.vector.riotx.core.di.HasVectorInjector
|
||||||
|
import im.vector.riotx.core.di.ScreenComponent
|
||||||
|
import im.vector.riotx.core.di.VectorComponent
|
||||||
import im.vector.riotx.core.dialogs.DialogLocker
|
import im.vector.riotx.core.dialogs.DialogLocker
|
||||||
import im.vector.riotx.core.extensions.observeEvent
|
import im.vector.riotx.core.extensions.observeEvent
|
||||||
import im.vector.riotx.core.utils.toast
|
import im.vector.riotx.core.utils.toast
|
||||||
@ -92,6 +104,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
lateinit var rageShake: RageShake
|
lateinit var rageShake: RageShake
|
||||||
private set
|
private set
|
||||||
protected lateinit var navigator: Navigator
|
protected lateinit var navigator: Navigator
|
||||||
|
private lateinit var fragmentFactory: FragmentFactory
|
||||||
private lateinit var activeSessionHolder: ActiveSessionHolder
|
private lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
private lateinit var vectorPreferences: VectorPreferences
|
private lateinit var vectorPreferences: VectorPreferences
|
||||||
|
|
||||||
@ -145,7 +158,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
}
|
}
|
||||||
Timber.v("Injecting dependencies into ${javaClass.simpleName} took $timeForInjection ms")
|
Timber.v("Injecting dependencies into ${javaClass.simpleName} took $timeForInjection ms")
|
||||||
ThemeUtils.setActivityTheme(this, getOtherThemes())
|
ThemeUtils.setActivityTheme(this, getOtherThemes())
|
||||||
supportFragmentManager.fragmentFactory = screenComponent.fragmentFactory()
|
fragmentFactory = screenComponent.fragmentFactory()
|
||||||
|
supportFragmentManager.fragmentFactory = fragmentFactory
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
viewModelFactory = screenComponent.viewModelFactory()
|
viewModelFactory = screenComponent.viewModelFactory()
|
||||||
configurationViewModel = viewModelProvider.get(ConfigurationViewModel::class.java)
|
configurationViewModel = viewModelProvider.get(ConfigurationViewModel::class.java)
|
||||||
@ -196,7 +210,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
handleInvalidToken(globalError)
|
handleInvalidToken(globalError)
|
||||||
is GlobalError.ConsentNotGivenError ->
|
is GlobalError.ConsentNotGivenError ->
|
||||||
consentNotGivenHelper.displayDialog(globalError.consentUri,
|
consentNotGivenHelper.displayDialog(globalError.consentUri,
|
||||||
activeSessionHolder.getActiveSession().sessionParams.homeServerConnectionConfig.homeServerUri.host ?: "")
|
activeSessionHolder.getActiveSession().sessionParams.homeServerConnectionConfig.homeServerUri.host
|
||||||
|
?: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,11 +224,11 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
mainActivityStarted = true
|
mainActivityStarted = true
|
||||||
|
|
||||||
MainActivity.restartApp(this,
|
MainActivity.restartApp(this,
|
||||||
MainActivityArgs(
|
MainActivityArgs(
|
||||||
clearCredentials = !globalError.softLogout,
|
clearCredentials = !globalError.softLogout,
|
||||||
isUserLoggedOut = true,
|
isUserLoggedOut = true,
|
||||||
isSoftLogout = globalError.softLogout
|
isSoftLogout = globalError.softLogout
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,6 +291,12 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
|
|
||||||
protected open fun injectWith(injector: ScreenComponent) = Unit
|
protected open fun injectWith(injector: ScreenComponent) = Unit
|
||||||
|
|
||||||
|
protected fun createFragment(fragmentClass: Class<out Fragment>, args: Bundle?): Fragment {
|
||||||
|
return fragmentFactory.instantiate(classLoader, fragmentClass.name).apply {
|
||||||
|
arguments = args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* PRIVATE METHODS
|
* PRIVATE METHODS
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
@ -96,6 +96,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
Timber.i("onCreateView Fragment ${this.javaClass.simpleName}")
|
||||||
return inflater.inflate(getLayoutResId(), container, false)
|
return inflater.inflate(getLayoutResId(), container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +118,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
Timber.i("onDestroyView Fragment ${this.javaClass.simpleName}")
|
||||||
mUnBinder?.unbind()
|
mUnBinder?.unbind()
|
||||||
mUnBinder = null
|
mUnBinder = null
|
||||||
uiDisposables.clear()
|
uiDisposables.clear()
|
||||||
|
@ -83,7 +83,7 @@ class DefaultNavigator @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun openRoomMemberProfile(userId: String, roomId: String?, context: Context, buildTask: Boolean) {
|
override fun openRoomMemberProfile(userId: String, roomId: String?, context: Context, buildTask: Boolean) {
|
||||||
val args = RoomMemberProfileArgs(userId = userId)
|
val args = RoomMemberProfileArgs(userId = userId, roomId = roomId)
|
||||||
context.startActivity(RoomMemberProfileActivity.newIntent(context, args))
|
context.startActivity(RoomMemberProfileActivity.newIntent(context, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,4 +19,13 @@ package im.vector.riotx.features.roommemberprofile
|
|||||||
|
|
||||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||||
|
|
||||||
sealed class RoomMemberProfileAction : VectorViewModelAction
|
sealed class RoomMemberProfileAction : VectorViewModelAction {
|
||||||
|
|
||||||
|
sealed class Displayable : RoomMemberProfileAction() {
|
||||||
|
object JumpToReadReceipt : Displayable()
|
||||||
|
object Ignore : Displayable()
|
||||||
|
object Mention : Displayable()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.epoxy.profiles.buildProfileAction
|
||||||
|
import im.vector.riotx.core.epoxy.profiles.buildProfileSection
|
||||||
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RoomMemberProfileController @Inject constructor(private val stringProvider: StringProvider)
|
||||||
|
: TypedEpoxyController<RoomMemberProfileViewState>() {
|
||||||
|
|
||||||
|
var callback: Callback? = null
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onIgnoreClicked()
|
||||||
|
fun onLearnMoreClicked()
|
||||||
|
fun onJumpToReadReceiptClicked()
|
||||||
|
fun onMentionClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildModels(data: RoomMemberProfileViewState?) {
|
||||||
|
if (data == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (data.roomId == null) {
|
||||||
|
buildUserActions()
|
||||||
|
} else {
|
||||||
|
buildRoomMemberActions(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildUserActions() {
|
||||||
|
// More
|
||||||
|
buildProfileSection(stringProvider.getString(R.string.room_profile_section_more))
|
||||||
|
buildProfileAction(
|
||||||
|
id = "ignore",
|
||||||
|
title = stringProvider.getString(R.string.ignore),
|
||||||
|
destructive = true,
|
||||||
|
editable = false,
|
||||||
|
action = { callback?.onIgnoreClicked() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildRoomMemberActions(data: RoomMemberProfileViewState) {
|
||||||
|
val roomSummaryEntity = data.roomSummary() ?: return
|
||||||
|
|
||||||
|
// Security
|
||||||
|
buildProfileSection(stringProvider.getString(R.string.room_profile_section_security))
|
||||||
|
val learnMoreSubtitle = if (roomSummaryEntity.isEncrypted) {
|
||||||
|
R.string.room_profile_encrypted_subtitle
|
||||||
|
} else {
|
||||||
|
R.string.room_profile_not_encrypted_subtitle
|
||||||
|
}
|
||||||
|
buildProfileAction(
|
||||||
|
id = "learn_more",
|
||||||
|
title = stringProvider.getString(R.string.room_profile_section_security_learn_more),
|
||||||
|
editable = false,
|
||||||
|
subtitle = stringProvider.getString(learnMoreSubtitle),
|
||||||
|
action = { callback?.onLearnMoreClicked() }
|
||||||
|
)
|
||||||
|
|
||||||
|
// More
|
||||||
|
if (!data.isMine) {
|
||||||
|
buildProfileSection(stringProvider.getString(R.string.room_profile_section_more))
|
||||||
|
buildProfileAction(
|
||||||
|
id = "read_receipt",
|
||||||
|
editable = false,
|
||||||
|
title = stringProvider.getString(R.string.room_member_jump_to_read_receipt),
|
||||||
|
action = { callback?.onJumpToReadReceiptClicked() }
|
||||||
|
)
|
||||||
|
buildProfileAction(
|
||||||
|
id = "mention",
|
||||||
|
title = stringProvider.getString(R.string.room_participants_action_mention),
|
||||||
|
editable = false,
|
||||||
|
action = { callback?.onMentionClicked() }
|
||||||
|
)
|
||||||
|
buildProfileAction(
|
||||||
|
id = "ignore",
|
||||||
|
title = stringProvider.getString(R.string.ignore),
|
||||||
|
destructive = true,
|
||||||
|
editable = false,
|
||||||
|
action = { callback?.onIgnoreClicked() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -19,14 +19,25 @@ package im.vector.riotx.features.roommemberprofile
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import kotlinx.android.parcel.Parcelize
|
|
||||||
import com.airbnb.mvrx.args
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import com.airbnb.mvrx.args
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
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 im.vector.riotx.R
|
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.VectorBaseFragment
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
import timber.log.Timber
|
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
|
import javax.inject.Inject
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@ -36,21 +47,87 @@ data class RoomMemberProfileArgs(
|
|||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
class RoomMemberProfileFragment @Inject constructor(
|
class RoomMemberProfileFragment @Inject constructor(
|
||||||
val viewModelFactory: RoomMemberProfileViewModel.Factory
|
val viewModelFactory: RoomMemberProfileViewModel.Factory,
|
||||||
) : VectorBaseFragment() {
|
private val roomMemberProfileController: RoomMemberProfileController,
|
||||||
|
private val avatarRenderer: AvatarRenderer
|
||||||
|
) : VectorBaseFragment(), RoomMemberProfileController.Callback {
|
||||||
|
|
||||||
private val fragmentArgs: RoomMemberProfileArgs by args()
|
private val fragmentArgs: RoomMemberProfileArgs by args()
|
||||||
private val viewModel: RoomMemberProfileViewModel by fragmentViewModel()
|
private val viewModel: RoomMemberProfileViewModel by fragmentViewModel()
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_room_member_profile
|
private lateinit var appBarStateChangeListener: AppBarStateChangeListener
|
||||||
|
|
||||||
|
override fun getLayoutResId() = R.layout.fragment_matrix_profile
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
// Initialize your view, subscribe to viewModel...
|
setupToolbar(matrixProfileToolbar)
|
||||||
|
matrixProfileHeaderView.apply {
|
||||||
|
layoutResource = R.layout.view_stub_room_member_profile_header
|
||||||
|
inflate()
|
||||||
|
}
|
||||||
|
matrixProfileRecyclerView.configureWith(roomMemberProfileController, hasFixedSize = true)
|
||||||
|
roomMemberProfileController.callback = this
|
||||||
|
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(matrixProfileCollapsingToolbarLayout.scrimAnimationDuration, listOf(matrixProfileToolbarAvatarImageView, matrixProfileToolbarTitleView))
|
||||||
|
matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
|
roomMemberProfileController.callback = null
|
||||||
|
matrixProfileRecyclerView.cleanup()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
Timber.v("Invalidate: $state")
|
val memberMatrixItem = state.memberAsMatrixItem() ?: return@withState
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
memberProfilePowerLevelView.setTextOrHide(powerLevelText)
|
||||||
|
}
|
||||||
|
roomMemberProfileController.setData(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RoomMemberProfileController.Callback
|
||||||
|
|
||||||
|
override fun onIgnoreClicked() {
|
||||||
|
vectorBaseActivity.notImplemented("Ignore")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLearnMoreClicked() {
|
||||||
|
vectorBaseActivity.notImplemented("Learn more")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onJumpToReadReceiptClicked() {
|
||||||
|
vectorBaseActivity.notImplemented("Jump to read receipts")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMentionClicked() {
|
||||||
|
vectorBaseActivity.notImplemented("Mention")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,20 @@ import com.airbnb.mvrx.MvRxViewModelFactory
|
|||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import com.squareup.inject.assisted.Assisted
|
import com.squareup.inject.assisted.Assisted
|
||||||
import com.squareup.inject.assisted.AssistedInject
|
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.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.PowerLevelsContent
|
||||||
|
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.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted initialState: RoomMemberProfileViewState,
|
class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private val initialState: RoomMemberProfileViewState,
|
||||||
private val session: Session)
|
private val session: Session)
|
||||||
: VectorViewModel<RoomMemberProfileViewState, RoomMemberProfileAction>(initialState) {
|
: VectorViewModel<RoomMemberProfileViewState, RoomMemberProfileAction>(initialState) {
|
||||||
|
|
||||||
@ -44,8 +53,73 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted initialSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val room = if (initialState.roomId != null) {
|
||||||
|
session.getRoom(initialState.roomId)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
setState { copy(isMine = session.myUserId == this.userId) }
|
||||||
|
observeRoomSummary()
|
||||||
|
observeRoomMemberSummary()
|
||||||
|
observePowerLevel()
|
||||||
|
observeUserIfRequired()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeUserIfRequired() {
|
||||||
|
if (initialState.roomId != null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
session.rx().liveUser(initialState.userId)
|
||||||
|
.unwrap()
|
||||||
|
.execute {
|
||||||
|
copy(user = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun handle(action: RoomMemberProfileAction) {
|
override fun handle(action: RoomMemberProfileAction) {
|
||||||
Timber.v("Handle $action")
|
Timber.v("Handle $action")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeRoomSummary() {
|
||||||
|
if (room == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
room.rx().liveRoomSummary()
|
||||||
|
.unwrap()
|
||||||
|
.execute {
|
||||||
|
copy(roomSummary = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeRoomMemberSummary() {
|
||||||
|
if (room == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val queryParams = roomMemberQueryParams {
|
||||||
|
this.userId = QueryStringValue.Equals(initialState.userId, QueryStringValue.Case.SENSITIVE)
|
||||||
|
}
|
||||||
|
room.rx().liveRoomMembers(queryParams)
|
||||||
|
.map { it.firstOrNull().toOptional() }
|
||||||
|
.unwrap()
|
||||||
|
.execute {
|
||||||
|
copy(roomMemberSummary = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observePowerLevel() {
|
||||||
|
if (room == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
room.rx()
|
||||||
|
.liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||||
|
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||||
|
.unwrap()
|
||||||
|
.execute {
|
||||||
|
copy(powerLevelsContent = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,35 @@
|
|||||||
|
|
||||||
package im.vector.riotx.features.roommemberprofile
|
package im.vector.riotx.features.roommemberprofile
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
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.session.user.model.User
|
||||||
|
import im.vector.matrix.android.api.util.MatrixItem
|
||||||
|
import im.vector.matrix.android.api.util.toMatrixItem
|
||||||
|
|
||||||
data class RoomMemberProfileViewState(
|
data class RoomMemberProfileViewState(
|
||||||
val userId: String,
|
val userId: String,
|
||||||
val roomId: String?
|
val roomId: String?,
|
||||||
|
val isMine: Boolean = false,
|
||||||
|
val roomSummary: Async<RoomSummary?> = Uninitialized,
|
||||||
|
val roomMemberSummary: Async<RoomMemberSummary> = Uninitialized,
|
||||||
|
val user: Async<User> = Uninitialized,
|
||||||
|
val powerLevelsContent: Async<PowerLevelsContent> = Uninitialized
|
||||||
) : MvRxState {
|
) : MvRxState {
|
||||||
|
|
||||||
constructor(args: RoomMemberProfileArgs) : this(roomId = args.roomId, userId = args.userId)
|
constructor(args: RoomMemberProfileArgs) : this(roomId = args.roomId, userId = args.userId)
|
||||||
|
|
||||||
|
|
||||||
|
fun memberAsMatrixItem(): MatrixItem? {
|
||||||
|
return if (roomId == null) {
|
||||||
|
user.invoke()?.toMatrixItem()
|
||||||
|
} else {
|
||||||
|
roomMemberSummary.invoke()?.toMatrixItem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.extensions.addFragment
|
import im.vector.riotx.core.extensions.commitTransaction
|
||||||
import im.vector.riotx.core.extensions.addFragmentToBackstack
|
import im.vector.riotx.core.extensions.commitTransactionNow
|
||||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||||
import im.vector.riotx.features.roomprofile.members.RoomMemberListFragment
|
import im.vector.riotx.features.roomprofile.members.RoomMemberListFragment
|
||||||
@ -32,6 +32,9 @@ class RoomProfileActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val EXTRA_ROOM_PROFILE_ARGS = "EXTRA_ROOM_PROFILE_ARGS"
|
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 {
|
fun newIntent(context: Context, roomId: String): Intent {
|
||||||
val roomProfileArgs = RoomProfileArgs(roomId)
|
val roomProfileArgs = RoomProfileArgs(roomId)
|
||||||
@ -50,7 +53,14 @@ class RoomProfileActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
sharedActionViewModel = viewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
||||||
roomProfileArgs = intent?.extras?.getParcelable(EXTRA_ROOM_PROFILE_ARGS) ?: return
|
roomProfileArgs = intent?.extras?.getParcelable(EXTRA_ROOM_PROFILE_ARGS) ?: return
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
addFragment(R.id.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sharedActionViewModel
|
sharedActionViewModel
|
||||||
.observe()
|
.observe()
|
||||||
@ -73,7 +83,15 @@ class RoomProfileActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun openRoomMembers() {
|
private fun openRoomMembers() {
|
||||||
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun configure(toolbar: Toolbar) {
|
override fun configure(toolbar: Toolbar) {
|
||||||
|
@ -97,6 +97,7 @@ class RoomProfileController @Inject constructor(private val stringProvider: Stri
|
|||||||
title = stringProvider.getString(R.string.room_profile_section_more_leave),
|
title = stringProvider.getString(R.string.room_profile_section_more_leave),
|
||||||
divider = false,
|
divider = false,
|
||||||
destructive = true,
|
destructive = true,
|
||||||
|
editable = false,
|
||||||
action = { callback?.onLeaveRoomClicked() }
|
action = { callback?.onLeaveRoomClicked() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -24,16 +24,16 @@ import android.os.Bundle
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.airbnb.mvrx.args
|
import com.airbnb.mvrx.args
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
|
||||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||||
import im.vector.matrix.android.api.util.toMatrixItem
|
import im.vector.matrix.android.api.util.toMatrixItem
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.animations.AppBarStateChangeListener
|
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.extensions.setTextOrHide
|
||||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
@ -42,7 +42,8 @@ import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBotto
|
|||||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedAction
|
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedAction
|
||||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.fragment_room_profile.*
|
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
||||||
|
import kotlinx.android.synthetic.main.view_stub_room_profile_header.*
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -63,26 +64,22 @@ class RoomProfileFragment @Inject constructor(
|
|||||||
private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
|
private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
|
||||||
private val roomProfileViewModel: RoomProfileViewModel by fragmentViewModel()
|
private val roomProfileViewModel: RoomProfileViewModel by fragmentViewModel()
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_room_profile
|
private lateinit var appBarStateChangeListener: AppBarStateChangeListener
|
||||||
|
|
||||||
|
|
||||||
|
override fun getLayoutResId() = R.layout.fragment_matrix_profile
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
roomListQuickActionsSharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
roomListQuickActionsSharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
||||||
roomProfileSharedActionViewModel = activityViewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
roomProfileSharedActionViewModel = activityViewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
||||||
setupToolbar(roomProfileToolbar)
|
matrixProfileHeaderView.apply {
|
||||||
|
layoutResource = R.layout.view_stub_room_profile_header
|
||||||
|
inflate()
|
||||||
|
}
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
roomProfileAppBarLayout.addOnOffsetChangedListener(object : AppBarStateChangeListener() {
|
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(matrixProfileCollapsingToolbarLayout.scrimAnimationDuration, listOf(matrixProfileToolbarAvatarImageView, matrixProfileToolbarTitleView))
|
||||||
override fun onStateChanged(appBarLayout: AppBarLayout, state: State) {
|
matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
val animationDuration = roomProfileCollapsingToolbarLayout.scrimAnimationDuration
|
|
||||||
if (state == State.COLLAPSED) {
|
|
||||||
roomProfileToolbarAvatarImageView.animate().alpha(1f).duration = animationDuration + 100
|
|
||||||
roomProfileToolbarTitleView.animate().alpha(1f).duration = animationDuration + 100
|
|
||||||
} else {
|
|
||||||
roomProfileToolbarAvatarImageView.animate().alpha(0f).duration = animationDuration - 100
|
|
||||||
roomProfileToolbarTitleView.animate().alpha(0f).duration = animationDuration - 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
roomProfileViewModel.viewEvents
|
roomProfileViewModel.viewEvents
|
||||||
.observe()
|
.observe()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
@ -101,6 +98,11 @@ class RoomProfileFragment @Inject constructor(
|
|||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
setupToolbar(matrixProfileToolbar)
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleQuickActions(action: RoomListQuickActionsSharedAction) = when (action) {
|
private fun handleQuickActions(action: RoomListQuickActionsSharedAction) = when (action) {
|
||||||
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
||||||
roomProfileViewModel.handle(RoomProfileAction.ChangeRoomNotificationState(RoomNotificationState.ALL_MESSAGES_NOISY))
|
roomProfileViewModel.handle(RoomProfileAction.ChangeRoomNotificationState(RoomNotificationState.ALL_MESSAGES_NOISY))
|
||||||
@ -135,14 +137,13 @@ class RoomProfileFragment @Inject constructor(
|
|||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
roomProfileController.callback = this
|
roomProfileController.callback = this
|
||||||
roomProfileRecyclerView.setHasFixedSize(true)
|
matrixProfileRecyclerView.configureWith(roomProfileController, hasFixedSize = true)
|
||||||
roomProfileRecyclerView.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
|
|
||||||
roomProfileRecyclerView.adapter = roomProfileController.adapter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
roomProfileRecyclerView.adapter = null
|
matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
|
matrixProfileRecyclerView.cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(roomProfileViewModel) { state ->
|
override fun invalidate() = withState(roomProfileViewModel) { state ->
|
||||||
@ -152,12 +153,12 @@ class RoomProfileFragment @Inject constructor(
|
|||||||
activity?.finish()
|
activity?.finish()
|
||||||
} else {
|
} else {
|
||||||
roomProfileNameView.text = it.displayName
|
roomProfileNameView.text = it.displayName
|
||||||
roomProfileToolbarTitleView.text = it.displayName
|
matrixProfileToolbarTitleView.text = it.displayName
|
||||||
roomProfileAliasView.setTextOrHide(it.canonicalAlias)
|
roomProfileAliasView.setTextOrHide(it.canonicalAlias)
|
||||||
roomProfileTopicView.setTextOrHide(it.topic)
|
roomProfileTopicView.setTextOrHide(it.topic)
|
||||||
val matrixItem = it.toMatrixItem()
|
val matrixItem = it.toMatrixItem()
|
||||||
avatarRenderer.render(matrixItem, roomProfileAvatarView)
|
avatarRenderer.render(matrixItem, roomProfileAvatarView)
|
||||||
avatarRenderer.render(matrixItem, roomProfileToolbarAvatarImageView)
|
avatarRenderer.render(matrixItem, matrixProfileToolbarAvatarImageView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
roomProfileController.setData(state)
|
roomProfileController.setData(state)
|
||||||
|
@ -19,6 +19,7 @@ package im.vector.riotx.features.roomprofile.members
|
|||||||
import com.airbnb.epoxy.TypedEpoxyController
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
|
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
|
||||||
import im.vector.matrix.android.api.util.toMatrixItem
|
import im.vector.matrix.android.api.util.toMatrixItem
|
||||||
|
import im.vector.riotx.core.epoxy.dividerItem
|
||||||
import im.vector.riotx.core.epoxy.profiles.buildProfileSection
|
import im.vector.riotx.core.epoxy.profiles.buildProfileSection
|
||||||
import im.vector.riotx.core.epoxy.profiles.profileMatrixItem
|
import im.vector.riotx.core.epoxy.profiles.profileMatrixItem
|
||||||
import im.vector.riotx.core.resources.StringProvider
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
@ -56,6 +57,10 @@ class RoomMemberListController @Inject constructor(private val avatarRenderer: A
|
|||||||
callback?.onRoomMemberClicked(roomMember)
|
callback?.onRoomMemberClicked(roomMember)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dividerItem {
|
||||||
|
id("divider_${roomMember.userId}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import im.vector.riotx.core.platform.VectorBaseFragment
|
|||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
import im.vector.riotx.features.roomprofile.RoomProfileArgs
|
import im.vector.riotx.features.roomprofile.RoomProfileArgs
|
||||||
import kotlinx.android.synthetic.main.fragment_room_member_list.*
|
import kotlinx.android.synthetic.main.fragment_room_member_list.*
|
||||||
import kotlinx.android.synthetic.main.fragment_room_member_list.recyclerView
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
@ -48,11 +47,15 @@ class RoomMemberListFragment @Inject constructor(
|
|||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setupToolbar(roomMemberListToolbar)
|
|
||||||
roomMemberListController.callback = this
|
roomMemberListController.callback = this
|
||||||
recyclerView.configureWith(roomMemberListController, hasFixedSize = true)
|
recyclerView.configureWith(roomMemberListController, hasFixedSize = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
setupToolbar(roomMemberListToolbar)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
recyclerView.cleanup()
|
recyclerView.cleanup()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -7,82 +7,33 @@
|
|||||||
android:background="?riotx_header_panel_background">
|
android:background="?riotx_header_panel_background">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/roomProfileAppBarLayout"
|
android:id="@+id/matrixProfileAppBarLayout"
|
||||||
style="@style/VectorAppBarLayoutStyle"
|
style="@style/VectorAppBarLayoutStyle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||||
android:id="@+id/roomProfileCollapsingToolbarLayout"
|
android:id="@+id/matrixProfileCollapsingToolbarLayout"
|
||||||
style="@style/VectorAppBarLayoutStyle"
|
style="@style/VectorAppBarLayoutStyle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
app:contentScrim="?riotx_background"
|
|
||||||
app:scrimAnimationDuration="250"
|
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
app:contentScrim="?riotx_background"
|
||||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||||
|
app:scrimAnimationDuration="250"
|
||||||
app:titleEnabled="false"
|
app:titleEnabled="false"
|
||||||
app:toolbarId="@+id/roomProfileToolbar">
|
app:toolbarId="@+id/matrixProfileToolbar">
|
||||||
|
|
||||||
<LinearLayout
|
<ViewStub
|
||||||
android:id="@+id/roomProfileHeaderView"
|
android:id="@+id/matrixProfileHeaderView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?riotx_background"
|
android:background="?riotx_background"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_collapseMode="parallax"
|
app:layout_collapseMode="parallax"
|
||||||
app:layout_collapseParallaxMultiplier="0.9">
|
app:layout_collapseParallaxMultiplier="0.9" />
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/roomProfileAvatarView"
|
|
||||||
android:layout_width="128dp"
|
|
||||||
android:layout_height="128dp"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
tools:src="@tools:sample/avatars" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/roomProfileNameView"
|
|
||||||
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="Random" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/roomProfileAliasView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:textAppearance="@style/Vector.Toolbar.Title"
|
|
||||||
android:textSize="16sp"
|
|
||||||
tools:text="#random:matrix.org" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/roomProfileTopicView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_marginStart="40dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:layout_marginEnd="40dp"
|
|
||||||
android:fontFamily="sans-serif"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:textStyle="normal"
|
|
||||||
tools:text="Here is a room topic, it can be multi-line but should always be displayed in full 🍱" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/roomProfileToolbar"
|
android:id="@+id/matrixProfileToolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
@ -93,29 +44,33 @@
|
|||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/roomProfileToolbarAvatarImageView"
|
android:id="@+id/matrixProfileToolbarAvatarImageView"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
|
android:alpha="0"
|
||||||
|
tools:alpha="1"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/roomProfileToolbarTitleView"
|
android:id="@+id/matrixProfileToolbarTitleView"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
|
android:alpha="0"
|
||||||
|
tools:alpha="1"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="?vctr_toolbar_primary_text_color"
|
android:textColor="?vctr_toolbar_primary_text_color"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
app:layout_constraintStart_toEndOf="@+id/roomProfileToolbarAvatarImageView"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/matrixProfileToolbarAvatarImageView"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@sample/matrix.json/data/roomName" />
|
tools:text="@sample/matrix.json/data/roomName" />
|
||||||
|
|
||||||
@ -130,7 +85,7 @@
|
|||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/roomProfileRecyclerView"
|
android:id="@+id/matrixProfileRecyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
@ -9,6 +9,7 @@
|
|||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/roomMemberListToolbar"
|
android:id="@+id/roomMemberListToolbar"
|
||||||
style="@style/VectorToolbarStyle"
|
style="@style/VectorToolbarStyle"
|
||||||
|
android:elevation="4dp"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="?actionBarSize"
|
android:layout_height="?actionBarSize"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ 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.
|
|
||||||
~
|
|
||||||
-->
|
|
||||||
|
|
||||||
<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:id="@+id/rootConstraintLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/message"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="RoomMemberProfileFragment"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout 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:background="?riotx_background"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<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"
|
||||||
|
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/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" />
|
||||||
|
|
||||||
|
<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>
|
57
vector/src/main/res/layout/view_stub_room_profile_header.xml
Normal file
57
vector/src/main/res/layout/view_stub_room_profile_header.xml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?riotx_background"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/roomProfileAvatarView"
|
||||||
|
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/roomProfileNameView"
|
||||||
|
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="Random" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/roomProfileAliasView"
|
||||||
|
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="#random:matrix.org" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/roomProfileTopicView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginStart="40dp"
|
||||||
|
android:layout_marginEnd="40dp"
|
||||||
|
android:fontFamily="sans-serif"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
tools:text="Here is a room topic, it can be multi-line but should always be displayed in full 🍱" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -41,4 +41,11 @@
|
|||||||
<string name="room_member_power_level_invites">Invites</string>
|
<string name="room_member_power_level_invites">Invites</string>
|
||||||
<string name="room_member_power_level_users">Users</string>
|
<string name="room_member_power_level_users">Users</string>
|
||||||
|
|
||||||
|
<string name="room_member_power_level_admin_in">Admin in %1$s</string>
|
||||||
|
<string name="room_member_power_level_moderator_in">Moderator in %1$s</string>
|
||||||
|
<string name="room_member_power_level_custom_in">Custom (%1$d) in %2$s</string>
|
||||||
|
|
||||||
|
<string name="room_member_jump_to_read_receipt">Jump to read receipt</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user