Add error feedback when joining space rooms
This commit is contained in:
parent
71b456c57e
commit
e277deece5
|
@ -0,0 +1 @@
|
||||||
|
Space Explore Rooms no feedback on failed to join
|
|
@ -17,11 +17,13 @@
|
||||||
package im.vector.app.features.home.room.list
|
package im.vector.app.features.home.room.list
|
||||||
|
|
||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Loading
|
import com.airbnb.mvrx.Loading
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.date.DateFormatKind
|
import im.vector.app.core.date.DateFormatKind
|
||||||
import im.vector.app.core.date.VectorDateFormatter
|
import im.vector.app.core.date.VectorDateFormatter
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.app.core.error.ErrorFormatter
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
|
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
|
||||||
|
@ -37,7 +39,8 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
||||||
private val dateFormatter: VectorDateFormatter,
|
private val dateFormatter: VectorDateFormatter,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val typingHelper: TypingHelper,
|
private val typingHelper: TypingHelper,
|
||||||
private val avatarRenderer: AvatarRenderer) {
|
private val avatarRenderer: AvatarRenderer,
|
||||||
|
private val errorFormatter: ErrorFormatter) {
|
||||||
|
|
||||||
fun create(roomSummary: RoomSummary,
|
fun create(roomSummary: RoomSummary,
|
||||||
roomChangeMembershipStates: Map<String, ChangeMembershipState>,
|
roomChangeMembershipStates: Map<String, ChangeMembershipState>,
|
||||||
|
@ -55,12 +58,21 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
||||||
fun createSuggestion(spaceChildInfo: SpaceChildInfo,
|
fun createSuggestion(spaceChildInfo: SpaceChildInfo,
|
||||||
suggestedRoomJoiningStates: Map<String, Async<Unit>>,
|
suggestedRoomJoiningStates: Map<String, Async<Unit>>,
|
||||||
listener: RoomListListener?): VectorEpoxyModel<*> {
|
listener: RoomListListener?): VectorEpoxyModel<*> {
|
||||||
|
val error = (suggestedRoomJoiningStates[spaceChildInfo.childRoomId] as? Fail)?.error
|
||||||
return SpaceChildInfoItem_()
|
return SpaceChildInfoItem_()
|
||||||
.id("sug_${spaceChildInfo.childRoomId}")
|
.id("sug_${spaceChildInfo.childRoomId}")
|
||||||
.matrixItem(spaceChildInfo.toMatrixItem())
|
.matrixItem(spaceChildInfo.toMatrixItem())
|
||||||
.avatarRenderer(avatarRenderer)
|
.avatarRenderer(avatarRenderer)
|
||||||
.topic(spaceChildInfo.topic)
|
.topic(spaceChildInfo.topic)
|
||||||
.buttonLabel(stringProvider.getString(R.string.join))
|
.errorLabel(
|
||||||
|
error?.let {
|
||||||
|
stringProvider.getString(R.string.error_failed_to_join_room, errorFormatter.toHumanReadable(it))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.buttonLabel(
|
||||||
|
if (error != null) stringProvider.getString(R.string.global_retry)
|
||||||
|
else stringProvider.getString(R.string.join)
|
||||||
|
)
|
||||||
.loading(suggestedRoomJoiningStates[spaceChildInfo.childRoomId] is Loading)
|
.loading(suggestedRoomJoiningStates[spaceChildInfo.childRoomId] is Loading)
|
||||||
.memberCount(spaceChildInfo.activeMemberCount ?: 0)
|
.memberCount(spaceChildInfo.activeMemberCount ?: 0)
|
||||||
.buttonClickListener { listener?.onJoinSuggestedRoom(spaceChildInfo) }
|
.buttonClickListener { listener?.onJoinSuggestedRoom(spaceChildInfo) }
|
||||||
|
|
|
@ -33,6 +33,7 @@ import im.vector.app.core.epoxy.ClickListener
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.app.core.epoxy.onClick
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import me.gujun.android.span.image
|
import me.gujun.android.span.image
|
||||||
|
@ -52,6 +53,7 @@ abstract class SpaceChildInfoItem : VectorEpoxyModel<SpaceChildInfoItem.Holder>(
|
||||||
@EpoxyAttribute var loading: Boolean = false
|
@EpoxyAttribute var loading: Boolean = false
|
||||||
|
|
||||||
@EpoxyAttribute var buttonLabel: String? = null
|
@EpoxyAttribute var buttonLabel: String? = null
|
||||||
|
@EpoxyAttribute var errorLabel: String? = null
|
||||||
|
|
||||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemLongClickListener: View.OnLongClickListener? = null
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemLongClickListener: View.OnLongClickListener? = null
|
||||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemClickListener: ClickListener? = null
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemClickListener: ClickListener? = null
|
||||||
|
@ -97,6 +99,8 @@ abstract class SpaceChildInfoItem : VectorEpoxyModel<SpaceChildInfoItem.Holder>(
|
||||||
holder.joinButton.isVisible = true
|
holder.joinButton.isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
holder.errorTextView.setTextOrHide(errorLabel)
|
||||||
|
|
||||||
holder.joinButton.onClick {
|
holder.joinButton.onClick {
|
||||||
// local echo
|
// local echo
|
||||||
holder.joinButton.isEnabled = false
|
holder.joinButton.isEnabled = false
|
||||||
|
@ -120,5 +124,6 @@ abstract class SpaceChildInfoItem : VectorEpoxyModel<SpaceChildInfoItem.Holder>(
|
||||||
val descriptionText by bind<TextView>(R.id.suggestedRoomDescription)
|
val descriptionText by bind<TextView>(R.id.suggestedRoomDescription)
|
||||||
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
|
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
|
||||||
val rootView by bind<ViewGroup>(R.id.itemRoomLayout)
|
val rootView by bind<ViewGroup>(R.id.itemRoomLayout)
|
||||||
|
val errorTextView by bind<TextView>(R.id.inlineErrorText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ import im.vector.app.features.home.room.list.spaceChildInfoItem
|
||||||
import me.gujun.android.span.span
|
import me.gujun.android.span.span
|
||||||
import org.matrix.android.sdk.api.failure.Failure
|
import org.matrix.android.sdk.api.failure.Failure
|
||||||
import org.matrix.android.sdk.api.failure.MatrixError.Companion.M_UNRECOGNIZED
|
import org.matrix.android.sdk.api.failure.MatrixError.Companion.M_UNRECOGNIZED
|
||||||
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
@ -127,6 +128,7 @@ class SpaceDirectoryController @Inject constructor(
|
||||||
val isSpace = info.roomType == RoomType.SPACE
|
val isSpace = info.roomType == RoomType.SPACE
|
||||||
val isJoined = data?.joinedRoomsIds?.contains(info.childRoomId) == true
|
val isJoined = data?.joinedRoomsIds?.contains(info.childRoomId) == true
|
||||||
val isLoading = data?.changeMembershipStates?.get(info.childRoomId)?.isInProgress() ?: false
|
val isLoading = data?.changeMembershipStates?.get(info.childRoomId)?.isInProgress() ?: false
|
||||||
|
val error = (data?.changeMembershipStates?.get(info.childRoomId) as? ChangeMembershipState.FailedJoining)?.throwable
|
||||||
// if it's known use that matrixItem because it would have a better computed name
|
// if it's known use that matrixItem because it would have a better computed name
|
||||||
val matrixItem = data?.knownRoomSummaries?.find { it.roomId == info.childRoomId }?.toMatrixItem()
|
val matrixItem = data?.knownRoomSummaries?.find { it.roomId == info.childRoomId }?.toMatrixItem()
|
||||||
?: info.toMatrixItem()
|
?: info.toMatrixItem()
|
||||||
|
@ -135,11 +137,19 @@ class SpaceDirectoryController @Inject constructor(
|
||||||
matrixItem(matrixItem)
|
matrixItem(matrixItem)
|
||||||
avatarRenderer(host.avatarRenderer)
|
avatarRenderer(host.avatarRenderer)
|
||||||
topic(info.topic)
|
topic(info.topic)
|
||||||
|
errorLabel(
|
||||||
|
error?.let {
|
||||||
|
host.stringProvider.getString(R.string.error_failed_to_join_room, host.errorFormatter.toHumanReadable(it))
|
||||||
|
}
|
||||||
|
)
|
||||||
memberCount(info.activeMemberCount ?: 0)
|
memberCount(info.activeMemberCount ?: 0)
|
||||||
loading(isLoading)
|
loading(isLoading)
|
||||||
buttonLabel(
|
buttonLabel(
|
||||||
if (isJoined) host.stringProvider.getString(R.string.action_open)
|
when {
|
||||||
else host.stringProvider.getString(R.string.join)
|
error != null -> host.stringProvider.getString(R.string.global_retry)
|
||||||
|
isJoined -> host.stringProvider.getString(R.string.action_open)
|
||||||
|
else -> host.stringProvider.getString(R.string.join)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
apply {
|
apply {
|
||||||
if (isSpace) {
|
if (isSpace) {
|
||||||
|
|
|
@ -188,20 +188,21 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
||||||
|
|
||||||
private fun handleJoinOrOpen(spaceChildInfo: SpaceChildInfo) = withState { state ->
|
private fun handleJoinOrOpen(spaceChildInfo: SpaceChildInfo) = withState { state ->
|
||||||
val isSpace = spaceChildInfo.roomType == RoomType.SPACE
|
val isSpace = spaceChildInfo.roomType == RoomType.SPACE
|
||||||
if (state.joinedRoomsIds.contains(spaceChildInfo.childRoomId)) {
|
val childId = spaceChildInfo.childRoomId
|
||||||
|
if (state.joinedRoomsIds.contains(childId)) {
|
||||||
if (isSpace) {
|
if (isSpace) {
|
||||||
handle(SpaceDirectoryViewAction.ExploreSubSpace(spaceChildInfo))
|
handle(SpaceDirectoryViewAction.ExploreSubSpace(spaceChildInfo))
|
||||||
} else {
|
} else {
|
||||||
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToRoom(spaceChildInfo.childRoomId))
|
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToRoom(childId))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// join
|
// join
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
if (isSpace) {
|
if (isSpace) {
|
||||||
session.spaceService().joinSpace(spaceChildInfo.childRoomId, null, spaceChildInfo.viaServers)
|
session.spaceService().joinSpace(childId, null, spaceChildInfo.viaServers)
|
||||||
} else {
|
} else {
|
||||||
session.joinRoom(spaceChildInfo.childRoomId, null, spaceChildInfo.viaServers)
|
session.joinRoom(childId, null, spaceChildInfo.viaServers)
|
||||||
}
|
}
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
Timber.e(failure, "## Space: Failed to join room or subspace")
|
Timber.e(failure, "## Space: Failed to join room or subspace")
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:maxWidth="@dimen/button_max_width"
|
android:maxWidth="@dimen/button_max_width"
|
||||||
android:text="@string/join"
|
android:text="@string/join"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toTopOf="@id/inlineErrorText"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
@ -102,6 +102,17 @@
|
||||||
app:barrierDirection="bottom"
|
app:barrierDirection="bottom"
|
||||||
app:constraint_referenced_ids="roomAvatarBottomSpace" />
|
app:constraint_referenced_ids="roomAvatarBottomSpace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/inlineErrorText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:textColor="@color/design_default_color_error"
|
||||||
|
app:drawableStartCompat="@drawable/ic_warning_badge"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/roomBottomBarrier"
|
||||||
|
tools:text="An error occured while joining" />
|
||||||
|
|
||||||
<!-- We use vctr_list_separator_system here for a better rendering -->
|
<!-- We use vctr_list_separator_system here for a better rendering -->
|
||||||
<View
|
<View
|
||||||
android:id="@+id/roomDividerView"
|
android:id="@+id/roomDividerView"
|
||||||
|
@ -111,6 +122,6 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/roomBottomBarrier" />
|
app:layout_constraintTop_toBottomOf="@+id/inlineErrorText" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -3403,4 +3403,5 @@
|
||||||
|
|
||||||
<string name="teammate_spaces_arent_quite_ready">"Teammate spaces aren’t quite ready but you can still give them a try"</string>
|
<string name="teammate_spaces_arent_quite_ready">"Teammate spaces aren’t quite ready but you can still give them a try"</string>
|
||||||
<string name="teammate_spaces_might_not_join">"At the moment people might not be able to join any private rooms you make.\n\nWe’ll be improving this as part of the beta, but just wanted to let you know."</string>
|
<string name="teammate_spaces_might_not_join">"At the moment people might not be able to join any private rooms you make.\n\nWe’ll be improving this as part of the beta, but just wanted to let you know."</string>
|
||||||
|
<string name="error_failed_to_join_room">Sorry, an error occurred while trying to join: %s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue